[Pkg-scicomp-commits] [SCM] MAdLib, a mesh adaptation library. branch, master, updated. debian/1.2.2-1-10-ga07b5fe

Christophe Prud'homme prudhomm at debian.org
Sun Oct 11 13:45:27 UTC 2009


The following commit has been merged in the master branch:
commit 7c8a3d4a195c7663c1c0247d37fdb7033fa40d4b
Author: Christophe Prud'homme <prudhomm at debian.org>
Date:   Sun Oct 11 12:14:30 2009 +0200

    Imported Upstream version 1.2.3

diff --git a/Adapt/AdaptInterface.cc b/Adapt/AdaptInterface.cc
new file mode 100644
index 0000000..0bf46d5
--- /dev/null
+++ b/Adapt/AdaptInterface.cc
@@ -0,0 +1,1512 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "AdaptInterface.h"
+#include "MAdResourceManager.h"
+#include "MAdTimeManager.h"
+#include "NodalDataManager.h"
+#include "MAdStatistics.h"
+#include "ModelConstraintManager.h"
+#include "MAdMessage.h"
+#include "History.h"
+
+// standard C/C++
+#include <iostream>
+#include <stdlib.h>
+#include <fstream>
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "MeshDataBaseParallelInterface.h"
+#endif
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::set;
+using std::vector;
+using std::multiset;
+using std::string;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  void MeshAdapterAbortFct(void * data) {
+    ((MeshAdapter *) data) -> abort();
+  }
+
+  // -------------------------------------------------------------------
+  MeshAdapter::MeshAdapter(pMesh m, pSField sf): 
+    mesh(m),
+    eSplitOp(0), eCollapseOp(0), fCollapseOp(0), descOp(0), 
+    eSwapOp(0), fSwapOp(0), vMoveOp(0), rRegionOp(0), sliverFOp(0), 
+    sliverROp(0), geoTracker(0), 
+    mpm(MeshParametersManagerSgl::instance()), 
+    verbosity(2), updateSFFrequency(0), outPrefix(""), debugLevel(0)
+  {
+    SFManager = new SizeFieldManager(mesh,sf);
+
+    MAdMsgSgl            ::instance().registerAbortFct(MeshAdapterAbortFct,this);
+    MAdTimeManagerSgl    ::instance().initialize();
+    MAdStatisticsSgl     ::instance().initialize();
+    CallBackManagerSgl   ::instance().initialize();
+    NodalDataManagerSgl  ::instance().initialize(mesh);
+    MeshQualityManagerSgl::instance().initialize(mesh,SFManager->getSizeField(),MEANRATIO);
+    HistorySgl           ::instance().initialize();
+    HistorySgl           ::instance().closeJournal();
+    ModelConstraintManagerSgl::instance().initialize(M_model(mesh));
+    MeshParametersManagerSgl::instance().initialize();
+
+    if (mesh) buildOperators();
+
+    setDefaultValues();
+
+    if ( debugLevel >= 1 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+  }
+
+  // -------------------------------------------------------------------
+  MeshAdapter::~MeshAdapter()
+  {
+    removeOperators();
+    if (geoTracker) delete geoTracker;
+    if (SFManager) delete SFManager;
+
+    MAdTimeManagerSgl    ::instance().finalize();
+    MAdStatisticsSgl     ::instance().finalize();
+    CallBackManagerSgl   ::instance().finalize();
+    NodalDataManagerSgl  ::instance().finalize();
+    MeshQualityManagerSgl::instance().finalize();
+    HistorySgl           ::instance().finalize();
+    ModelConstraintManagerSgl::instance().finalize();
+    MeshParametersManagerSgl::instance().finalize();
+  }
+
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setDefaultValues()
+  {
+    algorithm = CPS_SWP_SLV_SPT;
+    maxIterationsNumber = 10;
+
+    setEdgeLenSqBounds             ( 1./3. , 3. );
+
+    if ( M_dim(mesh) == 2 ) {
+      setNoSwapQuality             ( 0.2 );
+    }
+    else { //  to be checked
+      setNoSwapQuality             ( 0.1 );
+    }
+    mpm.setSwapMinImproveRatio     ( 1.0 );
+
+    mpm.setSliverTriBound          ( 0.01 );
+    mpm.setSliverTetBound          ( 0.02 );
+
+    // infinite loops control
+    setSliverPermissionInESplit    ( true, 10. );
+    setSliverPermissionInECollapse ( true, 0.1 );
+
+    setCollapseOnBoundary          ( true, 1.e-6 );
+    setSwapOnBoundary              ( true, 1.e-6 );
+
+#ifdef PARALLEL
+    load_balance_algorithm = DEFAULT_ALGORITHM;
+    dataExchanger = NULL;
+#endif
+
+    updateSFFrequency = 0;
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::printParameters() const
+  {
+    mpm.diagnostics();
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setEdgeLenSqBounds(double lower, double upper)
+  {
+    if ( sqrt(lower) > 0.5*sqrt(upper) ) {
+      cout << "Warning: edge length interval is too small ("
+           << sqrt(lower) << ", " << sqrt(upper) <<")\n";
+    }
+
+    mpm.setLowerLengthSqBound(lower);
+    mpm.setUpperLengthSqBound(upper);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setCollapseOnBoundary(bool accept, double tolerance) 
+  {
+    eCollapseOp->collapseOnBoundary(accept,tolerance);
+    fCollapseOp->collapseOnBoundary(accept,tolerance);
+    sliverROp  ->collapseOnBoundary(accept,tolerance);
+    sliverFOp  ->collapseOnBoundary(accept,tolerance);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setSwapOnBoundary(bool accept, double tolerance) 
+  {
+    eSwapOp  ->swapOnBoundary(accept,tolerance);
+    sliverROp->swapOnBoundary(accept,tolerance);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setMaxIterationsNumber(int max)
+  {
+    maxIterationsNumber = max;
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setNoSwapQuality(double noSwapQuality)
+  {
+    mpm.setNoSwapQuality(noSwapQuality);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setSwapMinImproveRatio(double ratio)
+  {
+    mpm.setSwapMinImproveRatio(ratio);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setSliverQuality(double sliverQuality)
+  {
+    mpm.setSliverTriBound(sliverQuality);
+    mpm.setSliverTetBound(sliverQuality);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setSliverPermissionInESplit(bool perm, double bound)
+  {
+    mpm.setSliverPermissionInESplit(perm, bound);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setSliverPermissionInECollapse(bool perm, double bound)
+  {
+    mpm.setSliverPermissionInECollapse(perm, bound);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setGeoTracking(bool track, bool cavityEqualMesh, 
+                                   int cavityThickness, double chi)
+  {
+    if ( track && !geoTracker) {
+      geoTracker = new geoMatcher(mesh);
+      geoTracker->setCavityEqualMesh(cavityEqualMesh,cavityThickness);
+      geoTracker->setStiffnessAlterationCoef(chi);
+    }
+    else if ( !track && geoTracker) { 
+      delete geoTracker;
+      geoTracker = NULL;
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setInfiniteLength(double length)
+  {
+    mpm.setBigLength(length);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setSFUpdateFrequency(int freq)
+  {
+    updateSFFrequency = freq;
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setVerbosity(int _verbosity)
+  {
+    verbosity = _verbosity;
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::clearConstraints() const
+  {
+    DeleteConstraint(mesh);
+    ModelConstraintManagerSgl::instance().clear();
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setConstraint(pEntity e) const
+  {
+    EN_constrain(e);
+  
+    switch (EN_type(e)) {
+    case 1:
+      EN_constrain( (pEntity)E_vertex((pEdge)e,0) );
+      EN_constrain( (pEntity)E_vertex((pEdge)e,1) );
+      break;
+    case 2:
+      setConstraint( (pEntity)F_edge((pFace)e,0) );
+      setConstraint( (pEntity)F_edge((pFace)e,1) );
+      setConstraint( (pEntity)F_edge((pFace)e,2) );
+      break;
+    case 3:
+      setConstraint( (pEntity)R_face((pRegion)e,0) );
+      setConstraint( (pEntity)R_face((pRegion)e,1) );
+      setConstraint( (pEntity)R_face((pRegion)e,2) );
+      setConstraint( (pEntity)R_face((pRegion)e,3) );
+      break;    
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setConstraint(int type, int id) const
+  {
+    ModelConstraintManagerSgl::instance().constrain(type,id);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::removeConstraint(int type, int id) const
+  {
+    ModelConstraintManagerSgl::instance().unconstrain(type,id);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setConstraint(pGEntity e) const
+  {
+    ModelConstraintManagerSgl::instance().constrain(e);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::removeConstraint(pGEntity e) const
+  {
+    ModelConstraintManagerSgl::instance().unconstrain(e);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::removeOperators()
+  {
+    if (eSplitOp)    { delete eSplitOp;     eSplitOp=0;    }
+    if (eCollapseOp) { delete eCollapseOp;  eCollapseOp=0; }
+    if (fCollapseOp) { delete fCollapseOp;  fCollapseOp=0; }
+    if (descOp)      { delete descOp;       descOp=0;      }
+    if (eSwapOp)     { delete eSwapOp;      eSwapOp=0;     }
+    if (fSwapOp)     { delete fSwapOp;      fSwapOp=0;     }
+    if (vMoveOp)     { delete vMoveOp;      vMoveOp=0;     }
+    if (rRegionOp)   { delete rRegionOp;    rRegionOp=0;   }
+    if (sliverFOp)   { delete sliverFOp;    sliverFOp=0;   }
+    if (sliverROp)   { delete sliverROp;    sliverROp=0;   }
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::buildOperators()
+  {
+    removeOperators();
+
+    eSplitOp    = new edgeSplitOp         (mesh,SFManager->getSizeField());
+    eCollapseOp = new edgeCollapseOp      (mesh,SFManager->getSizeField());
+    fCollapseOp = new faceCollapseOp      (mesh,SFManager->getSizeField());
+    descOp      = new DESCOp              (mesh,SFManager->getSizeField());
+    eSwapOp     = new edgeSwapOp          (mesh,SFManager->getSizeField());
+    fSwapOp     = new faceSwapOp          (mesh,SFManager->getSizeField());
+    vMoveOp     = new vertexMoveOp        (mesh,SFManager->getSizeField(),false);
+    rRegionOp   = new regionRemoveOp      (mesh,SFManager->getSizeField());
+    sliverROp   = new sliverRegionHandler (mesh,SFManager->getSizeField());
+    sliverFOp   = new sliverFaceHandler   (mesh,SFManager->getSizeField());
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::addCallback(CBFunction CB, void* userData, 
+                                CBFunc_move CB_move, void* userData_move)
+  { 
+    CallBackManagerSgl::instance().registerCallBack(CB,userData);
+    if (CB_move) {
+      CallBackManagerSgl::instance().registerCallBackMove(CB_move,userData_move);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::addSizeField(pSField sf)
+  {
+    SFManager->addSizeField(sf);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setSizeFieldSmoothing(bool enable, double maxGrad)
+  {
+    SFManager->setSmoothing(enable,maxGrad);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::incrementTime(double dt) 
+  {
+    MAdTimeManagerSgl::instance().incrementTime(dt);
+    updateSizeField();
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setTime(double t) 
+  {
+    MAdTimeManagerSgl::instance().setTime(t);
+    updateSizeField();
+  }
+
+  // -------------------------------------------------------------------
+  double MeshAdapter::getTime() const {
+    return MAdTimeManagerSgl::instance().getTime();
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::updateSizeField()
+  {
+    SFManager->update();
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::storeInitialCoordinates()
+  {
+    if ( getTime() != 0. ) {
+      cout << "Warning: storing coordinates at time " << getTime() << endl;
+    }
+    NodalDataManagerSgl::instance().storeCoordinates();
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::removeStoredCoordinates()
+  {
+    NodalDataManagerSgl::instance().removeCoordinates();
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::registerObjects(mobileObjectSet* objs)
+  {
+    set<mobileObject*> allObj = objs->getObjects();
+  
+    set<mobileObject*>::const_iterator it = allObj.begin();
+    for (; it != allObj.end(); it++) {
+      set<LocalSizeField* > sizes = (*it)->getSizes();
+      set<LocalSizeField* >::iterator it = sizes.begin();
+      for (; it != sizes.end(); it++) {
+        SFManager->addSizeField(*it);
+      }
+    }
+
+    objects = objs;
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::registerData  (string name, 
+                                   const vector<double> data) const
+  {
+    NodalDataManagerSgl::instance().registerData(name,data);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::registerVData (string name, 
+                                   const vector<vector<double> > data) const
+  {
+    NodalDataManagerSgl::instance().registerVData(name,data);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::getMeshData   (string name, 
+                                   vector<double> * data) const
+  {
+    NodalDataManagerSgl::instance().getMeshData(name,data);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::getMeshVData  (string name, 
+                                   vector<vector<double> > * data) const
+  {
+    NodalDataManagerSgl::instance().getMeshVData(name,data);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::removeData    (string name) const
+  {
+    NodalDataManagerSgl::instance().removeData(name);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::removeVData   (string name) const
+  {
+    NodalDataManagerSgl::instance().removeVData(name);
+  }
+
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  // LEVEL 1 OPERATIONS
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  bool MeshAdapter::splitEdge(pEdge edge, bool checkSize)
+  {
+    // set edge to split
+    double reducSq = eSplitOp->setSplitEdge(edge);
+
+    // check that the edge is not splitted in short edges
+    if ( checkSize )
+      {
+        double lenSq = SFManager->getSizeField()->SF_E_lengthSq(edge);
+        if ( ( reducSq * lenSq ) <= mpm.getLowerLengthSqBound() ) return false;
+      }
+
+    // do the checks
+    double worstShape;
+    if ( !eSplitOp->evaluate(&worstShape) ) return false;
+
+    // check that we do not create a worse sliver ( if asked for )
+    // if we can create new slivers, check that the edge is long enough to allow it
+    if ( worstShape < mpm.getSliverTetBound() ) 
+      {
+        double oriWorst;
+        MeshQualityManagerSgl::instance().E_worstShape(edge, &oriWorst);
+        if ( worstShape < oriWorst ) {
+          if ( !mpm.getSliverPermissionInESplit() ) return false;
+          if ( mpm.getSliverUpperLengthSqBound() > 0. &&
+               mpm.getSliverUpperLengthSqBound() > SFManager->getSizeField()->SF_E_lengthSq(edge) )
+            {
+              return false;
+            }
+        }
+      }
+
+    // do the job
+    eSplitOp->apply();
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool MeshAdapter::collapseEdge(pEdge edge)
+  {
+    double shapes[2] = {-1.,-1.};
+    int ok[2] = {0,0};
+
+    for (int iDir=0; iDir<2; iDir++) {
+
+      pVertex vDel = E_vertex(edge,iDir);
+      pVertex vTgt = E_vertex(edge,1-iDir);
+      eCollapseOp->setCollapseEdge(edge,vDel,vTgt);
+
+      // do the checks
+      ok[iDir] = eCollapseOp->evaluate(&(shapes[iDir]));
+
+      // check that we do not create a worse sliver ( if asked for )
+      // if we can create new slivers, check that the edge is short enough to allow it
+      if ( shapes[iDir] < mpm.getSliverTetBound() ) 
+        {
+          double oriWorst;
+          MeshQualityManagerSgl::instance().E_worstShape(edge, &oriWorst);
+          if ( shapes[iDir] < oriWorst ) {
+            if ( !mpm.getSliverPermissionInECollapse() ) ok[iDir] = 0;
+            if ( mpm.getSliverLowerLengthSqBound() > 0. &&
+                 mpm.getSliverLowerLengthSqBound() < SFManager->getSizeField()->SF_E_lengthSq(edge) )
+              {
+                ok[iDir] = 0;
+              }
+          }
+        }
+    }
+  
+    // find the best direction
+    int best = -1; double worst = -1.;
+    if ( ok[0] ) { best = 0; worst = shapes[0]; }
+    if ( ok[1] && shapes[1] > worst ) {
+      best = 1;
+      worst = shapes[1];
+    }
+  
+    // if possible apply an edge collapse
+    if ( best >= 0 ) {
+      pVertex vDel = E_vertex(edge,best);
+      pVertex vTgt = E_vertex(edge,1-best);
+      eCollapseOp->setCollapseEdge(edge,vDel,vTgt);
+      eCollapseOp->apply();
+      return true;
+    }
+
+    return false;
+  }
+
+  // -------------------------------------------------------------------
+  bool MeshAdapter::collapseFace(pFace face, pEdge edge)
+  {
+    for( int ClpsOnvt = 1; ClpsOnvt >=0; ClpsOnvt-- )
+      {
+        fCollapseOp->reset(face, edge, ClpsOnvt);
+        
+        // do the checks
+        double worstShape;
+        if ( !fCollapseOp->evaluate(&worstShape) ) continue;
+        
+        // check that we do not create a sliver
+        if ( worstShape < mpm.getSliverTetBound() ) continue;
+        
+        // do the job
+        fCollapseOp->apply();
+        return true;
+      }
+    return false;
+  }
+
+  // -------------------------------------------------------------------
+  bool MeshAdapter::DSplitCollapseEdge(pRegion pr, pEdge edge1, pEdge edge2)
+  {
+    descOp->setDESC(pr,edge1,edge2);
+
+    // do the checks
+    double worstShape;
+    if ( !descOp->evaluate(&worstShape) ) return false;
+
+    // check that we do not create a sliver
+    if ( worstShape < mpm.getSliverTetBound() ) return false;
+
+    // do the job
+    descOp->apply();
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool MeshAdapter::swapEdge(pEdge edge)
+  {
+    eSwapOp->setSwapEdge(edge);
+
+    // do the checks
+    double worstShape;
+    if ( !eSwapOp->evaluate(&worstShape) ) return false;
+
+    // check that we do not create a sliver
+    if ( worstShape < mpm.getSliverTetBound() ) return false;
+
+    // do the job
+    eSwapOp->apply();
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool MeshAdapter::swapFace(pFace face)
+  {
+    fSwapOp->setSwapFace(face);
+  
+    // do the checks
+    double worstShape;
+    if ( !fSwapOp->evaluate(&worstShape) ) return false;
+
+    // check that we do not create a sliver
+    if ( worstShape < mpm.getSliverTetBound() )  return false;
+
+    // do the job
+    fSwapOp->apply();
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool MeshAdapter::moveVertex (pVertex v, double dxyz[3])
+  {
+    return vMoveOp->move(v,dxyz);
+  }
+
+  // -------------------------------------------------------------------
+  bool MeshAdapter::removeRegion(pRegion region)
+  {
+    rRegionOp->setRegion(region);
+  
+    // do the checks
+    double worstShape;
+    if ( !rRegionOp->evaluate(&worstShape) ) return false;
+
+    // check that we do not create a sliver
+    if ( worstShape < mpm.getSliverTetBound() )  return false;
+
+    // do the job
+    rRegionOp->apply();
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool MeshAdapter::putVertex (pVertex v, double xyz[3])
+  {
+    double oriPos[3], dxyz[3];
+    V_coord(v,oriPos);
+    for (int i=0; i<3; i++) dxyz[i] = xyz[i] - oriPos[i];
+    return moveVertex(v,dxyz);
+  }
+
+  // -------------------------------------------------------------------
+  bool MeshAdapter::moveVertices (multiset<vDisplacement,vDisplacementLess>& vDisps)
+  {
+    return vMoveOp->move(vDisps);
+  }
+
+  // -------------------------------------------------------------------
+  // LEVEL 2 OPERATIONS
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  double MeshAdapter::LaplaceSmoothing(LaplSmooType type)
+  {
+    MAdResourceManager& tm   = MAdResourceManagerSgl::instance();
+    MAdStatistics&  stat = MAdStatisticsSgl ::instance();
+
+    double t0 = tm.getTime();
+
+    double convergenceCriterion = 1e-2;
+    double L2Disp = 0.;
+    LaplaceSmoothingOp* laplOp = new LaplaceSmoothingOp(mesh,SFManager->getSizeField());
+    laplOp->run(type,&L2Disp);
+    double L2Disp0 = L2Disp; int i = 0;
+    double L2DispTot = 0.;
+    while ( ( L2Disp > convergenceCriterion * L2Disp0 ) && ( L2Disp > MAdTOL ) ) {
+      laplOp->run(type,&L2Disp);
+      i++;
+      L2DispTot += L2Disp;
+    }
+    if (laplOp) delete laplOp;
+
+    double dt = tm.getTime() - t0;
+    if ( verbosity >= 2 ) {
+      cout << "Performed a Laplace smoothing: total L2 norm of the displacements: "<<L2DispTot<<" in "<<dt<<" seconds\n";
+    }
+
+    if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+    return L2DispTot;
+  }
+
+  // -------------------------------------------------------------------
+  int MeshAdapter::eSplitLoop() 
+  {
+    MAdResourceManager& tm   = MAdResourceManagerSgl::instance();
+    MAdStatistics&  stat = MAdStatisticsSgl ::instance();
+
+    double t0 = tm.getTime();
+
+    int nSplit = 0;
+    int countE = 0; int oriNbEdges = M_numEdges(mesh);
+    EIter ei = M_edgeIter(mesh);
+    pEdge edge;
+    while ( (countE < oriNbEdges) && ( edge = EIter_next(ei) ) ) {
+      double lengthSq = SFManager->getSizeField()->SF_E_lengthSq(edge);
+      if ( lengthSq > mpm.getUpperLengthSqBound() ) if (splitEdge(edge,true)) nSplit++;
+      countE++;
+    }
+    EIter_delete(ei);
+        
+    double dt = tm.getTime() - t0;
+    stat.addCPUESplits(dt);
+    stat.addNumESplits(nSplit);
+    if ( verbosity >= 2 ) {
+      cout << "Performed "<< nSplit<<" edge splits in "<<dt<<" seconds\n";
+    }
+
+    if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+    // --- Geometry tracking ---
+    if (nSplit) snapVertices();
+    
+    return nSplit;
+  }
+
+  // -------------------------------------------------------------------
+  int MeshAdapter::eCollapseLoop() 
+  {
+    MAdResourceManager& tm   = MAdResourceManagerSgl::instance();
+    MAdStatistics&  stat = MAdStatisticsSgl ::instance();
+
+    double t0 = tm.getTime();
+
+    int nCollapse = 0;
+    int countE = 0; int oriNbEdges = M_numEdges(mesh);
+    EIter ei = M_edgeIter(mesh);
+    pEdge edge;
+    while ( (countE < oriNbEdges) && ( edge = EIter_next(ei) ) ) {
+      double lengthSq = SFManager->getSizeField()->SF_E_lengthSq(edge);
+      if ( lengthSq < mpm.getLowerLengthSqBound() ) if (collapseEdge(edge)) nCollapse++;
+      countE++;
+    }
+    EIter_delete(ei);
+
+    double dt = tm.getTime() - t0;
+    stat.addCPUECollapses(dt);
+    stat.addNumECollapses(nCollapse);
+    if ( verbosity >= 2 ) {
+      cout << "Performed "<< nCollapse<<" edge collapses in "<<dt<<" seconds\n";
+    }
+
+    if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+    return nCollapse;
+  }
+
+  // -------------------------------------------------------------------
+  int MeshAdapter::eSplitCollapseLoop() 
+  {
+    int nSplit = 0;
+    int nCollapse = 0;
+    int countE = 0; int oriNbEdges = M_numEdges(mesh);
+    EIter ei = M_edgeIter(mesh);
+    pEdge edge;
+    while ( (countE < oriNbEdges) && ( edge = EIter_next(ei) ) ) {
+      double lengthSq = SFManager->getSizeField()->SF_E_lengthSq(edge);
+      if ( lengthSq > mpm.getUpperLengthSqBound() ) if (splitEdge(edge,true)) nSplit++;
+      if ( lengthSq < mpm.getLowerLengthSqBound() ) if (collapseEdge(edge)) nCollapse++;
+      countE++;
+    }
+    EIter_delete(ei);
+
+    if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+    return nSplit+nCollapse;
+  }
+
+  // -------------------------------------------------------------------
+  int MeshAdapter::edgeSwapLoop()
+  {
+    MAdResourceManager& tm   = MAdResourceManagerSgl::instance();
+    MAdStatistics&  stat = MAdStatisticsSgl ::instance();
+
+    double t0 = tm.getTime();
+
+    int nb_eswap = 0;
+    pEdge edge;
+    EIter ei = M_edgeIter(mesh);
+    int ne = M_numEdges(mesh);
+    int i = 0;
+    while( ( edge = EIter_next(ei) ) )
+    {
+      if( i > ne ) break;
+      i++;
+  
+      if( EN_constrained((pEntity)edge) )  continue;
+      if( E_numRegions(edge) > eSwapOp->getMaxNumRgns() )  continue;
+  
+      double worstShape;
+      MeshQualityManagerSgl::instance().E_worstShape(edge, &worstShape);
+  
+      if( worstShape > mpm.getNoSwapQuality() ) continue;
+  
+      eSwapOp->setSwapEdge(edge);
+
+      double newWorstShape;
+      if( eSwapOp->evaluate(&newWorstShape) )
+      {
+        if( newWorstShape > mpm.getSwapMinImproveRatio()*worstShape )
+        {
+          if( ( eSwapOp->getMaxLenSq() < mpm.getUpperLengthSqBound() ) &&
+            ( eSwapOp->getMinLenSq() > mpm.getLowerLengthSqBound() ) )
+          {
+            eSwapOp->apply();
+            nb_eswap++;
+          }
+        }
+      }
+    }
+    EIter_delete(ei);
+
+    double dt = tm.getTime() - t0;
+    stat.addCPUESwaps(dt);
+    stat.addNumESwaps(nb_eswap);
+    if ( verbosity >= 2 ) {
+      cout << "Performed "<< nb_eswap<<" edge swaps in "<<dt<<" seconds\n";
+    }
+
+    if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+    return nb_eswap;
+  }
+
+  // -------------------------------------------------------------------
+  int MeshAdapter::faceSwapLoop() 
+  {
+    int nfswap = 0;
+    pFace face;
+    FIter fi = M_faceIter(mesh);
+    int nf = M_numFaces(mesh);
+    int i = 0;
+    while ( ( face = FIter_next(fi) ) ) {
+      if( i > nf ) break;
+      i++;
+
+      if( EN_constrained((pEntity)face) )  continue;
+
+      double oriWorst;
+      MeshQualityManagerSgl::instance().F_worstShape(face, &oriWorst);
+
+      if ( oriWorst > mpm.getNoSwapQuality() ) continue;
+
+      fSwapOp->setSwapFace(face);
+      double newWorst;
+      if( fSwapOp->evaluate(&newWorst) ) {
+        if ( newWorst > mpm.getSwapMinImproveRatio()*oriWorst ) {
+          fSwapOp->apply();
+          nfswap++;
+        }
+      }
+    }
+    FIter_delete(fi);
+
+    if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+    return nfswap;
+  }
+
+  // -------------------------------------------------------------------
+  int MeshAdapter::splitEveryEdgeOnce()
+  {
+    MAdResourceManager& tm   = MAdResourceManagerSgl::instance();
+    double t0 = tm.getTime();
+
+    // list initial edges
+    std::set<pEdge> initEdges;
+    EIter ei = M_edgeIter(mesh);
+    pEdge edge;
+    while ( ( edge = EIter_next(ei) ) ) initEdges.insert(edge);
+    EIter_delete(ei);
+    
+    // split every edge
+    int numOp = 0;
+    std::set<pEdge>::const_iterator it = initEdges.begin();
+    for (; it != initEdges.end(); it++ ) {
+      if ( splitEdge( *it ) ) numOp++;
+    }
+
+    double dt = tm.getTime() - t0;
+    if ( verbosity >= 2 ) {
+      cout << "Performed "<< numOp<<" edge splits in "<<dt<<" seconds\n";
+    }
+
+    if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+    // --- Geometry tracking ---
+    if (numOp) snapVertices();
+    
+    return numOp;
+  }
+
+  // -------------------------------------------------------------------
+  int MeshAdapter::removeSlivers()
+  {
+    MAdResourceManager& tm   = MAdResourceManagerSgl::instance();
+    MAdStatistics&  stat = MAdStatisticsSgl ::instance();
+
+    double t0 = tm.getTime();
+
+    int nbBefore, nbAfter;
+    if (M_dim(mesh) == 3) sliverROp->removeSliverRegions(&nbBefore,&nbAfter);
+    else                  sliverFOp->removeSliverFaces  (&nbBefore,&nbAfter);
+
+    double dt = tm.getTime() - t0;
+    stat.addCPURSlivers(dt);
+    if ( verbosity >= 2 ) {
+      cout << "Removed slivers " << nbBefore << " -> " << nbAfter << " in "<<dt<<" seconds\n";
+    }
+
+    if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+    return ( nbBefore - nbAfter );
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::snapVertices()
+  {
+    if (geoTracker) {
+      MAdResourceManager& tm = MAdResourceManagerSgl::instance();
+      double t0 = tm.getTime();
+
+      // --- prepare the node motion ---
+      geoTracker->buildCavity();
+      geoTracker->setDirichletBC();
+      geoTracker->compute();
+
+// #warning "debug"
+//       geoTracker->forceRelocation();
+      
+      // --- perform the node motion ---
+      double ratio = 0.;
+      int achieved = -1;
+      while ( achieved != 2 )
+        {
+          achieved = geoTracker->advance(&ratio,1.e-12);
+          
+          if ( achieved == 0 ) {
+            MAdMsgSgl::instance().warning(-1,__FILE__,
+                                          "Could not advance snapping, achieved: %d, ratio: %f",achieved,ratio);
+          }
+          else {
+            MAdMsgSgl::instance().info(-1,__FILE__,
+                                       "Advance snapping, achieved: %d, ratio: %f",achieved,ratio);
+          }
+          if ( debugLevel >= 4 && !checkTheMesh() )  abort(__LINE__,__FILE__);
+          
+          if ( achieved <= 1 ) {
+            // Apply the operations that do not add vertices or manage their 
+            // target locations (complicated!)
+            bool slivR, slivF;
+            if ( sliverROp ) slivR = sliverROp->getNewVertexPermission();
+            if ( sliverFOp ) slivF = sliverFOp->getNewVertexPermission();
+            if ( sliverROp ) sliverROp->newVertexPermission(false);
+            if ( sliverFOp ) sliverFOp->newVertexPermission(false);
+            if ( !removeSlivers() ) {
+              if ( !optimiseElementShape() ) {
+                string filename = outPrefix + "dirichlet.txt";
+                std::ofstream dirichletOut(filename.c_str());
+                geoTracker->printDirichlet(dirichletOut);
+                dirichletOut.close();
+                filename = outPrefix + "relocations.txt";
+                std::ofstream relocationsOut(filename.c_str());
+                geoTracker->printRelocations(relocationsOut);
+                relocationsOut.close();
+                MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+                                            "Could not snap vertices, ratio reached: %f",ratio);
+                geoTracker->reportFailure(ratio);
+                break;
+              }
+            }
+            if ( sliverROp ) sliverROp->newVertexPermission( slivR );
+            if ( sliverFOp ) sliverFOp->newVertexPermission( slivF );
+            if ( debugLevel >= 4 && !checkTheMesh() )  abort(__LINE__,__FILE__);
+          }
+        }
+      
+      geoTracker->clear();
+
+      double dt = tm.getTime() - t0;
+      MAdMsgSgl::instance().info(__LINE__,__FILE__,
+                                 "Performed vertex snapping in %f seconds",dt);
+    }
+
+    if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+  }
+
+  // -------------------------------------------------------------------
+  // LEVEL 3 OPERATIONS
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  int MeshAdapter::optimiseEdgeLength()
+  {
+    int nbMaxItOptiLen = 10;
+    int nSplColl = 0;
+    for (int iter=0; iter < nbMaxItOptiLen; iter++ ) {
+      int nSC = eSplitCollapseLoop();
+      cout << "Applied "<<nSC<<" split or collapses\n";
+      if (!nSC) break;
+      nSplColl += nSC;
+    }
+    return nSplColl;
+  }
+
+  // -------------------------------------------------------------------
+  int MeshAdapter::optimiseElementShape()
+  {
+    int nbMaxItOptiShp = 10;
+    int nESwapTot = 0, nFSwapTot = 0;
+    int nESwap = 0, nFSwap = 0;
+    for (int iter=0; iter < nbMaxItOptiShp; iter++ ) {
+      // find ill-shaped elements around each edge
+      nESwap = edgeSwapLoop();
+      cout << "Applied " << nESwap<< " edge swaps"<<endl;
+      if ( M_dim(mesh) == 3 ) {
+        // find ill-shaped elements around each face
+        nFSwap = faceSwapLoop();
+        cout << "Applied " << nFSwap<< " face swaps"<<endl;
+      }
+    
+      if (nESwap+nFSwap == 0) break;
+      nESwapTot += nESwap;
+      nFSwapTot += nFSwap;
+    }
+    return ( nESwapTot + nFSwapTot );
+  }
+
+  // -------------------------------------------------------------------
+  int MeshAdapter::splitLongestEdges() 
+  {
+    MAdResourceManager& tm   = MAdResourceManagerSgl::instance();
+    MAdStatistics&  stat = MAdStatisticsSgl ::instance();
+
+    double t0 = tm.getTime();
+
+    int nSplitTot = 0;
+    double boundSq = 2.*mpm.getUpperLengthSqBound();
+
+    while (1)
+      {
+        int nSplit = 0;
+        
+        EIter ei = M_edgeIter(mesh);
+        pEdge edge;
+        double lengthSq;
+        while ( ( edge = EIter_next(ei) ) ) {
+          lengthSq = SFManager->getSizeField()->SF_E_lengthSq(edge);
+          if ( lengthSq > boundSq ) if (splitEdge(edge,true)) nSplit++;
+        }
+        EIter_delete(ei);
+
+        nSplitTot += nSplit;
+        if ( debugLevel >= 3 && !checkTheMesh() ) abort(__LINE__,__FILE__);
+
+        if ( nSplit == 0 ) break;
+      }
+    
+    double dt = tm.getTime() - t0;
+    stat.addCPUESplits(dt);
+    stat.addNumESplits(nSplitTot);
+    if ( verbosity >= 2 ) {
+      cout << "Performed "<< nSplitTot<<" (very long) edge splits in "<<dt<<" seconds\n";
+    }
+
+    // --- Geometry tracking ---
+    if (nSplitTot) snapVertices();
+
+    return nSplitTot;
+  }
+
+  // -------------------------------------------------------------------
+  int MeshAdapter::runOneIter()
+  {
+    MAdResourceManager& tm = MAdResourceManagerSgl::instance();
+
+    // --- constrain parallel interfaces ---
+#ifdef PARALLEL
+    { 
+      double t0= tm.getTime();
+      UpdateParallelConstraint(mesh);
+      double dt = tm.getTime() - t0;
+      MAdMsgSgl::instance().info(__LINE__,__FILE__,
+                                 "Performed constraint of parallel interfaces in %f seconds",dt);
+      MPI_Barrier(MPI_COMM_WORLD);
+    }
+#endif
+
+    // --- perform local mesh modifications ---
+    int numTopoChg = 0;
+
+    // first, split very long edges (avoid infinite loops split/collapse)
+//     numTopoChg += splitLongestEdges();
+    
+    if ( algorithm == CPS_SWP_SLV_SPT )
+      {
+        numTopoChg += eCollapseLoop(); // Collapse short edges
+        numTopoChg += edgeSwapLoop();  // Swap edges to improve elements quality
+        numTopoChg += removeSlivers(); // Remove slivers
+        numTopoChg += eSplitLoop();    // Split long edges
+      }
+
+    if ( algorithm == SPT_SWP_SLV_CPS )
+      {
+        numTopoChg += eSplitLoop();    // Split long edges
+        numTopoChg += edgeSwapLoop();  // Swap edges to improve elements quality
+        numTopoChg += removeSlivers(); // Remove slivers
+        numTopoChg += eCollapseLoop(); // Collapse short edges
+      }
+
+    if ( algorithm == SLV_CPS_SWP_SPT )
+      {
+        numTopoChg += removeSlivers(); // Remove slivers
+        numTopoChg += eCollapseLoop(); // Collapse short edges
+        numTopoChg += edgeSwapLoop();  // Swap edges to improve elements quality
+        numTopoChg += eSplitLoop();    // Split long edges
+      }
+
+    // --- Reposition the vertices ---
+//     LaplaceSmoothing(OPTIMAL);
+//     LaplaceSmoothing(FAST);
+
+#ifdef PARALLEL
+    // --- move parallel interfaces ---
+    { 
+      MPI_Barrier(MPI_COMM_WORLD);
+      double t0 = tm.getTime();
+      DeleteParallelConstraint(mesh);
+      double dt = tm.getTime() - t0;
+      if( verbosity >= 2 ) {
+        MAdMsgSgl::instance().info(__LINE__,__FILE__,
+                                   "Performed unconstraint of parallel interface in %f seconds",dt);
+      }
+
+      t0 = tm.getTime();
+      switch( load_balance_algorithm  ) {      
+      case DEFAULT_ALGORITHM:
+        Balance2( mesh, *dataExchanger );
+        break;
+      case METIS_ALGORITHM:
+#ifdef _HAVE_PARMETIS_
+        BalanceMetis2( mesh, *dataExchanger );
+#else
+        MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                    "Could not balance load: Parmetis not enabled");
+#endif
+        break;
+      default:
+        MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                    "Unknown load balancing algorithm: %d",
+                                    load_balance_algorithm);        
+      }
+      dt = tm.getTime() - t0;
+      if( verbosity >= 2 ) {
+        MAdMsgSgl::instance().info(__LINE__,__FILE__,
+                                   "Performed load balancing in %f seconds",dt);
+      }
+    }
+#endif
+
+    // --- check the mesh (debug) ---
+    if ( debugLevel >= 2 && !checkTheMesh() )  abort(__LINE__,__FILE__);
+
+    return numTopoChg;
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::uglyTheMesh(double avgQualThresh, int maxIt)
+  {
+    MeshQualityManagerSgl::instance().evaluateStatistics();
+    double meanQuality  = MeshQualityManagerSgl::instance().getMeanShape();
+  
+    int iter = 0;
+    while ( (meanQuality > avgQualThresh) && (iter < maxIt) ) {
+
+      int numOp = 0;
+      int oriNumFaces = M_numFaces(mesh);
+      int count = 0;
+      FIter fi = M_faceIter(mesh);
+      pFace pf;
+      while ( ( pf = FIter_next(fi) ) && ( count < oriNumFaces ) ) {
+        int flag = 0;
+        for (int j=0; j<3; j++) {
+          pEdge pe = F_edge(pf,j);
+          for( int ClpsOnvt = 0; ClpsOnvt < 2; ClpsOnvt++ ) {
+            fCollapseOp->reset(pf, pe, ClpsOnvt);
+            double worstShape;
+            if ( fCollapseOp->evaluate(&worstShape) ) {
+              fCollapseOp->apply();
+              flag = 1;
+              break;
+            }
+          }
+          if ( flag ) {
+            numOp++;
+            break;
+          }
+        }
+        count++;
+      }
+      FIter_delete(fi);
+      cout << "Num face collapses: "<<numOp<<endl;
+    
+      meanQuality  = MeshQualityManagerSgl::instance().getMeanShape();
+      iter++;
+    }
+  }
+
+  // -------------------------------------------------------------------
+  //! Removes elements with negative volume and returns \ingroup adaptation
+  //! number of remaining negative volumes
+  int MeshAdapter::removeNegativeElements()
+  {
+    int nNeg = 0;
+    int nRem = 0;
+    RIter rIt= M_regionIter(mesh);
+    while ( pRegion region = RIter_next(rIt) ) {
+      if (R_volume(region) < 0.) {
+        nNeg++;
+        if ( removeRegion(region) ) nRem++;
+      }
+    }
+    RIter_delete(rIt);
+
+    cout << "Negative elements removal: "
+         << nNeg << " detected, "
+         << nRem << " removed\n";
+
+    return (nNeg - nRem);
+  }
+
+  // -------------------------------------------------------------------
+  // LEVEL 4 OPERATIONS
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::run()
+  {
+    // --- Adaptation procedure ---
+
+    MAdResourceManager& tm = MAdResourceManagerSgl::instance();
+    double t0= tm.getTime();
+
+    cout << "\n +++ Starting a MDB mesh adaptation procedure +++\n";
+    if ( verbosity >= 2 ) cout<<"\n";
+
+    for (int iter=1; iter <= maxIterationsNumber; iter++) {
+    
+      if ( verbosity >= 1 ) {
+        cout<<"   --- Mesh adaptation iteration "<<iter<<" ---\n"<<endl;
+      }
+      int num = runOneIter();
+
+#ifdef PARALLEL
+      int numGlob = 0;
+      MPI_Allreduce(&num,&numGlob,1,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
+#endif
+
+      if ( updateSFFrequency && (iter%updateSFFrequency) == 0 ) updateSizeField();
+
+      if ( verbosity >= 2 ) cout<<"\n";
+#ifdef PARALLEL
+      if ( numGlob == 0 ) break;
+#else
+      if ( num == 0 ) break;
+#endif
+
+      if ( iter == maxIterationsNumber  && num != 0 )
+        {
+          MAdStatisticsSgl::instance().addInfiniteLoops(1);
+          if ( verbosity >= 1 ) {
+            MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+                                          "Infinite loop detected");
+          }
+          break;
+        }
+    }
+
+    // --- Load balancing ---
+#ifdef PARALLEL
+    MPI_Barrier(MPI_COMM_WORLD);
+    if( load_balance_algorithm != METIS_ALGORITHM ) {   
+#ifdef _HAVE_PARMETIS_ 
+      BalanceMetis2( mesh, *dataExchanger );
+#endif
+    }
+#endif
+    
+    if ( debugLevel >= 1 && !checkTheMesh() )  abort(__LINE__,__FILE__);
+    cout << "\n +++ Ending a MDB mesh adaptation procedure (" 
+         << tm.getTime() - t0 << " seconds) +++\n";
+    if ( verbosity >= 2 ) cout<<"\n";
+  }
+
+#ifdef PARALLEL
+  // -------------------------------------------------------------------
+  void MeshAdapter::setLoadBalancingAlgorithm( loadBalanceAlgorithm lbAlgo )
+  {
+    load_balance_algorithm = lbAlgo;
+  }
+  // -------------------------------------------------------------------
+  void MeshAdapter::setDataExchanger( MDB_DataExchanger* dataExch )
+  {
+    dataExchanger = dataExch;
+  }
+#endif
+
+  // -------------------------------------------------------------------
+  int MeshAdapter::partlyMoveObjects(double t, double dt, double* part)
+  {
+    return objects->partlyMove(*vMoveOp,t,dt,part);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::moveObjectsAndReposition(double t, double dt, 
+                                             double chi, bool meshIsCavity,
+                                             int cavityThickness)
+  {
+    objects->setupElasticRepositioning(mesh, t, dt, chi,
+                                       meshIsCavity, cavityThickness);
+    double ratio = 0.;
+    int achieved = -1;
+    while ( achieved != 2 ) {
+      achieved = objects->reposition(&ratio);
+      MAdMsgSgl::instance().info(-1,__FILE__,
+                                 "Advanced repositioning, achieved: %d, ratio: %f",achieved,ratio);
+
+      if ( debugLevel >= 3 && !checkTheMesh() )  abort(__LINE__,__FILE__);
+      if ( achieved <= 1 ) {
+        if ( !removeSlivers() ) {
+          if ( !optimiseElementShape() ) {
+            MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                        "Could not advance objects, ratio reached: %f",ratio);
+          }
+        }
+      }
+    }
+    
+    if ( debugLevel >= 1 && !checkTheMesh() )  abort(__LINE__,__FILE__);
+  }
+
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  void MeshAdapter::nodalDataDiagnostics(std::ostream& out) const
+  {
+    NodalDataManagerSgl::instance().diagnostics(out);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::openJournal() const
+  {
+    HistorySgl::instance().openJournal();
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::setReferenceJournal(std::string& name) const
+  {
+    HistorySgl::instance().loadJournal(name);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::flushJournal(std::ostream& out) const
+  {
+    HistorySgl::instance().flushJournal(out);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::enableSliverReports()
+  {
+    if ( !sliverROp ) {
+      std::cerr<<"Error: no sliver region handler\n";
+      exit(0);
+    }
+
+    sliverROp->enableReport(outPrefix);
+
+    if ( !sliverFOp ) {
+      std::cerr<<"Error: no sliver face handler\n";
+      exit(0);
+    }
+
+    sliverFOp->enableReport(outPrefix);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::testSliverOperators(bool test)
+  {
+    sliverROp->setTestAllOperators(test);
+  }
+
+  // -------------------------------------------------------------------
+  bool MeshAdapter::checkTheMesh(int verbosity, std::ostream& out, 
+                                 MeshStatus * status) const
+  {
+    MAdMsgSgl::instance().info(-1,__FILE__,
+                               "Checking mesh validity (debug level = %d)",
+                               debugLevel);
+    return checkMesh(mesh,CHECK_ALL,verbosity,out,status);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::infoMobileObjects(std::ostream& out) const
+  {
+    objects->describe(out);
+  }
+
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+
+  void MeshAdapter::setOutputPrefix(string prefix)
+  {
+    outPrefix = prefix;
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::writePos(string fn, MAdOutputData type) const
+  {
+    string fullName = outPrefix + fn;
+    MAdGmshOutput(mesh, (const pSField) SFManager->getSizeField(), 
+                  fullName.c_str(), type);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::writeMsh(string fn) const
+  {
+    string fullName = outPrefix + fn;
+    M_writeMsh(mesh,fullName.c_str(),2,NULL);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::writeVolumicCurvature(string fnb) const
+  {
+    std::set<LocalSizeField*> localSF = SFManager->getLocalSizeFields();
+    std::set<LocalSizeField*>::const_iterator it = localSF.begin();
+    for (; it != localSF.end(); it++)
+      {
+        string fullName = outPrefix + fnb + "_" + (*it)->getName() + ".pos";
+        MAdGmshOutput(mesh, (const pSField) *it, fullName.c_str(),
+                      OD_CURVATURE_DIV);
+      }
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::getStatistics(double * meanQuality, 
+                                  double * worstQuality) const
+  {
+    MeshQualityManagerSgl::instance().evaluateStatistics();
+    *meanQuality  = MeshQualityManagerSgl::instance().getMeanShape();
+    *worstQuality = MeshQualityManagerSgl::instance().getWorstShape();
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::printStatistics(std::ostream& out) const
+  {
+    MeshQualityManagerSgl::instance().evaluateStatistics();
+    MeshQualityManagerSgl::instance().printStatistics(out);
+    out << "\n\n";
+    MAdStatisticsSgl::instance().print(out);
+    out << "\n\n";
+    if (geoTracker) geoTracker->printFailures(out);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshAdapter::printSliverRegionStatistics(std::ostream& out) const 
+  {
+    if ( sliverROp ) sliverROp->printStats(out);
+    //   if ( sliverROp ) sliverROp->printOperatorsTest(out);
+  }
+  // -------------------------------------------------------------------
+  void MeshAdapter::abort(int line, const char* file) const
+  {
+    cerr << "\n"
+         << " ****************************\n"
+         << "  MeshAdapter is aborting... \n"
+         << " ****************************\n\n";    
+
+    string stName = outPrefix + "aborted_statistics";
+    std::ofstream stOut(stName.c_str());
+    printStatistics(stOut);
+
+    string slName = outPrefix + "aborted_slivers";
+    std::ofstream slOut(slName.c_str());
+    printSliverRegionStatistics(slOut);
+
+    string jName = outPrefix + "aborted_journal";
+    std::ofstream jOut(jName.c_str());
+    flushJournal(jOut);
+
+    writePos("aborted.pos",OD_MEANRATIO);
+    writeMsh("aborted.msh");
+
+    if ( file && line >=0 ) {
+      MAdMsgSgl::instance().info(-1,__FILE__,
+                                 "Abort function called from file %s (line %d)",
+                                 file,line);
+    }
+    else {
+      MAdMsgSgl::instance().info(-1,__FILE__,"Abort!");
+    }
+
+    flush(cout);
+    flush(cerr);
+
+    exit(EXIT_FAILURE);
+  }
+
+  // -------------------------------------------------------------------
+
+} // End of namespace MAd
+
diff --git a/Adapt/AdaptInterface.h b/Adapt/AdaptInterface.h
new file mode 100644
index 0000000..cd19aad
--- /dev/null
+++ b/Adapt/AdaptInterface.h
@@ -0,0 +1,342 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_ADAPTINTERFACE
+#define _H_ADAPTINTERFACE
+
+// from Adapt
+#include "MAdOutput.h"
+#include "MobileObject.h"
+#include "MeshParametersManager.h"
+#include "SizeFieldManager.h"
+#include "CallBackManager.h"
+#include "CheckMesh.h"
+#include "GeoMatcher.h"
+
+// from Adapt - operators
+#include "MAdOperatorBase.h"
+#include "EdgeSplitOp.h"
+#include "EdgeCollapseOp.h"
+#include "FaceCollapseOp.h"
+#include "DESCOp.h"
+#include "EdgeSwapOp.h"
+#include "FaceSwapOp.h"
+#include "VertexMoveOp.h"
+#include "RegionRemoveOp.h"
+#include "SliverFaceHandler.h"
+#include "SliverRegionHandler.h"
+#include "NodesRepositioningOp.h"
+#include "LaplaceSmoothingOp.h"
+
+// from Mesh
+#include "MSops.h"
+#ifdef PARALLEL
+#include "MeshDataBaseComm.h"
+#endif
+
+#include <set>
+#include <string>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+
+  enum algorithmDefinition {
+    SPT_SWP_SLV_CPS,
+    CPS_SWP_SLV_SPT,
+    SLV_CPS_SWP_SPT
+  };
+#ifdef PARALLEL
+  enum loadBalanceAlgorithm {
+    DEFAULT_ALGORITHM,
+    METIS_ALGORITHM
+  };
+#endif
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  class MeshAdapter {
+
+  public:
+  
+    MeshAdapter(pMesh m, pSField sf=NULL);
+    ~MeshAdapter();
+
+    // --------------------------------------------
+
+    // gives an overview of the current parameters
+    void printParameters() const;
+
+    void addCallback(CBFunction CB, void* userData, 
+                     CBFunc_move CB_move=0, void* userData_move=0);
+    void addSizeField(pSField sf);
+
+    // whether or not the global size field is smoothed and maximum gradient
+    void setSizeFieldSmoothing(bool, double maxGrad=1.);
+
+    // set the maximum number of iterations available to reach the 'convergence' 
+    // of the global mesh adaptation procedure
+    void setMaxIterationsNumber(int max);
+
+#ifdef PARALLEL
+    // set load balancing algorithm
+    void setLoadBalancingAlgorithm( loadBalanceAlgorithm lbAlgo );
+    // set the data Exchanger
+    void setDataExchanger( MDB_DataExchanger* dataExch);
+#endif
+
+    // impose the interval governing edges length in the transformed space
+    void setEdgeLenSqBounds(double lower, double upper);
+
+    // set permission for operators to modify slightly boundaries 
+    // (default: false) and tolerance for the relative volume/area 
+    // modifications.
+    // Edge collapse and face collapse:
+    void setCollapseOnBoundary(bool accept=true, double tolerance=1.e-6);
+    // Edge swap:
+    void setSwapOnBoundary(bool accept=true, double tolerance=1.e-6);
+
+    // impose the element quality from which a swap is not required
+    void setNoSwapQuality(double noSwapQuality);
+
+    // impose a threshold rate of improvement for edge and face swaps
+    void setSwapMinImproveRatio(double ratio);
+
+    // impose the maximum quality of a sliver
+    void setSliverQuality(double sliverQuality);
+
+    // Allow or forbid operations creating a sliver. 
+    // If allowed and a bound is prescribed, it is allowed only if the edge is 
+    // longer/shorter than the bound (bound is expressed as the square of 
+    // adimensional edge length)
+    void setSliverPermissionInESplit   (bool perm, double lenSqBound=-1.);
+    void setSliverPermissionInECollapse(bool perm, double lenSqBound=-1.);
+
+    // tell if you want to project new vertices on geometric entities
+    void setGeoTracking(bool enable, bool cavityEqualMesh=false,
+                        int cavityThickness=2, double chi=1.0);
+
+    // set a value for a very huge edge length (default=1.e14)
+    void setInfiniteLength(double length);
+
+    // frequency at which the size fields are updated inside the global loop
+    // (useful for local and analytical SF)
+    void setSFUpdateFrequency(int freq);
+
+    // Set verbosity:
+    //  < 0 : no detail
+    //    1 : global procedure details
+    //  > 2 : iterations details
+    void setVerbosity(int _verbosity);
+
+    // constraint a mesh/geometric entity and all its downward entities
+    void clearConstraints() const;
+    void setConstraint(pEntity e)        const;
+    void setConstraint(pGEntity ge)      const;
+    void setConstraint(int type, int id) const;
+    // unconstrain a geometric entity
+    void removeConstraint(int type, int id) const;
+    void removeConstraint(pGEntity ge)      const;
+
+    // manage the physical time
+    void   incrementTime(double dt);
+    void   setTime(double t);
+    double getTime() const;
+    void   updateSizeField();
+
+    // functions to keep track of the initial coordinates
+    void storeInitialCoordinates();
+    void removeStoredCoordinates();
+
+    // add predefined mobile objects
+    void registerObjects(mobileObjectSet* objs);
+
+    // will attach/get the datas to the nodes of the mesh
+    // order in vector is the node iterator order
+    void registerData  (std::string name, const std::vector<double>)               const;
+    void registerVData (std::string name, const std::vector<std::vector<double> >) const;
+    void getMeshData   (std::string name, std::vector<double> *)                   const;
+    void getMeshVData  (std::string name, std::vector<std::vector<double> > *)     const;
+    void removeData    (std::string name) const;
+    void removeVData   (std::string name) const;
+
+  public:
+
+    // ---------------- OPERATIONS ----------------
+
+    // ----- Level 1 -----
+    // ---> Elementary operations
+
+    // Split the edge and if 'checkSize' is true, check that the two resulting 
+    // edges are not short edges.
+    bool splitEdge (pEdge e, bool checkSize=false);
+    bool collapseEdge (pEdge e);
+    bool collapseFace(pFace f, pEdge e);
+    bool DSplitCollapseEdge(pRegion pr, pEdge edge1, pEdge edge2);
+    bool swapEdge (pEdge e);
+    bool swapFace (pFace f);
+    bool removeRegion(pRegion region);
+    bool moveVertex (pVertex v, double dxyz[3]);
+    bool putVertex (pVertex v, double xyz[3]);
+    bool moveVertices (std::multiset<vDisplacement,vDisplacementLess>& vDisps);
+
+    // ----- Level 2 -----
+    // ---> Loops on one elementary operation
+
+    // node repositioning
+    double LaplaceSmoothing(LaplSmooType type);
+
+    // topology operations
+    int eSplitLoop();
+    int eCollapseLoop();
+    int eSplitCollapseLoop();
+    int edgeSwapLoop();
+    int faceSwapLoop();
+    int splitEveryEdgeOnce();
+
+    // slivers handling
+    int removeSlivers();
+
+    // geometry matching
+    void snapVertices();
+
+    // ----- Level 3 -----
+    // ---> Procedures with a global objective
+    int optimiseEdgeLength();
+    int optimiseElementShape();
+    int splitLongestEdges();
+    int runOneIter();
+    void uglyTheMesh(double avgQualThresh, int maxIt);
+    int removeNegativeElements();
+
+    // ----- Level 4 -----
+    // ---> Global procedure
+    void run();
+
+    // ----- objects motion -----
+    // move boundaries without repositioning nodes in the volume
+    int partlyMoveObjects        (double t, double dt, double* part);
+    // move boundaries and reposition all nodes with an elasticity analogy
+    //   chi:             stiffness alteration coefficient (-1 = none)
+    //   meshIsCavity:    true = elastic computation on whole mesh
+    //   cavityThickness: nb layers of elements if mesh is not the cavity
+    void moveObjectsAndReposition (double t, double dt, double chi=-1., 
+                                   bool meshIsCavity=true, 
+                                   int cavityThickness=3);
+    
+    // --------------------------------------------
+
+  public:
+
+    // ------ Diagnostics ------
+
+    // get informations on mesh quality
+    void getStatistics(double * meanQuality, double * worstQuality) const;
+  
+    // about all datas attached to the nodes
+    void nodalDataDiagnostics(std::ostream& out) const;
+  
+    // journals listing all operations tested or applied
+    void setDebugLevel(int debug) { debugLevel = debug; }
+    void openJournal() const;
+    void setReferenceJournal(std::string& name) const;
+    void flushJournal(std::ostream& out) const;
+
+    // sliver outputs
+    void enableSliverReports();
+    void testSliverOperators(bool test);
+
+    // performs several checks to check the validity of the mesh
+    bool checkTheMesh(int verbose=1, 
+                      std::ostream& out=std::cout, 
+                      MeshStatus * status=NULL) const;
+
+    // get infos about mobile objects
+    void infoMobileObjects(std::ostream& out=std::cout) const;
+
+  public:
+
+    // ------ Outputs ------
+
+    // set the path to output directory
+    void setOutputPrefix(std::string prefix);
+
+    // write mesh with required postpro data in 'pos' format (Gmsh)
+    void writePos(std::string fn, MAdOutputData type=OD_CONSTANT) const;
+
+    // write mesh in 'msh' format (Gmsh)
+    void writeMsh(std::string fn) const;
+
+    // write a .pos file with the 'volumic' curvature for every local size field
+    void writeVolumicCurvature(std::string fnBase) const;
+
+    // get global data over the mesh
+    void printStatistics(std::ostream& out) const;
+    void printSliverRegionStatistics(std::ostream& out) const;
+
+  public:
+
+    // save all available informations to output directory and abort
+    void abort(int line=-1, const char* file=NULL) const;
+
+    // --------------------------------------------
+
+  private:
+
+    void setDefaultValues();
+    void buildOperators();
+    void removeOperators();
+
+  private:
+
+    pMesh mesh;
+    SizeFieldManager * SFManager;
+
+    mobileObjectSet * objects;
+
+    // ----- Local mesh modification operators -----
+    edgeSplitOp          *  eSplitOp;
+    edgeCollapseOp       *  eCollapseOp;
+    faceCollapseOp       *  fCollapseOp;
+    DESCOp               *  descOp;
+    edgeSwapOp           *  eSwapOp;
+    faceSwapOp           *  fSwapOp;
+    vertexMoveOp         *  vMoveOp;
+    regionRemoveOp       *  rRegionOp;
+    sliverFaceHandler    *  sliverFOp;
+    sliverRegionHandler  *  sliverROp;
+
+    // ----- Geometry related -----
+    geoMatcher * geoTracker;
+
+    // ----- Adaptation parameters -----
+    algorithmDefinition algorithm;
+    int maxIterationsNumber;
+    MeshParametersManager& mpm;
+#ifdef PARALLEL
+    loadBalanceAlgorithm load_balance_algorithm;
+    MDB_DataExchanger*   dataExchanger;
+#endif
+    int updateSFFrequency;
+
+    // ----- Output parameters -----
+    int verbosity;
+    std::string outPrefix;
+    int debugLevel;
+  };
+
+  // -------------------------------------------------------------------
+
+} // End of namespace MAd
+
+#endif
+
diff --git a/Adapt/Makefile b/Adapt/Makefile
new file mode 100644
index 0000000..aee788c
--- /dev/null
+++ b/Adapt/Makefile
@@ -0,0 +1,100 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information. 
+# You should have received a copy of these files along with MAdLib. 
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../variables
+
+LIB = ../lib/libMAdAdapt${LIBEXT}
+
+INC =  ${MAdLib_INCLUDES}\
+       ${DASH}I$(MAdROOT)/Geo\
+       ${DASH}I$(MAdROOT)/Mesh\
+       ${DASH}I$(MAdROOT)/Common\
+       ${DASH}I$(MAdROOT)/Adapt\
+       ${DASH}I$(MAdROOT)/Adapt/constraint\
+       ${DASH}I$(MAdROOT)/Adapt/operator\
+       ${DASH}I$(MAdROOT)/Adapt/output\
+       ${DASH}I$(MAdROOT)/Adapt/quality\
+       ${DASH}I$(MAdROOT)/Adapt/repositioning\
+       ${DASH}I$(MAdROOT)/Adapt/sizeField\
+       ${DASH}I$(MAdROOT)/Adapt/utils
+
+ALLFLAGS = ${OPTIM} ${CXXFLAGS} ${MAdLib_DEFS} ${FLAGS} ${INC} ${SYSINCLUDE}
+
+SRC = AdaptInterface.cc\
+      MeshParametersManager.cc\
+      constraint/Constraint.cc\
+      constraint/ModelConstraintManager.cc\
+      operator/DESCOp.cc\
+      operator/EdgeCollapseOp.cc\
+      operator/EdgeSplitOp.cc\
+      operator/EdgeSwapConfig.cc\
+      operator/EdgeSwapOp.cc\
+      operator/FaceCollapseOp.cc\
+      operator/FaceSwapOp.cc\
+      operator/MAdOperatorBase.cc\
+      operator/OperatorTools.cc\
+      operator/RegionRemoveOp.cc\
+      operator/SliverFaceHandler.cc\
+      operator/SliverRegionHandler.cc\
+      operator/VertexMoveOp.cc\
+      output/MAdOutput.cc\
+      quality/MeanRatioEvaluator.cc\
+      quality/OrientedMeanRatioEvaluator.cc\
+      quality/MeshQualityManager.cc\
+      repositioning/GeoMatcher.cc\
+      repositioning/LaplaceSmoothingOp.cc\
+      repositioning/MAdElasticityOp.cc\
+      repositioning/MobileObject.cc\
+      sizeField/AnalyticalSField.cc\
+      sizeField/AnisoMeshSize.cc\
+      sizeField/DiscreteSF.cc\
+      sizeField/IsoMeshSize.cc\
+      sizeField/LocalSizeField.cc\
+      sizeField/MeshSizeBase.cc\
+      sizeField/NullSField.cc\
+      sizeField/PWLinearSField.cc\
+      sizeField/SizeFieldBase.cc\
+      sizeField/SizeFieldManager.cc\
+      utils/CallBackManager.cc\
+      utils/History.cc\
+      utils/MAdStatistics.cc\
+      utils/MAdTimeManager.cc\
+      utils/NodalDataManager.cc\
+      utils/DistanceFunction.cc\
+      ../Contrib/mathex/mathex.cc
+
+OBJ = ${SRC:.cc=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cc
+
+${LIB}: ${OBJ} 
+	${AR} ${ARFLAGS} ${LIB} ${OBJ}
+	${RANLIB} ${LIB}
+
+cpobj: ${OBJ} 
+	cp -f ${OBJ} ${MAdLib_TMPDIR}/.
+
+.cc${OBJEXT}:
+	${CXX} ${ALLFLAGS} ${DASH}c $< ${DASH}o $@
+
+clean:
+	${RM} */*.o *.o *.obj ../Contrib/mathex/*.o
+
+purge:
+
+depend:
+	(sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+         ${CXX} -MM ${ALLFLAGS} ${SRC} | sed 's/.o:/$${OBJEXT}:/g' \
+        ) > Makefile.new
+	cp Makefile Makefile.bak
+	cp Makefile.new Makefile
+	rm -f Makefile.new
\ No newline at end of file
diff --git a/Adapt/MeshParametersManager.cc b/Adapt/MeshParametersManager.cc
new file mode 100644
index 0000000..58c3664
--- /dev/null
+++ b/Adapt/MeshParametersManager.cc
@@ -0,0 +1,161 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MeshParametersManager.h"
+#include "MAdMessage.h"
+
+// standart C/C++
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  MeshParametersManager::MeshParametersManager():
+    lowerLengthSqBound(-1.), upperLengthSqBound(-1.), 
+    sliverTetQualityBound(-1.), sliverTriQualityBound(-1.), 
+    sliverPermInESplit(false), sliverPermInECollapse(false),
+    sliverLowerLengthSqBound(-1.),sliverUpperLengthSqBound(-1.),
+    noSwapQuality(-1.),swapMinImproveRatio(-1.), bigLength(1.e14)
+  {}
+
+  // -------------------------------------------------------------------
+  void MeshParametersManager::initialize()
+  {
+  }
+
+  // -------------------------------------------------------------------
+  void MeshParametersManager::finalize()
+  {
+  }
+
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+
+  void MeshParametersManager::setLowerLengthSqBound(double lSq)
+  {
+    lowerLengthSqBound = lSq;
+  }
+
+  // -------------------------------------------------------------------
+
+  void MeshParametersManager::setUpperLengthSqBound(double lSq)
+  {
+    upperLengthSqBound = lSq;
+  }
+
+  // -------------------------------------------------------------------
+  double MeshParametersManager::getSliverBound(int dim) const
+  {
+    if (dim==3) return getSliverTetBound();
+    return getSliverTriBound();
+  }
+
+  // -------------------------------------------------------------------
+  double MeshParametersManager::getSliverBound(const pMesh mesh) const
+  {
+    return getSliverBound(M_dim(mesh));
+  }
+
+  // -------------------------------------------------------------------
+
+  void MeshParametersManager::setSliverTriBound(double bound)
+  {
+    sliverTriQualityBound = bound;
+  }
+
+  // -------------------------------------------------------------------
+
+  void MeshParametersManager::setSliverTetBound(double bound)
+  {
+    sliverTetQualityBound = bound;
+  }
+
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+
+  void MeshParametersManager::setSliverPermissionInESplit(bool perm, 
+                                                          double bound)
+  {
+    sliverPermInESplit = perm;
+    sliverUpperLengthSqBound = bound;
+    if ( sliverUpperLengthSqBound > 0. && 
+         sliverUpperLengthSqBound < upperLengthSqBound ) {
+      MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+                                    "Incoherent parameters: upper length square bound for edge splits creating slivers (%f) is lower than the global upper legnth square bound (%f)",
+                                    sliverUpperLengthSqBound,upperLengthSqBound);
+    }
+  }
+
+  // -------------------------------------------------------------------
+
+  void MeshParametersManager::setSliverPermissionInECollapse(bool perm, 
+                                                             double bound)
+  {
+    sliverPermInECollapse = perm;
+    sliverLowerLengthSqBound = bound;
+    if ( sliverLowerLengthSqBound > 0. && 
+         sliverLowerLengthSqBound > lowerLengthSqBound ) {
+      MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+                                    "Incoherent parameters: lower length square bound for edge collapses creating slivers (%f) is bigger than the global lower legnth square bound (%f)",
+                                    sliverLowerLengthSqBound,lowerLengthSqBound);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+
+  void MeshParametersManager::diagnostics() const
+  {
+    cout << "   *** Parameters for the mesh adaptation ***   \n";
+
+    cout << "\n";
+
+    cout << "- Bounds of the edge length squared: \n";
+    cout << "\t Lower: " << lowerLengthSqBound << "\n";
+    cout << "\t Upper: " << upperLengthSqBound << "\n";
+
+    cout << "\n";
+
+    cout << "- Quality bound for the sliver triangles: " 
+         << sliverTriQualityBound << "\n";
+
+    cout << "- Quality bound for the sliver tetrahedra: " 
+         << sliverTetQualityBound << "\n";
+
+    cout << "\n";
+
+    cout << "Edge splits can create slivers: ";
+    if (sliverPermInESplit) {
+      cout << "yes: ";
+      if ( sliverUpperLengthSqBound < 0) cout << "for any edge.";
+      else cout << "if the edge is longer than "<< sliverUpperLengthSqBound<<" (square of adimensional length)";
+    }
+    else cout << "no";
+    cout << "\n";
+    cout << "Edge collapses can create slivers: ";
+    if (sliverPermInECollapse) {
+      cout << "yes: ";
+      if ( sliverLowerLengthSqBound < 0) cout << "for any edge.";
+      else cout << "the edge is shorter than "<< sliverLowerLengthSqBound<<" (square of adimensional length)";
+    }
+    else cout << "no";
+    cout << "\n";
+
+    cout << "\n";
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/MeshParametersManager.h b/Adapt/MeshParametersManager.h
new file mode 100644
index 0000000..adb0e84
--- /dev/null
+++ b/Adapt/MeshParametersManager.h
@@ -0,0 +1,109 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MESHPARAMETERSMANAGER
+#define _H_MESHPARAMETERSMANAGER
+
+#include "MeshDataBaseInterface.h"
+#include "MAdOperatorBase.h"
+#include "MAdSingleton.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class MeshParametersManager {
+    
+  public:
+  
+    MeshParametersManager();
+    ~MeshParametersManager() {};
+
+    void initialize();
+    void finalize();
+
+    // ------------------------------------------
+  public:
+  
+    void setLowerLengthSqBound(double); 
+    void setUpperLengthSqBound(double); 
+    void setSliverTriBound(double);
+    void setSliverTetBound(double);
+  
+    double getLowerLengthSqBound() const {return lowerLengthSqBound;}
+    double getUpperLengthSqBound() const {return upperLengthSqBound;}
+    double getSliverBound(int dim) const;
+    double getSliverBound(const pMesh) const;
+    double getSliverTriBound() const {return sliverTriQualityBound;}
+    double getSliverTetBound() const {return sliverTetQualityBound;}
+
+  private:
+
+    double lowerLengthSqBound, upperLengthSqBound;
+    double sliverTetQualityBound;
+    double sliverTriQualityBound;
+
+    // ------------------------------------------
+  public:
+
+    void setSliverPermissionInESplit    (bool, double bound=-1.);
+    void setSliverPermissionInECollapse (bool, double bound=-1.);
+
+    bool getSliverPermissionInESplit    () const {return sliverPermInESplit;}
+    bool getSliverPermissionInECollapse () const {return sliverPermInECollapse;}
+
+    double getSliverLowerLengthSqBound  () const {return sliverLowerLengthSqBound;}
+    double getSliverUpperLengthSqBound  () const {return sliverUpperLengthSqBound;}
+
+  private:
+
+    bool sliverPermInESplit, sliverPermInECollapse;
+    double sliverLowerLengthSqBound, sliverUpperLengthSqBound;
+
+    // ------------------------------------------
+  public:
+
+    void setNoSwapQuality(double noSwap) {noSwapQuality = noSwap;}
+    void setSwapMinImproveRatio(double ratio) {swapMinImproveRatio = ratio;}
+
+    double getNoSwapQuality() const {return noSwapQuality;}
+    double getSwapMinImproveRatio() const {return swapMinImproveRatio;}
+
+  private:
+
+    double noSwapQuality;
+    double swapMinImproveRatio;
+
+    // ------------------------------------------
+  public:
+    
+    void setBigLength(double len) { bigLength = len; }
+    double getBigLength() { return bigLength; }
+
+  private:
+    
+    double bigLength;
+
+    // ------------------------------------------
+  public:
+
+    void diagnostics() const;
+
+  };
+
+  // -------------------------------------------------------------------
+
+  typedef MAdSingleton<MeshParametersManager> MeshParametersManagerSgl;
+
+}
+
+#endif
diff --git a/Adapt/constraint/Constraint.cc b/Adapt/constraint/Constraint.cc
new file mode 100644
index 0000000..5071c82
--- /dev/null
+++ b/Adapt/constraint/Constraint.cc
@@ -0,0 +1,433 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "Constraint.h"
+#include "ModelConstraintManager.h"
+
+#include "MeshDataBaseParallelInterface.h"
+
+static unsigned int CONSTRAIN_MARK_ID = 1687354269;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  void EN_constrain(pEntity pE) 
+  {
+    pE->attachInt(CONSTRAIN_MARK_ID,1);
+  }
+
+  // -------------------------------------------------------------------
+  void EN_unconstrain(pEntity pE)
+  {
+    pE->attachInt(CONSTRAIN_MARK_ID,0);
+  }
+ 
+  // -------------------------------------------------------------------
+  bool EN_constrained(pEntity pE)
+  {
+    if ( ModelConstraintManagerSgl::instance().constrained(EN_whatIn(pE)) ) {
+      return true;
+    }
+
+    return (bool) pE->getAttachedInt(CONSTRAIN_MARK_ID);
+  }
+
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  void DeleteConstraint(pMesh mesh) {
+    VIter vit = M_vertexIter(mesh);
+    pVertex pv;  
+    while ((pv = VIter_next(vit))) {
+      EN_unconstrain((pEntity) pv);  
+    }
+    VIter_delete(vit);	
+  
+    EIter eit = M_edgeIter(mesh);
+    pEdge ped;  
+    while ((ped = EIter_next(eit))) {
+      EN_unconstrain((pEntity) ped);  
+    }
+    EIter_delete(eit);	
+
+    FIter fit = M_faceIter(mesh);
+    pFace pface;  
+    while ((pface = FIter_next(fit))) {
+      EN_unconstrain((pEntity) pface);  
+    }
+    FIter_delete(fit);	
+
+    RIter rit = M_regionIter(mesh);
+    pRegion pregion;  
+    while ((pregion = RIter_next(rit))) {
+      EN_unconstrain((pEntity) pregion);  
+    }
+    RIter_delete(rit);	
+  }
+
+  // -------------------------------------------------------------------
+#ifdef PARALLEL
+  void DeleteParallelConstraint(pMesh mesh) {
+
+    VIter vit = M_vertexIter(mesh);
+    while ( pVertex pv = VIter_next(vit) ) {
+      if ( V_isInterface(pv) ) EN_unconstrain((pEntity) pv);
+    }
+    VIter_delete(vit);
+
+    EIter eit = M_edgeIter(mesh);
+    while ( pEdge pe = EIter_next(eit) ) {
+      // if ( E_isInterface(mesh,pe) ) {
+      if ( E_isInterface(pe) ) {
+        EN_unconstrain((pEntity) pe);
+      }
+    }
+    EIter_delete(eit);
+    int dim = (mesh->tets.empty()) ? 2 : 3;
+  
+    if ( dim == 3 ) {
+      FIter fit = M_faceIter(mesh);
+      while ( pFace pf = FIter_next(fit) ) {
+        // if ( F_isInterface(mesh,pf) ) {
+        if ( F_isInterface(pf) ) {
+          EN_unconstrain((pEntity) pf);
+        }
+      }
+      FIter_delete(fit);
+    }
+  }
+  void UpdateParallelConstraint(pMesh mesh) {
+
+    DeleteParallelConstraint(mesh);
+    //   DeleteConstraint(mesh);
+    int dim = (mesh->tets.empty()) ? 2 : 3;
+  
+    if ( dim == 3 ) {
+      FIter fit = M_faceIter(mesh);
+      while ( pFace pf = FIter_next(fit) ) {
+        // if ( F_isInterface(mesh,pf) ) {
+        if ( F_isInterface(pf) ) {
+          EN_constrain((pEntity) pf);
+        }
+      }
+      FIter_delete(fit);
+    }
+    EIter eit = M_edgeIter(mesh);
+    while ( pEdge pe = EIter_next(eit) ) {
+      // if ( E_isInterface(mesh,pe) ) {
+      if ( E_isInterface(pe) ) {
+        EN_constrain((pEntity) pe);
+      }
+    }
+    EIter_delete(eit);
+    VIter vit = M_vertexIter(mesh);
+    while ( pVertex pv = VIter_next(vit) ) {
+      if ( V_isInterface(pv) ) EN_constrain((pEntity) pv);
+    }
+    VIter_delete(vit);
+  }
+#endif
+
+  // -------------------------------------------------------------------
+  void UpdatePeriodicConstraint2d(pMesh mesh)
+  {
+    pMeshDataId tagPeriod  = MD_lookupMeshDataId("PeriodicPoint");
+
+    FIter fit = M_faceIter(mesh);
+    pFace pface;  
+    while ((pface = FIter_next(fit))) {
+      int ncount = 0;
+      pEdge pe1 = F_edge(pface,0);
+      pVertex p1 = E_vertex(pe1,0);
+      pVertex p2 = E_vertex(pe1,1);
+      void *temp_ptr1,*temp_ptr2;
+      int isPeriodic1  = EN_getDataPtr((pEntity) p1 , tagPeriod, &temp_ptr1);
+      int isPeriodic2  = EN_getDataPtr((pEntity) p2 , tagPeriod, &temp_ptr2);
+      if(isPeriodic1) EN_constrain((pEntity) p1); 
+      if(isPeriodic2) EN_constrain((pEntity) p2);
+      if(isPeriodic1 && isPeriodic2){ 
+        /*est-ce que l'arete image de celle-ci existe ?*/
+        /*ie est-ce l'arete Img(P1)-Img(P2) existe et est differente de ped ?*/
+        const std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr1;
+        const std::vector<std::pair<std::vector<int> , pVertex> > *recup2 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr2;
+        int nump = EN_id(p2); 
+        unsigned int k=0;
+        int exist=-1;
+        for(k=0; k<(*recup).size() ; k++) { 
+          /*edge p1p2 = p1 Img(p1) ?*/
+          pVertex n1 = (*recup)[k].second;
+          if ( nump == EN_id(n1) ) {
+            continue;         		
+          } 
+          /*edge = Img(p1)Img(p2) existe ?*/  
+          unsigned int kk=0;
+          std::vector<int> transfo1 = (*recup)[k].first;
+          for(kk=0; kk<(*recup2).size() ; kk++) { 
+            std::vector<int> transfo2 = (*recup2)[kk].first;
+            assert(transfo1.size()==transfo2.size());
+            unsigned int kt = 0;
+            for(kt = 0 ; kt < transfo1.size(); kt++) {
+              if(transfo1[kt] != transfo2[kt]) break;
+            }
+            if(kt!=transfo1.size()) continue;
+            pVertex n2 = (*recup2)[kk].second;   
+            if ( !E_exist(n1,n2) && !E_exist(n2,n1) ) { 
+              exist = 0;         		
+            } else {
+              exist = 1;
+            } 
+          }
+        }
+        if(exist==1) {      
+          ncount++;
+          EN_constrain((pEntity) pe1);
+        }
+      }
+      pEdge pe2 = F_edge(pface,1);
+      p1 = E_vertex(pe2,0);
+      p2 = E_vertex(pe2,1);
+      isPeriodic1  = EN_getDataPtr((pEntity) p1 , tagPeriod, &temp_ptr1);
+      isPeriodic2  = EN_getDataPtr((pEntity) p2 , tagPeriod, &temp_ptr2);
+      if(isPeriodic1) EN_constrain((pEntity) p1); 
+      if(isPeriodic2) EN_constrain((pEntity) p2);
+      if(isPeriodic1 && isPeriodic2){ 
+        /*est-ce que l'arete image de celle-ci existe ?*/
+        /*ie est-ce l'arete Img(P1)-Img(P2) existe et est differente de ped ?*/
+        const std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr1;
+        const std::vector<std::pair<std::vector<int> , pVertex> > *recup2 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr2;
+        int nump = EN_id(p2); 
+        unsigned int k=0;
+        int exist=-1;
+        for(k=0; k<(*recup).size() ; k++) {
+          /*edge p1p2 = p1 Img(p1) ?*/
+          pVertex n1 = (*recup)[k].second;
+          if ( nump == EN_id(n1) ){
+            continue;         		
+          } 
+          /*edge = Img(p1)Img(p2) existe ?*/  
+          unsigned int kk=0;
+          std::vector<int> transfo1 = (*recup)[k].first;
+          for(kk=0; kk<(*recup2).size() ; kk++) { 
+            std::vector<int> transfo2 = (*recup2)[kk].first;
+            assert(transfo1.size()==transfo2.size());
+            unsigned int kt = 0;
+            for(kt = 0 ; kt < transfo1.size(); kt++) {
+              if(transfo1[kt] != transfo2[kt]) break;
+            }
+            if(kt!=transfo1.size()) continue;
+            pVertex n2 = (*recup2)[kk].second;   
+            if ( !E_exist(n1,n2) && !E_exist(n2,n1) ) { 
+              exist = 0;         		
+            } else {
+              exist = 1;
+            } 
+          }
+        }
+        if(exist==1) {      
+          ncount++;
+          EN_constrain((pEntity) pe2); 	
+        }
+      }	
+      pEdge pe3 = F_edge(pface,2);
+      p1 = E_vertex(pe3,0);
+      p2 = E_vertex(pe3,1);
+      isPeriodic1  = EN_getDataPtr((pEntity) p1 , tagPeriod, &temp_ptr1);
+      isPeriodic2  = EN_getDataPtr((pEntity) p2 , tagPeriod, &temp_ptr2);
+      if(isPeriodic1) EN_constrain((pEntity) p1); 
+      if(isPeriodic2) EN_constrain((pEntity) p2);
+      if(isPeriodic1 && isPeriodic2){ 
+        /*est-ce que l'arete image de celle-ci existe ?*/
+        /*ie est-ce l'arete Img(P1)-Img(P2) existe et est differente de ped ?*/
+        const std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr1;
+        const std::vector<std::pair<std::vector<int> , pVertex> > *recup2 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr2;
+        int nump = EN_id(p2); 
+        unsigned int k=0,exist=0;
+        for(k=0; k<(*recup).size() ; k++) {
+          /*edge p1p2 = p1 Img(p1) ?*/
+          pVertex n1 = (*recup)[k].second;
+          if ( nump == EN_id(n1) ){
+            continue;         		
+          } 
+          /*edge = Img(p1)Img(p2) existe ?*/  
+          unsigned int kk=0;
+          std::vector<int> transfo1 = (*recup)[k].first;
+          for(kk=0; kk<(*recup2).size() ; kk++) { 
+            std::vector<int> transfo2 = (*recup2)[kk].first;
+            assert(transfo1.size()==transfo2.size());
+            unsigned int kt = 0;
+            for(kt = 0 ; kt < transfo1.size(); kt++) {
+              if(transfo1[kt] != transfo2[kt]) break;
+            }
+            if(kt!=transfo1.size()) continue;
+            pVertex n2 = (*recup2)[kk].second;   
+            if ( E_exist(n1,n2) || E_exist(n2,n1) ) { 
+              exist = 1;
+            } 
+          }
+        }
+        if(exist==1) {      
+          ncount++;
+          EN_constrain((pEntity) pe3);
+        }
+      }
+      if(ncount==3)  EN_constrain((pEntity) pface);
+  
+    }
+    FIter_delete(fit);
+  }
+
+  // -------------------------------------------------------------------
+  void UpdatePeriodicConstraint3d(pMesh mesh)
+  {
+    pMeshDataId tagPeriod  = MD_lookupMeshDataId("PeriodicPoint");
+
+    RIter rit = M_regionIter(mesh);
+    pRegion pr;  
+    while ((pr = RIter_next(rit))) {
+      int ncountr = 0;
+      pFace pface[4];
+      for(int i=0 ; i<4 ; i++) { 
+        int nbdry = 1;
+        pface[i] = R_face(pr,i);  
+        /*Img(pface[i]) exist ?*/
+        pVertex nod[3];
+        int isPeriodic[3];
+        void *tmp[3];
+        unsigned int j=0;
+        for(j=0 ;  j<3 ; j++) {
+          nod[j] = F_vertex(pface[i],j);  
+          isPeriodic[j]  = EN_getDataPtr((pEntity) nod[j] , tagPeriod, &tmp[j]);
+          if(!isPeriodic[j]) {
+            nbdry=0;
+            continue;
+          }
+          EN_constrain((pEntity) nod[j]); 
+        }             
+        if(nbdry) {
+          /*find Img(nod[j])*/ 
+          const std::vector<std::pair<std::vector<int> , pVertex> > *recup  = (std::vector<std::pair<std::vector<int> , pVertex> > *) tmp[0];
+          const std::vector<std::pair<std::vector<int> , pVertex> > *recup2 = (std::vector<std::pair<std::vector<int> , pVertex> > *) tmp[1];
+          const std::vector<std::pair<std::vector<int> , pVertex> > *recup3 = (std::vector<std::pair<std::vector<int> , pVertex> > *) tmp[2];
+          unsigned int k;
+          int exist=-1,nfound=0;
+          for(k=0; k<(*recup).size() ; k++) {
+            pVertex n1 = (*recup)[k].second;
+            /*ATTENTION CA PEUT ARRIVER DANS LES CAS 3_PERIODIQUES!!!if ( EN_id((pEntity) nod[1]) == EN_id((pEntity) n1) || EN_id((pEntity) nod[2]) == EN_id((pEntity) n1) ){  
+              continue;         		
+              } */
+            unsigned int kk=0;
+            std::vector<int> transfo1 = (*recup)[k].first;
+            for(kk=0; kk<(*recup2).size() ; kk++) { 
+              std::vector<int> transfo2 = (*recup2)[kk].first;
+              assert(transfo1.size()==transfo2.size());
+              unsigned int kt = 0;
+              for(kt = 0 ; kt < transfo1.size(); kt++) {
+                if(transfo1[kt] != transfo2[kt]) break;
+              }
+              if(kt!=transfo1.size()) continue; 
+              if(!nfound) nfound = 1;
+              pVertex n2 = (*recup2)[kk].second;   
+              unsigned int kkk=0;
+              for(kkk=0; kkk<(*recup3).size() ; kkk++) { 
+                std::vector<int> transfo2 = (*recup3)[kkk].first;
+                unsigned int kt = 0;
+                for(kt = 0 ; kt < transfo1.size(); kt++) {
+                  if(transfo1[kt] != transfo2[kt]) break;
+                }
+                if(kt!=transfo1.size()) continue;
+                pVertex n3 = (*recup3)[kkk].second;   
+                nfound = 2;
+                if ( F_exist(n1,n2,n3,0) || F_exist(n1,n3,n2,0) ||
+                     F_exist(n2,n1,n3,0) || F_exist(n2,n3,n1,0) || 
+                     F_exist(n3,n2,n1,0) || F_exist(n3,n1,n2,0) ) { 
+                  exist = 1;
+                } 
+              }/*end kkk*/    
+            }/*end kk*/
+          }/*end k*/ 
+          if(!nfound) nbdry=0;//printf("on n'a pas trouve la face\n"); 
+          if(nfound==1) nbdry = 1;//printf("3 ou 2 ? %d\n",nfound);
+          if(nfound==2) nbdry = 0;//printf("3 ou 2 ? %d\n",nfound);
+	
+          if(exist==1) {      
+            ncountr++;
+            EN_constrain((pEntity) pface[i]);
+            for(int j=0 ;  j<3 ; j++) {
+              EN_constrain((pEntity) F_edge(pface[i],j));  
+              /* pVertex p1 = F_edge(pface[i],j)->p1;
+                 pVertex p2 = F_edge(pface[i],j)->p2;
+                 double len = (p1->X-p2->X)*(p1->X-p2->X) + (p1->Y-p2->Y)*(p1->Y-p2->Y) +(p1->Z-p2->Z)*(p1->Z-p2->Z);
+                 printf("edge %d %d : %e\n",p1->iD,p2->iD,len); */
+            }
+            continue;
+          } else{
+            /* if(F_numRegions(pface[i]) != 2){ printf("pbs constraint %d %d %d\n",EN_id((pEntity) nod[0])
+               ,EN_id((pEntity) nod[1]),EN_id((pEntity) nod[2]));exit(0);  }   */
+          }
+        }/*end nbdry*/                    
+        /*face not constraint*/
+        int ncount = 0;      
+        for(int j=0 ; j<3 ; j++) {
+          pEdge ped = F_edge(pface[i],j);
+          pVertex p1 = E_vertex(ped,0);
+          pVertex p2 = E_vertex(ped,1);
+          void *temp_ptr1,*temp_ptr2;
+          int isPeriodic1  = EN_getDataPtr((pEntity) p1 , tagPeriod, &temp_ptr1);
+          int isPeriodic2  = EN_getDataPtr((pEntity) p2 , tagPeriod, &temp_ptr2);
+          if((isPeriodic1 && isPeriodic2)) {
+            const std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr1;
+            const std::vector<std::pair<std::vector<int> , pVertex> > *recup2 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr2;
+            //int nump = EN_id(p2);
+            int nfound = 0; 
+            unsigned int k=0;
+            int exist=-1;
+            for(k=0; k<(*recup).size() ; k++) {
+              /*edge p1p2 = p1 Img(p1) ?*/
+              pVertex n1 = (*recup)[k].second;  
+              /*if ( nump == EN_id(n1) ){
+                continue;         		
+                }*/ 
+              /*edge = Img(p1)Img(p2) existe ?*/  
+              unsigned int kk=0;
+              std::vector<int> transfo1 = (*recup)[k].first;
+              for(kk=0; kk<(*recup2).size() ; kk++) { 
+                std::vector<int> transfo2 = (*recup2)[kk].first;
+                assert(transfo1.size()==transfo2.size());
+                unsigned int kt = 0;
+                for(kt = 0 ; kt < transfo1.size(); kt++) {
+                  if(transfo1[kt] != transfo2[kt]) break;
+                }
+                if(kt!=transfo1.size()) continue;
+                nfound = 1;
+                pVertex n2 = (*recup2)[kk].second;   
+                if ( E_exist(n1,n2) || E_exist(n2,n1) ) { 
+                  exist = 1;
+                } 
+              }
+            }/*end k*/
+		   
+            if(exist==1) {
+              ncount++; 
+              EN_constrain((pEntity) ped);
+            }  
+          }
+        }
+      }
+      if(ncountr==4) EN_constrain((pEntity) pr);
+    }
+    RIter_delete(rit); 
+  
+  }
+
+}
+
+//#endif
diff --git a/Adapt/constraint/Constraint.h b/Adapt/constraint/Constraint.h
new file mode 100644
index 0000000..deef2a6
--- /dev/null
+++ b/Adapt/constraint/Constraint.h
@@ -0,0 +1,49 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_CONSTRAINT
+#define _H_CONSTRAINT
+
+#include "MeshDataBaseInterface.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+
+  // --- entity level constraining ---
+
+  void EN_constrain   (pEntity);
+  void EN_unconstrain (pEntity);
+  bool EN_constrained (pEntity);
+
+  // --- mesh level constraining ---
+
+#ifdef PARALLEL
+  // Constrain parallel interface elements 
+  void UpdateParallelConstraint(pMesh mesh);
+  // unConstrain parallel interface elements
+  void DeleteParallelConstraint(pMesh mesh);
+#endif
+
+  // Constrain periodic interface elements
+  void UpdatePeriodicConstraint3d(pMesh mesh);
+  void UpdatePeriodicConstraint2d(pMesh mesh);
+
+  // Remove all constraints on elements (periodic, parallel and misc.)
+  void DeleteConstraint(pMesh mesh);
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/constraint/ModelConstraintManager.cc b/Adapt/constraint/ModelConstraintManager.cc
new file mode 100644
index 0000000..6571169
--- /dev/null
+++ b/Adapt/constraint/ModelConstraintManager.cc
@@ -0,0 +1,86 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "ModelConstraintManager.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  void ModelConstraintManager::initialize(pGModel _model)
+  {
+    model = _model;
+  }
+
+  // -------------------------------------------------------------------
+  void ModelConstraintManager::finalize()
+  {
+  }
+
+  // -------------------------------------------------------------------
+  void ModelConstraintManager::setModel(pGModel _model)
+  {
+    model = _model;
+  }
+
+  // -------------------------------------------------------------------
+  void ModelConstraintManager::clear()
+  {
+    constrEntities.clear();
+  }
+
+  // -------------------------------------------------------------------
+  void ModelConstraintManager::constrain(int type, int id)
+  {
+    pGEntity pGE = GM_entityByTag(model, type, id);
+    constrain(pGE);
+  }
+
+  // -------------------------------------------------------------------
+  void ModelConstraintManager::constrain(pGEntity pGE)
+  {
+    // constrain entity
+    constrEntities.insert(pGE);
+  
+#ifdef _HAVE_GMSH_
+    // constrain lower geometrical levels
+    std::list<pGEntity> subGE = GEN_closure(pGE);
+    std::list<pGEntity>::const_iterator subIter = subGE.begin();
+    for (; subIter != subGE.end(); subIter++) constrain(*subIter);
+#endif
+  }
+
+  // -------------------------------------------------------------------
+  void ModelConstraintManager::unconstrain(int type, int id)
+  {
+    pGEntity pGE = GM_entityByTag(model, type, id);
+    unconstrain(pGE);
+  }
+
+  // -------------------------------------------------------------------
+  void ModelConstraintManager::unconstrain(pGEntity pGE)
+  {
+    std::set<pGEntity>::iterator eIter = constrEntities.find(pGE);
+    if ( eIter != constrEntities.end() ) constrEntities.erase(eIter);
+  }
+
+  // -------------------------------------------------------------------
+  bool ModelConstraintManager::constrained(pGEntity pGE)
+  {
+    //GCTODO: check upper-level geometric entities: need model with connectivity
+
+    if ( constrEntities.find(pGE) != constrEntities.end() ) return true;
+    return false;
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/constraint/ModelConstraintManager.h b/Adapt/constraint/ModelConstraintManager.h
new file mode 100644
index 0000000..1348d3f
--- /dev/null
+++ b/Adapt/constraint/ModelConstraintManager.h
@@ -0,0 +1,61 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MODELCONSTRAINTMANAGER
+#define _H_MODELCONSTRAINTMANAGER
+
+#include "ModelInterface.h"
+#include <set>
+
+#include "MAdSingleton.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+
+  class ModelConstraintManager {
+
+  public:
+  
+    ModelConstraintManager()  {};
+    ~ModelConstraintManager() {};
+
+    void initialize(pGModel);
+    void finalize();
+    void setModel(pGModel);
+
+  public:
+
+    void clear();
+
+    void constrain  (int type, int id);
+    void constrain  (pGEntity);
+
+    void unconstrain(int type, int id);
+    void unconstrain(pGEntity);
+
+    bool constrained(pGEntity);
+
+  private:
+
+    pGModel model;
+    std::set<pGEntity> constrEntities;
+  };
+
+  // -------------------------------------------------------------------
+
+  typedef MAdSingleton<ModelConstraintManager> ModelConstraintManagerSgl;
+
+}
+
+#endif
diff --git a/Adapt/operator/DESCOp.cc b/Adapt/operator/DESCOp.cc
new file mode 100644
index 0000000..8ee3a71
--- /dev/null
+++ b/Adapt/operator/DESCOp.cc
@@ -0,0 +1,204 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Olivier Pierard, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "DESCOp.h"
+#include "OperatorTools.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  void DESCOp::setDESC(pRegion r, pEdge e0, pEdge e1)
+  {
+    region = r;
+    splitE[0] = e0;
+    splitE[1] = e1;
+    E_center(splitE[0],xyz);  // Collapse on mid-edge e0 only 
+  }
+
+  // -------------------------------------------------------------------
+  bool DESCOp::checkConstraints() const
+  {
+    if ( EN_constrained((pEntity)splitE[0]) || 
+         EN_constrained((pEntity)splitE[1]) ) {
+      return false;
+    }
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool DESCOp::checkGeometry()
+  {
+    if( E_whatInType(splitE[1]) != 3 ) return false;
+  
+    for( int i=0; i<2; i++ ) {
+
+      int nbV = 0;
+      pVertex verts[2];
+      for(int iF=0; iF < R_numFaces(region); iF++) {
+        pFace face = R_face(region,iF);
+        if( F_inClosure(face,(pEntity)splitE[i]) ) {
+          pRegion oppR = F_region(face,0);
+          if( oppR == region ) oppR = F_region(face,1);
+          if ( oppR ) {
+            verts[nbV] = R_fcOpVt(oppR,face);
+            nbV++;
+          }
+        }
+      }
+
+      pEdge edge = splitE[(i+1)%2];
+      for( int j=0; j<E_numFaces(edge); j++ ) {
+        pVertex oppV = F_edOpVt(E_face(edge,j),edge);
+        for( int k=0; k<nbV; k++ ) {
+          if( oppV == verts[k] ) return false;
+        }
+      }
+    }
+
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool DESCOp::evaluateShapes()
+  {
+    double worstShape = mqm.getElementEvaluator()->bestShapeEver();
+
+    pMSize xyzSize = sizeField->getSizeOnEntity((pEntity)region,xyz);
+
+    for(int iE=0; iE<2; iE++) {
+    
+      pPList eRegs = E_regions(splitE[iE]);
+
+      void * temp = NULL;
+      while( pRegion pR = (pRegion)PList_next(eRegs,&temp) ) {
+    	
+        if( pR == region ) continue;
+	
+        pPList rVerts = R_vertices(pR);
+
+        // evaluate the two regions resulting from the split
+        for( int iER=0; iER<2; iER++ ) {
+
+          pVertex eV = E_vertex(splitE[iE],iER);
+
+          pMSize rSizes[4];  
+          for (int idel = 0; idel<4; idel++) rSizes[idel] = NULL;
+          double rCoords[4][3];
+
+          pVertex pV = NULL;
+          void * iter = NULL;
+          for( int iERV=0; ( pV=(pVertex)PList_next(rVerts,&iter) ); iERV++ ) {
+            if( pV == eV ) {
+              rSizes[iERV] = xyzSize;
+              rCoords[iERV][0] = xyz[0]; 
+              rCoords[iERV][1] = xyz[1]; 
+              rCoords[iERV][2] = xyz[2];
+            }
+            else {
+              rSizes[iERV] = sizeField->findSize(pV);
+              V_coord(pV,rCoords[iERV]);
+            }
+          }
+        
+          double rShape;
+          if( !mqm.getElementEvaluator()->XYZ_R_shape(rCoords,rSizes,&rShape) ) {
+            PList_delete (rVerts);
+            if( xyzSize ) delete xyzSize;
+            PList_delete(eRegs);
+            return false;
+          }
+	  
+          if( worstShape > rShape ) worstShape = rShape;
+        }
+
+        PList_delete(rVerts);
+      }
+
+      PList_delete(eRegs);
+    }
+  
+    if( xyzSize ) delete xyzSize;
+
+    results->setWorstShape(worstShape); 
+
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  void DESCOp::evaluateLengths() const
+  {
+    // get size at new point (interpolation)
+    pMSize xyzSize = sizeField->getSizeOnEntity((pEntity)splitE[0],xyz);
+
+    double lSqMin = MAdBIG, lSqMax = 0.;
+
+    for( int iE=0; iE<2; iE++ ) {
+      for( int i=0; i<E_numFaces(splitE[iE]); i++ ) {
+
+        pVertex oppV = F_edOpVt( E_face(splitE[iE],i), splitE[iE] );
+        const pMSize oppSize = sizeField->findSize(oppV);
+      
+        double xyzOpp[3];
+        V_coord(oppV,xyzOpp);
+        double lSq = sizeField->SF_XYZ_lengthSq(xyz, xyzOpp,
+                                                xyzSize, oppSize);
+        if( lSq > lSqMax ) lSqMax = lSq;
+        if( lSq < lSqMin ) lSqMin = lSq;
+      }
+    }
+
+    results->setMaxLenSq(lSqMax);
+    results->setMinLenSq(lSqMin);
+  
+    if( xyzSize ) delete xyzSize;
+  }
+
+
+  // -------------------------------------------------------------------
+  void DESCOp::getCavity(pPList * cavity) const
+  {
+    *cavity = PList_new();
+    PList_append(*cavity,region);
+
+    for(int i=0; i<2; i++) {
+      pPList eRegs = E_regions(splitE[i]);
+      void * iter = NULL;
+      for(pRegion pR; ( pR=(pRegion)PList_next(eRegs,&iter) ); ) {
+        if( pR != region ) {
+          PList_append(*cavity,pR);
+        }
+      }
+      PList_delete(eRegs);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void DESCOp::apply()
+  {
+    pVertex newV[2];  
+    for(int iE=0; iE<2; iE++) {
+      newV[iE] = E_split(mesh, splitE[iE], xyz);
+    }
+
+    pVertex vTgt = newV[0];
+  
+    pEdge edgeDel = E_exist(vTgt,newV[1]);
+    assert ( edgeDel );
+  
+    E_collapse(mesh, edgeDel, newV[1], vTgt);
+ 
+    HistorySgl::instance().add((int)type(),OPERATOR_APPLY,1);
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/operator/DESCOp.h b/Adapt/operator/DESCOp.h
new file mode 100644
index 0000000..c497537
--- /dev/null
+++ b/Adapt/operator/DESCOp.h
@@ -0,0 +1,82 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Olivier Pierard, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_DESCOP
+#define _H_DESCOP
+
+#include "MAdOperatorBase.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class DESCOp: public MAdOperatorBase
+  {
+  public:
+  
+    DESCOp(pMesh, DiscreteSF *);
+    DESCOp(const DESCOp &);
+    ~DESCOp() {}
+
+    operationType type() const { return MAd_DESPLTCLPS; }
+
+    void setDESC(pRegion, pEdge, pEdge);
+
+    void getCavity(pPList *) const;
+
+    void apply();
+
+  private:
+
+    bool checkConstraints() const;
+    bool checkGeometry();
+    bool evaluateShapes();
+    void evaluateLengths() const;
+
+  private:
+
+    pRegion region;
+    pEdge splitE[2];
+    double xyz[3];
+  };
+
+
+  // -------------------------------------------------------------------
+  inline DESCOp::DESCOp(const DESCOp &_desc):
+    MAdOperatorBase(_desc)
+  {
+    region = _desc.region;
+    splitE[0] = _desc.splitE[0];
+    splitE[1] = _desc.splitE[1];
+  
+    xyz[0] = _desc.xyz[0];
+    xyz[1] = _desc.xyz[1];
+    xyz[2] = _desc.xyz[2];
+  }
+
+  // -------------------------------------------------------------------
+  inline DESCOp::DESCOp(pMesh _m, DiscreteSF * _sf):
+    MAdOperatorBase(_m,_sf), region(NULL)
+  {
+    splitE[0] = NULL;
+    splitE[1] = NULL;
+
+    xyz[0] = 0.0;
+    xyz[1] = 0.0;
+    xyz[2] = 0.0;
+  }
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/operator/EdgeCollapseOp.cc b/Adapt/operator/EdgeCollapseOp.cc
new file mode 100644
index 0000000..7268214
--- /dev/null
+++ b/Adapt/operator/EdgeCollapseOp.cc
@@ -0,0 +1,399 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "EdgeCollapseOp.h"
+#include "OperatorTools.h"
+#include <map>
+
+using std::map;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  bool edgeCollapseOp::checkConstraints() const
+  {
+    if ( EN_constrained((pEntity)edgeDel) ) return false;
+    if ( EN_constrained((pEntity)vDel   ) ) return false;
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool edgeCollapseOp::checkGeometry()
+  {
+    int typeD = V_whatInType(vDel);
+    if ( typeD == 0 ) return false;
+
+    if ( constrainBoundary ) {
+      switch( typeD ) {
+      case 3: break;
+      case 2:
+        {
+          bool ok = true;
+          pPList eRgns = E_regions(edgeDel);
+          if( PList_size(eRgns) != 0 )  ok = false;
+          PList_delete(eRgns);
+          if (!ok) return false;
+          break;
+        }
+      case 1: return false;
+      case 0: return false;
+      }
+    }
+    else {
+      // check in edgeDel
+      if ( V_whatIn(vDel) != E_whatIn(edgeDel) ) return false;
+      
+      if ( V_whatInType(vDel) <= 2 )
+        {
+          // check in every tet around edgeDel (= to be collapsed):
+          //   - no dimension reduction surface on surface
+          pEdge oppE;
+          pFace newSurfaceFace;
+          pPList vDelFaces = V_faces(vDel);
+          void * temp = NULL;
+          pFace pf;
+          while ( ( pf = (pFace)PList_next(vDelFaces,&temp) ) ) {
+            if ( F_inClosure(pf,edgeDel) ) continue;
+            if ( F_whatInType(pf) == 2 ) {
+              oppE           = F_vtOpEd(pf,vDel);
+              newSurfaceFace = F_exist(oppE,vTgt);
+              if ( newSurfaceFace && F_whatInType(newSurfaceFace) == 2 ) {
+                PList_delete(vDelFaces);
+                return false;
+              }
+            }
+          }
+          PList_delete(vDelFaces);
+      
+          
+          // check in every face around edge del (= to be collapsed):
+          //   - the face exists (that's why we loop over edges, not faces)
+          //   - no new contact between surface and line
+          //   - no new contact between surface and surface
+          //   - no dimension reduction line on line
+          //
+          //          vTgt 
+          //
+          //           |  \
+          //           |   \
+          //           |    \
+          //           |     \  oppE
+          //  edgeDel  |      \
+          //           |  pf   \
+          //           |        \
+          //           |         \
+          //
+          //          vDel ----- oppV
+          //
+          //                 pe
+
+          pVertex oppV;
+          pEdge pe;
+          pPList vDelEdges = V_edges(vDel);
+          temp = NULL;
+          while ( ( pe = (pEdge)PList_next(vDelEdges,&temp) ) ) {
+            if ( pe == edgeDel ) continue;
+            int d1 = E_whatInType(pe);
+            if ( d1 <= 2 ) {
+              oppV = E_otherVertex(pe,vDel);
+              oppE = E_exist(oppV,vTgt);
+              if ( oppE ) {
+                int d2 = E_whatInType(oppE);
+                if ( d2 <= 2 ) {
+                  pf = F_exist(oppE,vDel);
+
+                  // check if the face exists
+                  if ( !pf ) {
+                    PList_delete(vDelEdges); return false;
+                  }
+
+                  // check for line on line dimension reduction
+                  if ( d1 == 1 && d2 == 1 ) {
+                    PList_delete(vDelEdges); return false;
+                  }
+
+                  pGEntity fge = F_whatIn(pf);
+
+                  // check for new contacts between a line and a surface
+                  if ( d1 == 1 && d2 == 2 && fge != E_whatIn(oppE) ) {
+                    PList_delete(vDelEdges); return false;
+                  }
+                  if ( d1 == 2 && d2 == 1 && fge != E_whatIn(pe) ) {
+                    PList_delete(vDelEdges); return false;
+                  }
+
+                  // check for new contacts between 2 surfaces
+                  if ( d1 == 2 && d2 == 2 ) {
+                    if ( fge != E_whatIn(pe) || fge != E_whatIn(oppE) ) {
+                      PList_delete(vDelEdges); return false;
+                    }
+                  }
+                }
+              }
+            }
+          }
+          PList_delete(vDelEdges);
+          
+        }
+    }
+
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool edgeCollapseOp::evaluateShapes2D()
+  {
+    pPList vDelFaces = V_faces(vDel);
+
+    double worstShape = mqm.getElementEvaluator()->bestShapeEver();
+
+    map<pGEntity,double> area_after;
+
+    void * temp1 = 0;
+    while ( pFace face = (pFace)PList_next(vDelFaces,&temp1) ) {
+
+      // Faces surrounding edgeDel will be deleted
+      if (F_inClosure(face,(pEntity)edgeDel)) continue;
+
+      // Gather the coordinates and sizes of the new face
+      double xyz[3][3];
+      pMSize fSizes[3] = {NULL,NULL,NULL};
+
+      pPList fVerts = F_vertices(face,1);
+      void * temp2 = 0;
+      int iV = 0;
+      while ( pVertex vertex = (pVertex)PList_next(fVerts, &temp2) ) {
+        if (vertex == vDel) {
+          fSizes[iV] = sizeField->findSize(vTgt);
+          V_coord(vTgt,xyz[iV]);
+        }
+        else {
+          fSizes[iV] = sizeField->findSize(vertex);
+          V_coord(vertex,xyz[iV]);
+        }
+        iV++;
+      }
+      PList_delete(fVerts);
+
+      // Check if the shape is acceptable and compare it to the worst shape
+      double shape = 0.;
+      double normalBefore[3];
+      F_normal(face,normalBefore);
+      if ( !mqm.getElementEvaluator()->XYZ_F_shape(xyz, fSizes, normalBefore, &shape) ) {
+        PList_delete(vDelFaces); 
+        return false;
+      }
+      else {
+        if ( shape < worstShape ) worstShape = shape;
+      }
+
+      // Compute the area of the new face
+      if( !constrainBoundary && V_whatInType(vDel) < 2 ) {
+
+        pGEntity g = F_whatIn(face);
+        std::map<pGEntity,double>::iterator it = area_after.find( g );
+        if( it != area_after.end() )
+         (*it).second += XYZ_F_area(xyz,normalBefore);
+        else
+         area_after[g] = XYZ_F_area(xyz,normalBefore);
+      }
+    }
+
+    // If the edge is on a boundary, check that the area of
+    // the old and the new cavities are the same for each Geo entities
+    if( !constrainBoundary && V_whatInType(vDel) < 2 ) {
+      map< pGEntity,double>  area_before;
+      map<pGEntity,double>::iterator it, it2;
+
+      void * temp3 = 0;
+      while ( pFace face = (pFace)PList_next(vDelFaces,&temp3) ) {
+        double normal[3];
+        F_normal(face,normal);
+        pGEntity g = F_whatIn(face);
+        it = area_before.find( g );
+        if( it != area_before.end() )
+          (*it).second += F_area(face,normal);
+        else
+          area_before[g] = F_area(face,normal);
+      }
+
+      for( it=area_before.begin(); it!=area_before.end(); ++it  )
+      {
+        double before = (*it).second;
+        double after( 0.0 );
+        it2 = area_after.find( (*it).first );
+        if( it2 != area_after.end() )
+          after = (*it2).second;
+
+        // Check area change
+        double dA = fabs( (before-after) / before );
+        if( dA > dATol ) {
+          PList_delete(vDelFaces);
+          return false;
+        }
+      }
+    }
+    results->setWorstShape(worstShape);
+
+    PList_delete(vDelFaces);
+
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool edgeCollapseOp::evaluateShapes()
+  {
+    pPList vDelRgns = V_regions(vDel);
+
+    // 2D case
+    if( PList_size(vDelRgns)==0 ) {
+      bool flag = evaluateShapes2D();
+      PList_delete(vDelRgns);
+      return flag;
+    }
+
+    // 3D case
+    else {
+
+      double worstShape = mqm.getElementEvaluator()->bestShapeEver();
+      double volAfter = 0.;
+
+      void * temp1 = 0;
+      while ( pRegion region = (pRegion)PList_next(vDelRgns,&temp1) ) {
+      
+        // Regions surrounding edgeDel will be deleted
+        if (R_inClosure(region,(pEntity)edgeDel)) continue;
+
+        // Gather the coordinates and sizes of the new region
+        double xyz[4][3];
+        pMSize rSizes[4] = {NULL,NULL,NULL,NULL};
+
+        pPList rVerts = R_vertices(region);
+        void * temp2 = 0;
+        int iV = 0;
+        while ( pVertex vertex = (pVertex)PList_next(rVerts, &temp2) ) {
+          if (vertex == vDel) {
+            rSizes[iV] = sizeField->findSize(vTgt);
+            V_coord(vTgt,xyz[iV]);
+          }
+          else {
+            rSizes[iV] = sizeField->findSize(vertex);
+            V_coord(vertex,xyz[iV]);
+          }
+          iV++;
+        }
+        PList_delete(rVerts);
+
+        // Check if the shape is acceptable and compare it to the worst shape
+        double shape = 0.;
+        if ( !mqm.getElementEvaluator()->XYZ_R_shape(xyz, rSizes, &shape) ) {
+          PList_delete(vDelRgns); 
+          return false;
+        }
+        else {
+          if ( shape < worstShape ) worstShape = shape;
+        }
+
+        // Compute the volume of the new region
+        if( !constrainBoundary && V_whatInType(vDel)!=3 ) {
+          volAfter += R_XYZ_volume (xyz);
+        }
+      }
+
+      // If the edge is on a boundary, check that the volume of 
+      // the old and the new cavities are the same
+      if( !constrainBoundary && V_whatInType(vDel)!=3 ) {
+
+        double volBefore = 0.;
+      
+        void * temp3 = 0;
+        while ( pRegion region = (pRegion)PList_next(vDelRgns,&temp3) ) {
+          volBefore += R_volume (region);
+        }
+
+        double dV = fabs( (volBefore-volAfter) / volBefore );
+        if( dV > dVTol ) {
+          PList_delete(vDelRgns);
+          return false;
+        }
+      }
+    
+      results->setWorstShape(worstShape);
+    }
+  
+    PList_delete(vDelRgns); 
+  
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  void edgeCollapseOp::evaluateLengths() const
+  {
+    double minSq = MAdBIG, maxSq = 0.;
+
+    double xyzTgt[3];
+    V_coord(vTgt,xyzTgt);
+    pMSize sizeTgt = sizeField->findSize(vTgt);
+
+    // list nodes linked to target vertex by an edge
+    std::set<pVertex> vTgtLinked;
+    pPList vTgtEdges = V_edges(vTgt);
+    void * temp1 = 0;
+    while ( pEdge edge = (pEdge) PList_next(vTgtEdges,&temp1) ) {
+      vTgtLinked.insert(E_vertex(edge,0));
+      vTgtLinked.insert(E_vertex(edge,1));
+    }
+    PList_delete(vTgtEdges);
+
+    // find nodes linked to vDel and not linked to vTgt
+    pPList vDelEdges = V_edges(vDel);
+    void * temp2 = 0;
+    while ( pEdge edge = (pEdge) PList_next(vDelEdges,&temp2) ) {
+      for (int iV=0; iV<2; iV++) {
+        pVertex pV = E_vertex(edge,iV);
+        if ( pV == vDel ) continue;
+        if ( vTgtLinked.find(pV) != vTgtLinked.end() ) continue;
+      
+        double xyzV[3];
+        V_coord(pV,xyzV);
+        pMSize sizeV = sizeField->findSize(pV);
+      
+        double newSq = sizeField->SF_XYZ_lengthSq(xyzTgt,xyzV,sizeTgt,sizeV);
+        if( newSq < minSq ) { minSq = newSq; }
+        if( newSq > maxSq ) { maxSq = newSq; }
+      }
+    }
+    PList_delete(vDelEdges);
+
+    results->setMaxLenSq(maxSq);
+    results->setMinLenSq(minSq);
+  }
+
+  // -------------------------------------------------------------------
+  void edgeCollapseOp::getCavity(pPList * cavity) const
+  {
+    if ( dim == 3 ) *cavity = V_regions(vDel);
+    else            *cavity = V_faces(vDel);
+  }
+
+  // -------------------------------------------------------------------
+  void edgeCollapseOp::apply()
+  {
+    E_collapse(mesh, edgeDel, vDel, vTgt);
+
+    HistorySgl::instance().add((int)type(),OPERATOR_APPLY,1);
+  }
+
+  // -------------------------------------------------------------------
+
+}
+
diff --git a/Adapt/operator/EdgeCollapseOp.h b/Adapt/operator/EdgeCollapseOp.h
new file mode 100644
index 0000000..5790fc4
--- /dev/null
+++ b/Adapt/operator/EdgeCollapseOp.h
@@ -0,0 +1,105 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_EDGECOLLAPSEOP
+#define _H_EDGECOLLAPSEOP
+
+#include "MAdOperatorBase.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class edgeCollapseOp: public MAdOperatorBase
+  {
+  public:
+
+    edgeCollapseOp(pMesh, DiscreteSF *);
+    edgeCollapseOp(const edgeCollapseOp &);
+    ~edgeCollapseOp() {}
+
+    operationType type() const { return MAd_ECOLLAPSE; }
+
+    void collapseOnBoundary(bool, double);
+    void setCollapseEdge(pEdge, pVertex, pVertex);
+
+    void getCavity(pPList *) const;
+
+    void apply();
+
+  private:
+
+    bool checkConstraints() const;
+    bool checkGeometry();
+    bool evaluateShapes();
+    bool evaluateShapes2D();
+    void evaluateLengths() const;
+  
+  private:
+
+    pEdge edgeDel;
+    pVertex vDel; // the vertex to be deleted
+    pVertex vTgt; // the target vertex
+
+    bool constrainBoundary;
+    double dVTol, dATol; // tolerance on the relative change of volume or area
+  };
+
+  // -------------------------------------------------------------------
+  inline edgeCollapseOp::edgeCollapseOp(const edgeCollapseOp & _ec):
+    MAdOperatorBase(_ec)
+  {
+    edgeDel = _ec.edgeDel;
+    vDel = _ec.vDel;
+    vTgt = _ec.vTgt;
+    constrainBoundary = _ec.constrainBoundary;
+    dVTol = _ec.dVTol;
+    dATol = _ec.dATol;
+  }
+
+  // -------------------------------------------------------------------
+  inline edgeCollapseOp::edgeCollapseOp(pMesh _m, DiscreteSF * _sf):
+    MAdOperatorBase(_m,_sf)
+  {
+    edgeDel = NULL;
+    vDel = NULL;
+    vTgt = NULL;
+    constrainBoundary = true;
+    dVTol = MAdTOL;
+    dATol = MAdTOL;
+  }
+
+  // -------------------------------------------------------------------
+  inline void edgeCollapseOp::collapseOnBoundary(bool cob, double tolerance)
+  {
+    constrainBoundary = !cob;
+    dVTol = tolerance;
+    dATol = tolerance;
+  }
+
+  // -------------------------------------------------------------------
+  inline void edgeCollapseOp::setCollapseEdge(pEdge _edgeDel,
+                                              pVertex _vDel,
+                                              pVertex _vTgt)
+  {
+    edgeDel = _edgeDel;
+    vDel = _vDel;
+    vTgt = _vTgt;
+    results->reset();
+  }
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
+
diff --git a/Adapt/operator/EdgeSplitOp.cc b/Adapt/operator/EdgeSplitOp.cc
new file mode 100644
index 0000000..4590560
--- /dev/null
+++ b/Adapt/operator/EdgeSplitOp.cc
@@ -0,0 +1,207 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Olivier Pierard, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "EdgeSplitOp.h"
+#include "OperatorTools.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  bool edgeSplitOp::checkConstraints() const
+  {
+    if ( EN_constrained((pEntity)edge) )  return false;
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool edgeSplitOp::checkGeometry()
+  {
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool edgeSplitOp::evaluateShapes()
+  {
+    pPList eRegs = E_regions(edge);
+
+    // 2D case
+    if ( PList_size(eRegs) == 0 ) {
+      bool flag = evaluateShapes2D();
+      PList_delete(eRegs);
+      return flag;
+    }
+
+    // 3D case
+    else {
+
+      double worstShape = MAdBIG;
+
+      void * temp = 0;
+      while ( pRegion region = (pRegion)PList_next(eRegs,&temp) ) {
+
+        pPList rVerts = R_vertices(region);
+      
+        // evaluate the two regions resulting from the split
+        for( int iR=0; iR<2; iR++ ) {
+
+          pVertex eV = E_vertex(edge,iR);
+
+          pMSize rSizes[4] = { NULL, NULL, NULL, NULL };
+          double rCoords[4][3];
+
+          pVertex pV = NULL;
+          void * iter = NULL;
+          for( int iRV=0; (pV=(pVertex)PList_next(rVerts,&iter) ); iRV++ ) {
+            if( pV == eV ) {
+              rSizes[iRV] = xyzSize;
+              rCoords[iRV][0] = xyz[0]; 
+              rCoords[iRV][1] = xyz[1]; 
+              rCoords[iRV][2] = xyz[2];
+            }
+            else {
+              rSizes[iRV] = sizeField->findSize(pV);
+              V_coord(pV,rCoords[iRV]);
+            }
+          }
+        
+          double rShape;
+          if( !mqm.getElementEvaluator()->XYZ_R_shape(rCoords,rSizes,&rShape) ) {
+            PList_delete (eRegs);
+            PList_delete (rVerts);
+            return false;
+          }
+
+          if( worstShape > rShape ) worstShape = rShape;
+        }
+        PList_delete(rVerts);
+      }
+
+      results->setWorstShape(worstShape);
+    }
+
+    PList_delete(eRegs);
+  
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool edgeSplitOp::evaluateShapes2D()
+  {
+    double worstShape = MAdBIG;
+
+    pPList eFaces = E_faces(edge);
+
+    void * temp = NULL;
+    while ( pFace face = (pFace)PList_next(eFaces,&temp) ) {
+
+      pPList fVerts = F_vertices(face,1);
+    
+      // evaluate the two faces resulting from the split
+      for( int iF=0; iF<2; iF++ ) {
+
+        pVertex eV = E_vertex(edge,iF);
+
+        pMSize fSizes[3] = { NULL, NULL, NULL };  
+        double fCoords[3][3];
+
+        pVertex pV;
+        void * iter = NULL;
+        for( int iFV=0; (pV=(pVertex)PList_next(fVerts,&iter)); iFV++ ) {
+          if( pV == eV ) {
+            fSizes[iFV] = xyzSize;
+            fCoords[iFV][0] = xyz[0];
+            fCoords[iFV][1] = xyz[1];
+            fCoords[iFV][2] = xyz[2];
+          }
+          else {
+            fSizes[iFV] = sizeField->findSize(pV);
+            V_coord(pV,fCoords[iFV]);
+          }
+        }
+      
+        double fShape;
+        if( !mqm.getElementEvaluator()->XYZ_F_shape(fCoords,fSizes,0,&fShape) ) {
+          PList_delete (eFaces);
+          PList_delete (fVerts);
+          return false;
+        }
+
+        if( worstShape > fShape ) worstShape = fShape;
+      }
+
+      PList_delete(fVerts);
+    }
+
+    PList_delete(eFaces);
+
+    results->setWorstShape(worstShape);
+  
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  void edgeSplitOp::evaluateLengths() const
+  {
+    pVertex verts[2];
+    double vCoords[2][3];
+    pMSize vSizes[2] = {NULL,NULL};
+    for( int iV=0; iV<2; iV++ ) {
+      verts[iV] = E_vertex(edge,iV);
+      V_coord(verts[iV],vCoords[iV]);
+      vSizes[iV] = sizeField->findSize(verts[iV]);
+    }
+
+    pMSize newSize = sizeField->getSizeOnEntity((pEntity)edge,xyz);
+
+    double lSqMax = sizeField->SF_XYZ_lengthSq(xyz, vCoords[0],
+                                               newSize, vSizes[0]);
+    double lSqMin = lSqMax;
+    double lSq = sizeField->SF_XYZ_lengthSq(xyz, vCoords[1],
+                                            newSize, vSizes[1]);  
+    if( lSq > lSqMax ) lSqMax = lSq;
+    if( lSq < lSqMin ) lSqMin = lSq;
+  
+    for( int i=0; i<E_numFaces(edge); i++ ) {
+      pVertex oppV = F_edOpVt(E_face(edge,i), edge);
+      pMSize oppSize = sizeField->findSize(oppV);
+      double xyzOpp[3];
+      V_coord(oppV,xyzOpp);
+      lSq = sizeField->SF_XYZ_lengthSq(xyz, xyzOpp,
+                                       newSize, oppSize);
+      if( lSq > lSqMax ) lSqMax = lSq;
+      if( lSq < lSqMin ) lSqMin = lSq;
+    }
+  
+    if( newSize ) delete newSize;
+  
+    results->setMaxLenSq(lSqMax);
+    results->setMinLenSq(lSqMin);
+  }
+
+  // -------------------------------------------------------------------
+  void edgeSplitOp::getCavity(pPList * cavity) const
+  {
+    if ( dim == 3 )  *cavity = E_regions(edge);
+    else             *cavity = E_faces(edge);
+  }
+
+  // -------------------------------------------------------------------
+  void edgeSplitOp::apply()
+  {
+    E_split(mesh,edge,xyz,u);
+
+    HistorySgl::instance().add((int)type(),OPERATOR_APPLY,1);
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/operator/EdgeSplitOp.h b/Adapt/operator/EdgeSplitOp.h
new file mode 100644
index 0000000..fa0becb
--- /dev/null
+++ b/Adapt/operator/EdgeSplitOp.h
@@ -0,0 +1,92 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Olivier Pierard, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_EDGESPLITOP
+#define _H_EDGESPLITOP
+
+#include "MAdOperatorBase.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class edgeSplitOp: public MAdOperatorBase
+  {
+  public:
+
+    edgeSplitOp(pMesh, DiscreteSF *);
+    edgeSplitOp(const edgeSplitOp &);
+    ~edgeSplitOp() { if (xyzSize) delete xyzSize; }
+
+    operationType type() const { return MAd_ESPLIT; }
+
+    // stores the edge to be splitted, computes the location of the split 
+    // and returns the (unique) adimensional square length of the resulting edges
+    double setSplitEdge(pEdge);
+
+    void getCavity(pPList *) const;
+
+    void apply();
+
+  private:
+
+    bool checkConstraints() const;
+    bool checkGeometry();
+    bool evaluateShapes();
+    bool evaluateShapes2D();
+    void evaluateLengths() const;
+
+  private:
+
+    pEdge edge;
+    double xyz[3], u; // new vertex location: euclidian and edge parameter
+    pMSize xyzSize;   // size at the new vertex
+  };
+
+  // -------------------------------------------------------------------
+  inline edgeSplitOp::edgeSplitOp(const edgeSplitOp & _es):
+    MAdOperatorBase(_es)
+  {
+    edge = _es.edge;
+    xyz[0] = _es.xyz[0];
+    xyz[1] = _es.xyz[1];
+    xyz[2] = _es.xyz[2];
+    u = _es.u;
+    xyzSize = MS_copy(_es.xyzSize);
+  }
+
+  // -------------------------------------------------------------------
+  inline edgeSplitOp::edgeSplitOp(pMesh _m, DiscreteSF * _sf):
+    MAdOperatorBase(_m,_sf), edge(NULL)
+  {
+    xyz[0] = 0.;
+    xyz[1] = 0.;
+    xyz[2] = 0.;
+    u = -1.;
+    xyzSize = NULL;
+  }
+
+  // -------------------------------------------------------------------
+  inline double edgeSplitOp::setSplitEdge(pEdge _edge)
+  {
+    if ( xyzSize ) delete xyzSize;
+    edge = _edge;
+    double lenReduc;
+    u = sizeField->SF_E_center(_edge,xyz,&lenReduc,&xyzSize);
+    return lenReduc;
+  }
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/operator/EdgeSwapConfig.cc b/Adapt/operator/EdgeSwapConfig.cc
new file mode 100644
index 0000000..53ff7e4
--- /dev/null
+++ b/Adapt/operator/EdgeSwapConfig.cc
@@ -0,0 +1,75 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Arnaud Francois, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "EdgeSwapConfig.h"
+#include <iostream>
+
+using namespace MAd;
+
+// -------------------------------------------------------------------
+// Edge swap template with 3 faces connected to the edge
+const int EdgeSwap3::triangles[1][3] = { { 0,1,2 } };
+const int EdgeSwap3::triangulations[1][1] = {{0}};
+
+// Edge swap template with 4 faces connected to the edge
+const int EdgeSwap4::triangles[4][3] = { {0,1,2}, {0,2,3}, {0,1,3}, {1,2,3} };
+const int EdgeSwap4::triangulations[2][2] = { {0, 1}, {2, 3} };
+
+// Edge swap template with 5 faces connected to the edge
+const int EdgeSwap5::triangles[10][3]= { {0,1,2}, {0,2,3}, {0,3,4}, {0,1,4}, {1,3,4},
+                                         {1,2,3}, {2,3,4}, {0,2,4}, {0,1,3}, {1,2,4} };
+const int EdgeSwap5::triangulations[5][3] = { {0,1,2}, {3,4,5}, {0,6,7}, {2,5,8}, {3,6,9} } ;
+
+// Edge swap template with 6 faces connected to the edge
+const int EdgeSwap6::triangles[20][3]= { {0,1,2}, {0,2,3}, {0,3,4}, {0,4,5}, 
+      {0,2,5}, {2,4,5}, {2,3,4}, {0,3,5}, {3,4,5}, {0,2,4}, {2,3,5}, {1,2,3},
+      {0,1,3}, {0,1,5}, {1,4,5}, {1,3,4}, {0,1,4}, {1,3,5}, {1,2,4}, {1,2,5} };
+const int EdgeSwap6::triangulations[14][4] = { {0,1,2,3}, {0,4,5,6}, {0,1,7,8},
+      {0,3,6,9}, {0,4,8,10}, {2,3,11,12}, {11,13,14,15}, {7,8,11,12}, {3,11,15,16},
+      {8,11,13,17}, {6,13,14,18}, {3,6,16,18}, {5,6,13,19}, {8,10,13,19} };
+
+// Edge swap template with 7 faces connected to the edge
+const int EdgeSwap7::triangles[35][3] = { {0,1,2}, {0,2,3}, {0,3,4}, {0,4,5}, 
+      {0,5,6}, {0,3,6}, {3,5,6}, {3,4,5}, {0,4,6}, {4,5,6}, {0,3,5}, {3,4,6},
+      {0,2,4}, {2,3,4}, {0,2,6}, {2,5,6}, {2,4,5}, {0,2,5}, {2,4,6}, {2,3,5},
+      {2,3,6}, {0,1,3}, {1,2,3}, {0,1,4}, {1,3,4}, {0,1,6}, {1,5,6}, {1,4,5},
+      {0,1,5}, {1,4,6}, {1,3,5}, {1,3,6}, {1,2,4}, {1,2,5}, {1,2,6} };
+const int EdgeSwap7::triangulations[42][5] = { {0,1,2,3,4}, {0,1,5,6,7}, 
+      {0,1,2,8,9}, {0,1,4,7,10}, {0,1,5,9,11}, {0,3,4,12,13}, {0,13,14,15,16},
+      {0,8,9,12,13}, {0,4,13,16,17}, {0,9,13,14,18}, {0,7,14,15,19},{0,4,7,17,19},
+      {0,6,7,14,20}, {0,9,11,14,20}, {2,3,4,21,22}, {5,6,7,21,22}, {2,8,9,21,22},
+      {4,7,10,21,22}, {5,9,11,21,22}, {3,4,22,23,24}, {22,24,25,26,27}, 
+      {8,9,22,23,24}, {4,22,24,27,28}, {9,22,24,25,29}, {7,22,25,26,30},
+      {4,7,22,28,30}, {6,7,22,25,31}, {9,11,22,25,31}, {3,4,13,23,32},
+      {13,25,26,27,32}, {8,9,13,23,32}, {4,13,27,28,32}, {9,13,25,29,32},
+      {13,16,25,26,33}, {4,13,16,28,33}, {13,15,16,25,34}, {9,13,18,25,34},
+      {7,19,25,26,33}, {4,7,19,28,33}, {7,15,19,25,34}, {6,7,20,25,34}, 
+      {9,11,20,25,34} };
+
+// -------------------------------------------------------------------
+void EdgeSwapConfiguration::set( int i )
+{
+  switch( i )
+  {
+    case 0: c = &cNull; break;
+    case 3: c = &c3; break;
+    case 4: c = &c4; break;
+    case 5: c = &c5; break;
+    case 6: c = &c6; break;
+    case 7: c = &c7; break;
+    default:
+      std::cerr << "Error: Swap configuration not implemented for n="<< i << std::endl;
+      throw;
+  }
+}
+
+// -------------------------------------------------------------------
diff --git a/Adapt/operator/EdgeSwapConfig.h b/Adapt/operator/EdgeSwapConfig.h
new file mode 100644
index 0000000..975e8c0
--- /dev/null
+++ b/Adapt/operator/EdgeSwapConfig.h
@@ -0,0 +1,173 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Arnaud Francois, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_EDGESWAPCONFIG
+#define _H_EDGESWAPCONFIG
+
+namespace MAd
+{
+  // -------------------------------------------------------------------
+  class EdgeSwapTemplate  // 3D case
+  {
+  public:
+    EdgeSwapTemplate() {}
+    virtual ~EdgeSwapTemplate() {}
+    virtual int getConfig(){ return 0; }       // nb of faces attached to edge
+    virtual int nb_triangulations() = 0;       // nb of possible triangulations
+    virtual int nb_triangles() = 0;            // nb of different triangles
+    virtual int nb_tri_triangulation() = 0;    // nb of triangles in a triangulation
+    virtual const int* triangle( int i ) = 0;  // return the triangle i 
+    virtual const int* triangulation( int i ) = 0;  // return the triangulation i
+  };
+
+  // -------------------------------------------------------------------
+  // Null edge swap template
+  class EdgeSwap0 : public EdgeSwapTemplate
+  {
+  public:
+    EdgeSwap0() { }
+    int getConfig(){ return 0; }
+    int nb_triangles(){ return -1; }
+    int nb_triangulations(){ return -1; }
+    int nb_tri_triangulation(){ return -1; }
+    const int* triangle( int i) { return 0; }
+    const int* triangulation( int i) { return 0; }
+  };
+
+  // -------------------------------------------------------------------
+  // Edge swap template with 3 faces connected to the edge
+  class EdgeSwap3 : public EdgeSwapTemplate
+  {
+  public:
+    EdgeSwap3() { }
+    int getConfig(){ return 3; }
+    int nb_triangles(){ return 1; }
+    int nb_triangulations(){ return 1; }
+    int nb_tri_triangulation(){ return 1; }
+    const int* triangle( int i) { return triangles[i]; }
+    const int* triangulation( int i) { return triangulations[i]; }
+  private:
+    static const int triangles[1][3];
+    static const int triangulations[1][1];
+  };
+
+  // -------------------------------------------------------------------
+  // Edge swap template with 4 faces connected to the edge
+  class EdgeSwap4 : public EdgeSwapTemplate
+  {
+  public:
+    EdgeSwap4() { }
+    int getConfig(){ return 4; }
+    int nb_triangles(){ return 4; }
+    int nb_triangulations(){ return 2; }
+    int nb_tri_triangulation(){ return 2; }
+    const int* triangle( int i) { return triangles[i]; }
+    const int* triangulation( int i) { return triangulations[i]; }
+  private:
+    static const int triangles[4][3];
+    static const int triangulations[2][2];
+  };
+
+  // -------------------------------------------------------------------
+  // Edge swap template with 5 faces connected to the edge
+  class EdgeSwap5 : public EdgeSwapTemplate
+  {
+  public:
+    EdgeSwap5() { }
+    int getConfig(){ return 5; }
+    int nb_triangles(){ return 10; }
+    int nb_triangulations(){ return 5; }
+    int nb_tri_triangulation(){ return 3; }
+    const int* triangle( int i) { return triangles[i]; }
+    const int* triangulation( int i) { return triangulations[i]; }
+  private:
+    static const int triangles[10][3];
+    static const int triangulations[5][3];
+  };
+
+  // -------------------------------------------------------------------
+  // Edge swap template with 6 faces connected to the edge
+  class EdgeSwap6 : public EdgeSwapTemplate
+  {
+  public:
+    EdgeSwap6() { }
+    int getConfig(){ return 6; }
+    int nb_triangles(){ return 20; }
+    int nb_triangulations(){ return 14; }
+    int nb_tri_triangulation(){ return 4; }
+    const int* triangle( int i) { return triangles[i]; }
+    const int* triangulation( int i) { return triangulations[i]; }
+  protected:
+    static const int triangles[20][3];
+    static const int triangulations[14][4];
+  };
+
+  // -------------------------------------------------------------------
+  // Edge swap template with 7 faces connected to the edge
+  class EdgeSwap7 : public EdgeSwapTemplate
+  {
+  public:
+    EdgeSwap7() { }
+    int getConfig(){ return 7; }
+    int nb_triangles(){ return 35; }
+    int nb_triangulations(){ return 42; }
+    int nb_tri_triangulation(){ return 5; }
+    const int* triangle( int i) { return triangles[i]; }
+    const int* triangulation( int i) { return triangulations[i]; }
+  protected:
+    static const int triangles[35][3];
+    static const int triangulations[42][5];
+  };
+
+  // -------------------------------------------------------------------
+  // Interface
+  class EdgeSwapConfiguration
+  {
+  public:
+
+    EdgeSwapConfiguration( ) { set(0); }
+    EdgeSwapConfiguration( int n ) { set( n ); }
+    EdgeSwapConfiguration( const EdgeSwapConfiguration &x ) { set( x.get() ); }
+    ~EdgeSwapConfiguration() { }
+
+    // select edge swap template with n faces connected to the edge
+    void set( int n );
+
+    // return the nodes of triangle i for the selected configuration
+    const int* triangle( int i ) const {  return (*c).triangle(i); }
+
+    // return the node j of triangle i for the selected configuration
+    int triangle( int i, int j ) const {  return (*c).triangle(i)[j]; }
+
+    // return the triangle j of triangulation i
+    int triangulation( int i, int j ) const {  return (*c).triangulation(i)[j]; }
+
+    int nb_triangles() const { return c->nb_triangles(); }
+    int nb_triangulations() const { return c->nb_triangulations(); }
+    int nb_tri_triangulation() const { return c->nb_tri_triangulation(); }
+
+    int get() const { return c->getConfig(); }
+
+  private:
+    EdgeSwap0         cNull;
+    EdgeSwap3         c3;
+    EdgeSwap4         c4;
+    EdgeSwap5         c5;
+    EdgeSwap6         c6;
+    EdgeSwap7         c7;
+    EdgeSwapTemplate * c;
+  };
+
+  // -------------------------------------------------------------------
+}
+#endif
diff --git a/Adapt/operator/EdgeSwapOp.cc b/Adapt/operator/EdgeSwapOp.cc
new file mode 100644
index 0000000..8cb975d
--- /dev/null
+++ b/Adapt/operator/EdgeSwapOp.cc
@@ -0,0 +1,576 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Arnaud Francois, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "EdgeSwapOp.h"
+#include "MAdDefines.h"
+#include "CallBackManager.h"
+#include "MAdOutput.h"
+#include "MathUtils.h"
+#include "MAdMessage.h"
+
+#include <iostream>
+#include <sstream>
+using std::cout;
+using std::endl;
+using std::cerr;
+using std::stringstream;
+#include <math.h>
+
+namespace MAd
+{
+  // -------------------------------------------------------------------
+  bool edgeSwapOp::checkConstraints() const
+  {
+    if( EN_constrained((pEntity)edge) ) return false;
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool edgeSwapOp::checkGeometry()
+  {
+    // set the available swap configurations for a given edge 
+    // regarding geometry
+    if( M_numRegions(mesh)==0 ) return checkGeometry2D();  // 2D mesh
+    else                        return checkGeometry3D();  // 3D mesh
+    return false;
+  }
+
+  // -------------------------------------------------------------------
+  bool edgeSwapOp::checkGeometry2D()
+  {
+    if ( E_numFaces(edge)   != 2 ) return false;
+    if ( E_whatInType(edge) <= 1 ) return false;
+    
+    // check for dimension reduction
+    pFace face0 = E_face(edge,0);
+    pVertex pv0 = F_edOpVt(face0,edge);
+    pFace face1 = E_face(edge,1);
+    pVertex pv1 = F_edOpVt(face1,edge);
+    if ( E_exist(pv0,pv1) ) return false;
+
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  // Set the swap configuration to be used. Return false if the edge swap
+  // operation is not allowed
+  bool edgeSwapOp::checkGeometry3D()
+  {
+    int nbf = E_numFaces(edge);  // nb of faces attached to the edge
+    if( nbf < 3 || nbf >7 )      // check if swap configuration is implemented
+      return false;
+
+    // check the dimension of the geometrical entity on which edge is classified
+    bool boundarySwap = false;
+    int gDim = E_whatInType(edge);
+    if( gDim == 1 ) return false;
+    else if ( gDim == 2 )
+      {
+        if ( constrainBoundary ) return false;
+        else {
+          checkVol = true;
+          boundarySwap = true;
+        }
+      }
+
+    // get 'face' that connects to edge. if one classified on a surface, take that
+    // one, otherwise take any (e.g. last one)
+    int nbBFaces = 0;
+    pFace face;
+    pFace bFace=NULL;
+    for( int i=0; i < nbf; i++ )
+      {
+        face = E_face(edge,i);
+        if( F_whatInType(face) == 2 ) {
+          nbBFaces++;
+          bFace = face;
+        }
+      }
+    if (bFace) face = bFace;
+
+    // reject swaps on non-manifold cavities
+    if ( nbBFaces > 2 || nbBFaces == 1 ) {
+      exportCavity("swap_nonmanif1.pos");
+      MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+                                    "Found a non-manifold domain, rejecting edge swap");
+      return false;
+    }
+
+    // get region connected to face
+    pRegion region = F_region(face,0);
+    if( !region ) region = F_region(face,1);
+
+    // Get vertices of the polyhedron around 'edge'
+    vertices.clear();
+    vertices.resize(nbf);
+    pFace current_face = face;
+    pRegion current_region = region;
+    for( int i=0; i < nbf; i++ )
+      {
+        vertices[i] = F_edOpVt(current_face, edge);
+        
+        if (i == (nbf-1)) {
+          if ( boundarySwap && current_region != NULL ) {
+            // non-manifold-domain: a geometrical face with 2 regions
+            exportCavity("swap_nonmanif2.pos");
+            MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+                                          "Found a non-manifold domain, rejecting edge swap");
+            return false;
+          }
+        }
+        else {
+          pFace next_face = E_otherFace(edge, current_face, current_region);
+          pRegion next_region = F_region(next_face, 0);
+          if( next_region == current_region ) {
+            next_region = F_region(next_face, 1);
+          }
+          current_face   = next_face;
+          current_region = next_region;
+        }
+      }
+
+    // Check dimension reduction: if swap on boundary, check that no edge 
+    // links the first and last points of the crown. 
+    if ( boundarySwap ) {
+      if ( E_exist(vertices[0],vertices[nbf-1]) ) return false;
+    }
+
+    // Find top and bottom vertices from orientation of the polyhedron
+    // v2 is top vertex if ( V01 x V02 ) . V32 > 0
+    pVertex  v0 = vertices[0];
+    pVertex  v1 = vertices[1];
+    pVertex  v2 = E_vertex(edge, 0);
+    pVertex  v3 = E_vertex(edge, 1);
+
+    double p[4][3];
+    V_coord( v0, p[0] );
+    V_coord( v1, p[1] );
+    V_coord( v2, p[2] );
+    V_coord( v3, p[3] );
+    double a[3] = { p[1][0]-p[0][0], p[1][1]-p[0][1], p[1][2]-p[0][2] };
+    double b[3] = { p[2][0]-p[0][0], p[2][1]-p[0][1], p[2][2]-p[0][2] };
+    double c[3] = { p[2][0]-p[3][0], p[2][1]-p[3][1], p[2][2]-p[3][2] };
+    double ab[3] = { a[1]*b[2]-a[2]*b[1], a[2]*b[0]-a[0]*b[2], a[0]*b[1]-a[1]*b[0] };  // a x b
+    if( ab[0]*c[0] + ab[1]*c[1] + ab[2]*c[2] > 0.0 )
+      {
+        vt = v2;
+        vb = v3;
+      }
+    else
+      {
+        vt = v3;
+        vb = v2;
+      }
+
+    swap_config.set( nbf );
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool edgeSwapOp::evaluateShapes()
+  {
+    // select the best triangulation and evaluate worst shape
+    if( M_numRegions(mesh)==0 ) return evaluateShapes2D();
+    else                        return evaluateShapes3D();
+    return false;
+  }
+
+  // -------------------------------------------------------------------
+  // loop over all possible swap configurations and select the best triangulation
+  bool edgeSwapOp::evaluateShapes3D()
+  {
+    // if edge is classified on face type need to check volume
+    double volume = 0.0;
+    if( checkVol )
+      {
+        pRegion region;
+        pPList regions = E_regions (edge);
+        void *temp=0;
+        while( ( region = (pRegion)PList_next(regions, &temp) ) )
+          volume += R_volume (region);
+        PList_delete (regions);
+      }
+    int nb_triangles = swap_config.nb_triangles();
+    // here nb_triangles is maximum 35 (for config = 7), 
+    // ansi c++ does not support variable lengths for arrays
+    double shapes[35];     // worst shape for each configuration
+    bool   valid_shapes[35];
+    double volumes[35];    // volumes of the new swap configurations
+
+    // -- loop on all possible triangulations and compute associated element shapes --
+    for( int i=0; i< nb_triangles; i++ )
+      {
+        double xyz[4][3];
+        pMSize s[4];
+
+        pVertex v0 = vertices[ swap_config.triangle(i,0) ];
+        pVertex v1 = vertices[ swap_config.triangle(i,1) ];
+        pVertex v2 = vertices[ swap_config.triangle(i,2) ];
+
+        V_coord(v0, xyz[0]);
+        V_coord(v1, xyz[1]);
+        V_coord(v2, xyz[2]);
+        V_coord(vt, xyz[3]);
+
+        s[0] = sizeField->findSize(v0);
+        s[1] = sizeField->findSize(v1);
+        s[2] = sizeField->findSize(v2);
+        s[3] = sizeField->findSize(vt);
+
+        // evaluate 'top' Tet [v0,v1,v2,vt]
+        double shape;
+        bool shape_ok = mqm.getElementEvaluator()->XYZ_R_shape( xyz, s , &shape );
+        valid_shapes[i] = shape_ok;
+        shapes[i] = shape;
+
+        if( !shape_ok )    // no need to compute shape of bottom tet since
+          {                  // configuration will be rejected
+            valid_shapes[i] = false;
+            continue;
+          }
+
+        // evaluate 'bottom' Tet [v0,v2,v1,vb]
+        V_coord(v2, xyz[1]);
+        V_coord(v1, xyz[2]);
+        V_coord(vb, xyz[3]);
+        s[1] = sizeField->findSize(v2);
+        s[2] = sizeField->findSize(v1);
+        s[3] = sizeField->findSize(vb);
+
+        valid_shapes[i] = mqm.getElementEvaluator()->XYZ_R_shape( xyz, s , &shape );
+
+        // keep worst value of top-bottom tets for swap configuration i in shapes[i]
+        if( shape < shapes[i] ) shapes[i] = shape;
+
+        // volume computation
+        if( checkVol )
+          {
+            volumes[i]  = R_XYZ_volume( xyz ); // bottom tet
+            V_coord(vt,xyz[3]);
+            volumes[i] += R_XYZ_volume( xyz ); // top tet
+          }
+      }
+
+    // -- Select best valid edge swap configuration --
+    double optimum = 0.0;
+    for( int i=0; i < swap_config.nb_triangulations(); i++ )
+      {
+        // find worst element shape of this configuration
+        double worst_shape = MAdBIG;    // assume the shape is always between 0.0 and 1.0
+        bool   valid;
+        for( int j=0; j < swap_config.nb_tri_triangulation(); j++ )
+          {
+            int t = swap_config.triangulation(i,j);  // test triangle t
+            valid = valid_shapes[t];
+            if( !valid )
+              break;
+
+            if( shapes[t] < worst_shape )
+              worst_shape = shapes[t];
+          }
+
+        // if shape is not valid, check next swap configuration
+        if( !valid )
+          continue;
+
+        // check volume change
+        if( checkVol )
+          {
+            double new_volume = 0.0;
+            for( int j=0; j < swap_config.nb_tri_triangulation(); j++ )
+              new_volume += volumes[ swap_config.triangulation(i,j) ];
+
+            if( fabs(volume-new_volume)/volume > dVTol )
+              continue;
+          }
+
+        if( worst_shape > optimum )
+          {
+            optimum = worst_shape;  // worst shape of the configuration
+            conf =  i;              // best swap configuration
+          }
+      }
+
+    // no valid swap configuration was found
+    if( optimum <= MAdTOL ) return false;
+
+    results->setWorstShape( optimum );
+
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool edgeSwapOp::evaluateShapes2D()
+  {
+    double worstShape = MAdBIG;
+  
+    // evaluate shape of new triangles
+    pFace f0 = E_face(edge,0);
+    pFace f1 = E_face(edge,1);
+    pVertex v0 = E_vertex(edge,0);
+    pVertex v1 = E_vertex(edge,1);
+    pVertex v2 = F_edOpVt(f0, edge);
+    pVertex v3 = F_edOpVt(f1, edge);
+  
+    double xyz[3][3];
+    V_coord(v0, xyz[0]);
+    V_coord(v2, xyz[1]);
+    V_coord(v3, xyz[2]);
+  
+    pMSize s[3];
+    s[0] = sizeField->findSize(v0);
+    s[1] = sizeField->findSize(v2);
+    s[2] = sizeField->findSize(v3);
+  
+    // evaluate shape of new triangles [v0,v2,v3] && [v1,v2,v3]
+    double normal[3];
+    double e02[3],e03[3];
+    diffVec(xyz[1],xyz[0],e02);
+    diffVec(xyz[2],xyz[0],e03);
+    crossProd(e02,e03,normal);
+    double shape;
+    // [v0,v2,v3]
+    if( !mqm.getElementEvaluator()->XYZ_F_shape(xyz, s, normal, &shape) ) return false;
+    worstShape = shape;
+  
+    V_coord(v1, xyz[0]);
+    s[0] = sizeField->findSize(v1);
+  
+    normal[0] = -normal[0];
+    normal[1] = -normal[1];
+    normal[2] = -normal[2];
+  
+    if( !mqm.getElementEvaluator()->XYZ_F_shape(xyz, s, normal, &shape) ) return false;
+  
+    if( worstShape > shape ) worstShape = shape;
+  
+    results->setWorstShape(worstShape);
+    // check the area of the new faces in case of '3D' surf mesh
+  
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  //  calculate the max/min size after the modification is applied
+  void edgeSwapOp::evaluateLengths() const
+  {
+    double maxSwap, minSwap;
+
+    // consider the new edges created after swap
+    if( M_numRegions(mesh) == 0 )   // 2D mesh
+      {
+        pFace face0 = E_face(edge, 0);
+        pVertex v0  = F_edOpVt(face0,edge);
+        pFace face1 = E_face(edge, 1);
+        pVertex v1  = F_edOpVt(face1,edge);
+        maxSwap = sizeField->SF_VV_lengthSq(v0,v1);
+        minSwap = maxSwap;
+      }
+    else
+      {
+        // 3D mesh
+        minSwap = MAdBIG;
+        maxSwap = 0.;
+
+        // evaluate the triangles of the c'th configuration
+        pVertex v[3];
+        for( int j=0; j < swap_config.nb_tri_triangulation(); j++ )
+          {
+            int t = swap_config.triangulation(conf,j);
+            for( int i=0; i<3; i++ )
+              {
+                v[i] = vertices[ swap_config.triangle(t,i) ];
+              }
+
+            for( int i=0; i<3; i++ )
+              {
+                // (AF) we could also pre-define the new edges to be tested in the EdgeSwapConfig
+                // to avoid the E_exist loop
+                if( !E_exist(v[i],v[(i+1)%3]) )   /// 0-1,1-2,2-0
+                  {
+                    double lSq = sizeField->SF_VV_lengthSq(v[i], v[(i+1)%3]);
+                    if( lSq > maxSwap ) maxSwap = lSq;
+                    if( lSq < minSwap ) minSwap = lSq;
+                  }
+              }
+          }
+      }
+
+    // initialization
+    double lMinSq = MAdBIG;
+    double lMaxSq = 0.0;
+    if( maxSwap > lMaxSq ) lMaxSq = maxSwap;
+    if( minSwap < lMinSq ) lMinSq = minSwap;
+
+    results->setMaxLenSq(lMaxSq);
+    results->setMinLenSq(lMinSq);
+  }
+
+  // -------------------------------------------------------------------
+  void edgeSwapOp::apply()
+  {
+    if( M_numRegions(mesh) !=0 ) apply3D();
+    else                         apply2D();
+    HistorySgl::instance().add((int)type(),OPERATOR_APPLY,1);
+  }
+
+  // -------------------------------------------------------------------
+  int edgeSwapOp::apply2D()
+  {
+    // 2D mesh case
+    pPList old_faces = PList_new();
+    pPList new_faces = PList_new();
+
+    pFace f0 = E_face(edge,0);
+    pFace f1 = E_face(edge,1);
+    pVertex v0 = E_vertex(edge,0);
+    pVertex v1 = E_vertex(edge,1);
+    pVertex v2 = F_edOpVt(f0, edge);
+    pVertex v3 = F_edOpVt(f1, edge);
+
+    pGEntity gface = F_whatIn(f0);  // classification
+
+    // new triangles [v0,v2,v3] && [v1,v2,v3]
+    pEdge newe  = M_createE(mesh, v2, v3, gface);
+    pEdge e02 = mesh->find_edge( v0, v2, (MDB_Triangle*)f0 );
+    pEdge e03 = mesh->find_edge( v0, v3, (MDB_Triangle*)f1 );
+    pEdge e12 = mesh->find_edge( v1, v2, (MDB_Triangle*)f0 );
+    pEdge e13 = mesh->find_edge( v1, v3, (MDB_Triangle*)f1 );
+    pFace newf0 = mesh->add_triangle( e02, newe, e03, gface);
+    pFace newf1 = mesh->add_triangle( e12, newe, e13, gface);
+
+    PList_append(new_faces, newf0);
+    PList_append(new_faces, newf1);
+
+    // call callback
+    CallBackManagerSgl::instance().callCallBacks(old_faces, new_faces, MAd_ESWAP, (pEntity)edge);
+    PList_delete(old_faces);
+    PList_delete(new_faces);
+
+    // deletion
+    M_removeFace(mesh,f0);
+    M_removeFace(mesh,f1);
+    M_removeEdge(mesh,edge);
+
+    edge = 0;
+    conf = -1;
+
+    return 1;
+
+  }
+
+  // -------------------------------------------------------------------
+  int edgeSwapOp::apply3D()
+  {
+    pPList eregs = E_regions(edge);   // cavity before swap
+    pGRegion greg = R_whatIn( (pRegion)PList_item(eregs, 0) );
+
+    pPList newRegions = PList_new();
+
+    if( conf < 0 ) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Edge swap configuration not defined, call evaluate() first");
+    }
+
+    // create new regions for the selected swap configuration
+    pVertex v[3];
+    for( int i=0; i < swap_config.nb_tri_triangulation(); i++ )
+      {
+        int t = swap_config.triangulation(conf,i);
+        for( int j=0; j<3; j++ )
+          v[j] = vertices[ swap_config.triangle(t,j) ];
+
+        //create new regions
+        pRegion r1 = mesh->add_tet( v[0], v[1],v[2], vt, (pGEntity)greg );
+        pRegion r2 = mesh->add_tet( v[0], v[2],v[1], vb, (pGEntity)greg );
+        PList_append( newRegions, r1 );
+        PList_append( newRegions, r2 );
+      }
+
+    // If swap on a boundary, classify new boundary entities (1 edge, 2 faces)
+    if( E_whatInType(edge) == 2 )
+      {
+        pGEntity bgent = E_whatIn(edge);
+
+        // the new edge to be classified is supposed to be between the first 
+        // and the last vertices of the configuration (we started to list nodes
+        // at a classified face in checkGeometry)
+        pEdge bEdge = E_exist(vertices[0],vertices[swap_config.get()-1]);
+        E_setWhatIn(bEdge,bgent);
+
+        // now classify the faces
+        pPList eFaces = E_faces(bEdge);
+        void * temp = NULL;
+        pFace face;
+        pVertex oppV;
+        int count = 0;
+        while ( ( face = (pFace)PList_next(eFaces,&temp) ) ) {
+          oppV = F_edOpVt(face,bEdge);
+          if ( oppV == vt || oppV == vb ) {
+            assert ( F_numRegions(face) == 1 );
+            F_setWhatIn(face,bgent);
+            count++;
+          }
+        }
+        PList_delete(eFaces);
+        assert(count == 2);
+      }
+
+    // call callback
+    CallBackManagerSgl::instance().callCallBacks(eregs, newRegions, MAd_ESWAP, (pEntity)edge );
+    PList_delete(newRegions);
+
+    // remove old regions connected to edge
+    pRegion frgn;
+    void   *temp = 0;
+    while( ( frgn = (pRegion)PList_next(eregs, &temp) ) )
+      M_removeRegion(mesh,frgn);
+    PList_delete(eregs);
+
+    // remove old faces connected to edge
+    pFace face;
+    pPList faces = E_faces(edge);
+    void   *temp1 = 0;
+    while( ( face = (pFace)PList_next(faces, &temp1) ) )
+      M_removeFace(mesh, face);
+    PList_delete(faces);
+
+    // remove edge
+    M_removeEdge(mesh, edge);
+
+    edge = 0;
+    conf = -1;
+
+    return 1;
+  }
+
+  // -------------------------------------------------------------------
+  void edgeSwapOp::getCavity(pPList * cavity) const
+  {
+    if ( dim == 3 )   *cavity = E_regions(edge);
+    else              *cavity = E_faces(edge);
+  }
+
+  // -------------------------------------------------------------------
+  void edgeSwapOp::reportSwap( )
+  {
+    stringstream ss;
+    std::string idStr;  ss << reportId;  ss >> idStr;
+    std::string name = reportPrefix + "swap" + idStr + ".pos";
+    pPList cavity = E_regions( edge );
+    printPosEntities(cavity,name.c_str(),OD_CONSTANT, 0 );
+    PList_delete(cavity);
+    reportId++;
+  }
+
+  // -------------------------------------------------------------------
+}
diff --git a/Adapt/operator/EdgeSwapOp.h b/Adapt/operator/EdgeSwapOp.h
new file mode 100644
index 0000000..e867ff7
--- /dev/null
+++ b/Adapt/operator/EdgeSwapOp.h
@@ -0,0 +1,124 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Arnaud Francois, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_EDGESWAPOP
+#define _H_EDGESWAPOP
+
+#include "MAdOperatorBase.h"
+#include "EdgeSwapConfig.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class edgeSwapOp : public MAdOperatorBase
+  {
+  public:
+
+    edgeSwapOp();
+    edgeSwapOp(pMesh, DiscreteSF *);
+    edgeSwapOp(const edgeSwapOp &);
+    ~edgeSwapOp() {}
+
+    operationType type() const { return MAd_ESWAP; }
+    int getMaxNumRgns() { return 7; }
+
+    void setSwapEdge(pEdge);
+    void swapOnBoundary(bool,double);
+
+    void getCavity(pPList *) const;
+
+    void apply();
+
+  private:
+
+    bool checkConstraints() const;
+    bool checkGeometry();
+    bool evaluateShapes();
+    void evaluateLengths() const;
+
+    bool checkGeometry2D();
+    bool checkGeometry3D();
+    bool evaluateShapes2D();
+    bool evaluateShapes3D();
+
+    int apply3D();
+    int apply2D();
+
+    pEdge edge;          // the edge to be swapped
+    int conf;            // best swap configuration - set by geomCheck()
+    pVertex vt;          // top and bottom vertices of the edge (define the polygon orientation
+    pVertex vb;          // w/r to vertices)
+    std::vector<pVertex> vertices; // oriented list of vertices defining the polygon
+
+    EdgeSwapConfiguration swap_config;
+
+    bool constrainBoundary;
+    bool checkVol; // tells if it's interesting to compute the variation of 
+                   // volume in the cavity (deduced from classif of edge 
+                   // and constrainBoundary)
+    double dVTol;
+
+    // reporting
+    void reportSwap( );
+    bool   report;
+    int    reportId;
+    std::string reportPrefix;
+
+  };
+
+  // -------------------------------------------------------------------
+  inline edgeSwapOp::edgeSwapOp(pMesh _m, DiscreteSF * _sf):
+    MAdOperatorBase(_m,_sf), edge(0), conf(-1), vt(0), vb(0), 
+    constrainBoundary(true),  checkVol(false), dVTol(MAdTOL),
+    report(false), reportId(0), reportPrefix("")
+  {
+    vertices.reserve(7);
+  }
+
+  // -------------------------------------------------------------------
+  inline edgeSwapOp::edgeSwapOp(const edgeSwapOp & _es):
+    MAdOperatorBase(_es), swap_config( _es.swap_config )
+  {
+    edge        = _es.edge;
+    conf        = _es.conf;
+    vt          = _es.vt;
+    vb          = _es.vb;
+    vertices    = _es.vertices;
+
+    constrainBoundary = _es.constrainBoundary;
+    checkVol          = _es.checkVol;
+    dVTol             = _es.dVTol;
+
+    report       = _es.report;
+    reportId     = _es.reportId;
+    reportPrefix = _es.reportPrefix;
+  }
+
+  // -------------------------------------------------------------------
+  inline void edgeSwapOp::setSwapEdge(pEdge e) 
+  {
+    edge = e;
+    results->reset();
+    conf = -1;
+    checkVol = false;
+  }
+  
+  // -------------------------------------------------------------------
+  inline void edgeSwapOp::swapOnBoundary(bool eswapob, double dV)
+  {
+    constrainBoundary = !eswapob;
+    dVTol = dV;
+  }
+}
+// -------------------------------------------------------------------
+#endif
diff --git a/Adapt/operator/FaceCollapseOp.cc b/Adapt/operator/FaceCollapseOp.cc
new file mode 100644
index 0000000..6d48dc8
--- /dev/null
+++ b/Adapt/operator/FaceCollapseOp.cc
@@ -0,0 +1,495 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Olivier Pierard, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "FaceCollapseOp.h"
+#include "OperatorTools.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  bool faceCollapseOp::checkConstraints() const
+  {
+    // find the opposite vertex
+    oppV = F_edOpVt(delFace,delEdge);
+
+    if( EN_constrained((pEntity)delEdge)) return false;
+    if( !clpsOnOppV && EN_constrained((pEntity)oppV) ) return false;
+
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool faceCollapseOp::checkGeometry()
+  {
+    pGEntity fGE = F_whatIn(delFace);
+    if( clpsOnOppV )
+      {
+        // delEdge and delFace must have the same classification
+        if( E_whatIn(delEdge) != fGE ) return false;
+      }
+    else
+      {
+        // oppV and delFace must have the same classification
+        if( V_whatIn(oppV) != fGE ) return false;
+      }
+    
+    // It leaves us with two possibilities:
+    // (a) In case ( clpsOnOppV == true ) :
+    //     (1) delFaces and delEdges are classified on a dim 2
+    //     (2) delFaces and delEdges are classified on a dim 3
+    // (b) In case ( clpsOnOppV == false ) :
+    //     (1) delFaces and oppV are classified on a dim 2
+    //     (2) delFaces and oppV are classified on a dim 3
+    // For both (a) and (b):
+    // In case (2) no dimension reduction can occur -> unconditionally valid
+    // In case (1): * if 2D mesh, no dim reduc -> unconditionally valid
+    //              * if 3D mesh, two things to check:
+    //                   A.: check boundaries are not constrained
+    //                       (otherwise ok but checkVol=true)
+    //                   B.: check dimension reduction
+
+    if ( dim == 3 && GEN_type(fGE) == 2 )
+      {
+        // check A
+        if( constrainBoundary ) return false;
+        else checkVol = true;
+            
+        // check B
+        // - Dimension reduction on node (on oppV, case clpsOnOppV=true): as delEdge 
+        //   is classified on dim 2, only one surface (fGE) passes 
+        //   through it. As it is the same as the geom ent of delFace, 
+        //   oppV already touches it -> no node dim reduction.
+        // - Dimension reduction on lines and surfaces:
+        //   occurs if these 2 conditions hold together:
+        //   C1: for one of the regions bounding delFace, the face 
+        //       containing delEdge and which is not delFace is 
+        //       classified on a surface,
+        //   C2: for one of the regions bounding delFace, the edge 
+        //       of the region opposite to delEdge is classified 
+        //       on a dimension < 3 (line contact).
+        //   C2b (surface contact): for one of the regions bounding 
+        //       delFace, one of the 2 other faces is classified on 
+        //       a surface. This is found by Condition 2.
+        // - Dimension reduction occur if these 2 conditions hold together:
+        //   C3: the face has only 1 region,
+        //   C4: there is a face using delEdge which opposite vertex
+        //       is linked to oppV by an edge oppE and oppE is not 
+        //       used by the only region.
+        bool C1 = false, C2 = false;
+        for (int iR=0; iR<2; iR++)
+          {
+            pRegion reg = F_region(delFace,iR);
+            if ( !reg ) continue;
+            
+            // check C1
+            for (int iF=0; iF<4; iF++) {
+              pFace pf = R_face(reg,iF);
+              if ( pf == delFace ) continue;
+              if ( F_inClosure(pf,delEdge) && F_whatInType(pf) == 2 ) C1 = true;
+            }
+
+            // check C2
+            if ( E_whatInType( R_gtOppEdg(reg, delEdge) ) < 3 ) C2 = true;
+          }
+        if ( C1 && C2 ) return false;
+
+        // In case C3 holds
+        if ( F_numRegions(delFace) == 1 )
+          {
+            // check C4
+            pRegion pr = F_region(delFace,0);
+            if ( !pr ) pr = F_region(delFace,1);
+            pPList delEdgeFaces = E_faces(delEdge);
+            void * temp = NULL;
+            pFace pf;
+            while ( ( pf = (pFace) PList_next(delEdgeFaces,&temp) ) )
+              {
+                if ( pf == delFace ) continue;
+                if ( R_inClosure(pr,pf) ) continue;
+                if ( E_exist(oppV, F_edOpVt(pf,delEdge) ) ) {
+                  PList_delete(delEdgeFaces); return false;
+                }
+              }
+            PList_delete(delEdgeFaces);
+          }
+      }
+
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool faceCollapseOp::evaluateShapes()
+  {
+    if( dim != 3 ) return evaluateShapes2D();
+  
+    double worstShape = mqm.getElementEvaluator()->bestShapeEver();
+
+    pRegion delReg[2];
+    delReg[0] = F_region(delFace,0);
+    delReg[1] = F_region(delFace,1);
+
+    double rCoords[4][3];   
+    pMSize rSizes[4] = {NULL, NULL, NULL, NULL};
+
+    double volIn = 0.;
+    double volOut = 0.;
+  
+    // 1°) General case valid for any clpsOnOppV
+  
+    pPList eRegs = E_regions(delEdge);
+    void * temp = NULL;
+    while( pRegion region = (pRegion)PList_next( eRegs, &temp ) ) {   
+    
+      if (checkVol) { volIn += R_volume (region); }
+    
+      if( region==delReg[0] || region==delReg[1] ) continue;
+    
+      // check every tet resulting from the split
+      for( int iR=0; iR<2; iR++ ) {
+      
+        pVertex eV = E_vertex(delEdge,iR);
+      
+        // Loop over all the vertices of region
+        pVertex rV;
+        for( int iRV=0; iRV < R_numVertices(region); iRV++ ) {        
+        
+          rV = R_vertex( region, iRV );
+      
+          if ( rSizes[iRV] ) delete rSizes[iRV];
+        
+          if( rV == eV ) { // Set oppV size and pos. instead of end of delEdge
+            if( clpsOnOppV ) {  // Collapse on oppV
+              double xyz[3]; 
+              V_coord(oppV,xyz);
+              for( int k=0; k<3; k++ ) rCoords[iRV][k] = xyz[k];
+              rSizes[iRV] = sizeField->getSize(oppV);  
+            }
+            else {  // Collapse on newVt
+              for( int k=0; k<3; k++ ) rCoords[iRV][k] = newVPos[k];
+              rSizes[iRV] = sizeField->getSizeOnEntity((pEntity)delEdge,rCoords[iRV]);
+            }
+          }
+          else {
+            rSizes[iRV] = sizeField->getSize(rV);
+            V_coord(rV,rCoords[iRV]);
+          }
+        }
+      
+        // Some cleaning and exit if new element is not acceptable
+        double shape;
+        if( ! mqm.getElementEvaluator()->XYZ_R_shape(rCoords,rSizes,&shape) ) {
+          for (int i=0; i<4; i++) {
+            if ( rSizes[i] ) delete rSizes[i];
+          }
+          PList_delete(eRegs);
+          return false;
+        }
+
+        if( worstShape > shape ) worstShape = shape;
+      
+        if (checkVol) { volOut += R_XYZ_volume(rCoords); }
+      }  // End of loop on sub-tetra
+    }  // End loop on regions around delEdge
+    PList_delete(eRegs);
+  
+    // 2°) Particular case if collapse edge on new vertex; need other checks 
+  
+    if( !clpsOnOppV ) {     
+    
+      // loop over the regions of oppV excepted delReg[0-1]
+      pPList vRegs = V_regions(oppV);
+      void * temp = NULL;
+      while( pRegion region = (pRegion)PList_next(vRegs,&temp) ) {
+    
+        if( region==delReg[0] || region==delReg[1] ) continue;
+      
+        if (checkVol) { volIn += R_volume(region); }
+      
+        pVertex rV;
+        for(int iRV=0; iRV < R_numVertices(region); iRV++) {
+      
+          rV = R_vertex(region, iRV);
+      
+          if ( rSizes[iRV] ) delete rSizes[iRV];
+        
+          if( rV == oppV ) { // Set size and pos. of new vertex on delEdge
+            for(int iC=0; iC<3; iC++) rCoords[iRV][iC] = newVPos[iC];
+            rSizes[iRV] = sizeField->getSizeOnEntity((pEntity)delEdge,rCoords[iRV]);
+          }
+          else {
+            rSizes[iRV] = sizeField->getSize(rV);
+            V_coord(rV,rCoords[iRV]);
+          }
+        }
+      
+        if (checkVol) { volOut += R_XYZ_volume(rCoords); }
+      
+        // Some cleaning and exit if new element is not acceptable
+        double shape;
+        if( ! mqm.getElementEvaluator()->XYZ_R_shape(rCoords,rSizes,&shape) ) {
+          for (int i=0; i<4; i++) {
+            if ( rSizes[i] ) delete rSizes[i];
+          }
+          PList_delete(vRegs);
+          return false;
+        }
+      
+        if( worstShape > shape ) worstShape = shape;
+      
+      }  // End loop on vRegs
+      PList_delete(vRegs);
+    }
+  
+    for (int i=0; i<4; i++) {
+      if ( rSizes[i] ) delete rSizes[i];
+    }
+  
+    results->setWorstShape(worstShape); 
+
+    if (checkVol) {
+      double dV = fabs( (volIn-volOut) / volIn );
+      if( dV > dVTol ) return false;
+    }
+  
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool faceCollapseOp::evaluateShapes2D()
+  {
+    double worstShape = mqm.getElementEvaluator()->bestShapeEver();
+
+    // get the normal to the del face
+    double fNormal[3];
+    F_normal(delFace,fNormal);
+
+    double fCoords[3][3];   
+    pMSize fSizes[3] = {NULL, NULL, NULL};
+  
+    // 1°) General case valid for any clpsOnOppV
+  
+    for( int eF=0; eF < E_numFaces(delEdge); eF++ ) {
+    
+      pFace face = E_face(delEdge, eF);
+    
+      if( face == delFace ) continue;
+
+      for( int iSubF=0; iSubF<2; iSubF++ ) {
+      
+        pVertex eV = E_vertex(delEdge,iSubF);
+      
+        // Loop over all the vertices of face
+        pVertex fV;
+        for( int iFV=0; iFV<F_numVertices(face); iFV++ ) {        
+        
+          fV = F_vertex(face, iFV);
+      
+          if ( fSizes[iFV] ) delete fSizes[iFV];
+        
+          if( fV == eV ) { // Set oppV size and pos. instead of end of delEdge
+            if( clpsOnOppV ) {
+              double xyz[3]; 
+              V_coord(oppV,xyz);
+              for(int k=0; k<3; k++ ) fCoords[iFV][k] = xyz[k];
+              fSizes[iFV] = sizeField->getSize(oppV);  
+            }
+            else {  // Collapse on newVt
+              for(int k=0; k<3; k++) fCoords[iFV][k] = newVPos[k];
+              fSizes[iFV] = sizeField->getSizeOnEntity((pEntity)delEdge,fCoords[iFV]);
+            }
+          }
+          else {
+            V_coord(fV,fCoords[iFV]);
+            fSizes[iFV] = sizeField->getSize(fV);
+          }
+        }
+      
+        // Some cleaning and exit if new element is not acceptable
+        double shape;
+        if( ! mqm.getElementEvaluator()->XYZ_F_shape(fCoords,fSizes,fNormal,&shape) ) {
+          for (int i = 0; i<3; i++) {
+            if ( fSizes[i] ) delete fSizes[i];
+          }
+          return false;
+        }
+      
+        if( worstShape > shape ) worstShape = shape;
+      }  // End of loop on sub-tetra
+    }  // End loop on regions around delEdge
+  
+  
+    // 2°) Particular case if collapse edge on new vertex; need other checks 
+  
+    if( !clpsOnOppV ) {
+    
+      pPList vFaces = V_faces(oppV);
+      void * temp = NULL;
+      while( pFace face = (pFace)PList_next( vFaces, &temp ) ) { 
+    
+        if( face == delFace ) continue;
+      
+        pVertex fV;       
+        for( int k=0; k < F_numVertices(face); k++ ) {
+      
+          fV = F_vertex(face,k);
+      
+          if ( fSizes[k] ) delete fSizes[k];
+        
+          if( fV == oppV ) { // Set size and pos. of new vertex on delEdge
+            for( int iC=0; iC<3; iC++ ) fCoords[k][iC] = newVPos[iC];
+            fSizes[k] = sizeField->getSizeOnEntity((pEntity)delEdge,fCoords[k]);
+          }
+          else {
+            V_coord(fV,fCoords[k]);
+            fSizes[k] = sizeField->getSize(fV);
+          }
+        }
+      
+        // Some cleaning and exit if new element is not acceptable
+        double shape;
+        if( ! mqm.getElementEvaluator()->XYZ_F_shape(fCoords,fSizes,fNormal,&shape) ) {
+          for (int i = 0; i<3; i++) {
+            if ( fSizes[i] ) delete fSizes[i];
+          }
+          return false;
+        }
+      
+        if( worstShape > shape ) worstShape = shape;
+      }  // End loop on vFaces              
+      PList_delete(vFaces);
+    }
+  
+    for (int i = 0; i<3; i++) {
+      if ( fSizes[i] ) delete fSizes[i];
+    }
+  
+    results->setWorstShape(worstShape);
+    
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  void faceCollapseOp::evaluateLengths() const
+  {
+    double minSq = MAdBIG;
+    double maxSq = 0.;
+  
+    // Interpolate the desired size at splitting location (for !clpsOnOppV)
+    pMSize sizeNewV = NULL;
+    if (!clpsOnOppV) {
+      sizeNewV = sizeField->getSizeOnEntity((pEntity)delEdge,newVPos);
+    }
+  
+    // 1°) General case, all faces touching delEdge are modified for both types
+  
+    pFace face;
+    for( int i=0; i<E_numFaces(delEdge); i++ ) {
+    
+      face = E_face(delEdge, i);
+    
+      if( face == delFace ) continue;
+    
+      pVertex vertex = F_edOpVt(face,delEdge);
+    
+      double lenSq;
+      if( clpsOnOppV ) {
+        lenSq = sizeField->SF_VV_lengthSq(oppV,vertex);
+      }
+      else {
+        double vxyz[3];
+        V_coord(vertex,vxyz);
+        pMSize vSize = sizeField->findSize(vertex);
+        lenSq = sizeField->SF_XYZ_lengthSq( newVPos, vxyz, 
+                                            sizeNewV, vSize );
+      }
+
+      if( lenSq > maxSq ) maxSq = lenSq;
+      if( lenSq < minSq ) minSq = lenSq;
+    }
+    
+    // 2°) For type 0 only, all edges touching oppV are affected as well
+    
+    if( !clpsOnOppV ) {
+    
+      for( int j=0; j<V_numEdges( oppV ); j++ )
+        {
+          pVertex vertex = E_otherVertex( V_edge(oppV, j), oppV );
+          double vxyz[3];
+          V_coord(vertex,vxyz);
+          pMSize vSize = sizeField->findSize(vertex);
+          double lenSq = sizeField->SF_XYZ_lengthSq( newVPos, vxyz, 
+                                                     sizeNewV, vSize );
+      
+          if( lenSq > maxSq ) maxSq = lenSq;
+          if( lenSq < minSq ) minSq = lenSq;
+        }          
+    }
+  
+    results->setMaxLenSq(maxSq);
+    results->setMinLenSq(minSq);
+
+    if (sizeNewV) delete sizeNewV;
+  }
+
+  // -------------------------------------------------------------------
+  void faceCollapseOp::getCavity(pPList * cavity) const
+  {
+    if( clpsOnOppV )  // Delete new vertex
+      {
+        if ( dim == 3 ) *cavity = E_regions(delEdge);
+        else            *cavity = E_faces(delEdge);
+      }
+    else  // Delete existing vertex
+      {
+        if ( dim == 3 ) {
+          *cavity = V_regions(oppV);
+          pPList eRegs = E_regions(delEdge);
+          void * temp = 0;
+          while ( pRegion region = (pRegion)PList_next(eRegs,&temp) ) {
+            if ( !PList_inList(*cavity,region) ) PList_append(*cavity,region);
+          }
+          PList_delete(eRegs);
+        }
+        else {
+          *cavity = V_faces(oppV);
+          pPList eFaces = E_faces(delEdge);
+          void * temp = 0;
+          while ( pFace face = (pFace)PList_next(eFaces,&temp) ) {
+            if ( !PList_inList(*cavity,face) ) PList_append(*cavity,face);
+          }
+          PList_delete(eFaces);
+
+        }
+      }
+  }
+
+  // -------------------------------------------------------------------
+  void faceCollapseOp::apply()
+  {
+    pVertex newV = E_split(mesh, delEdge, newVPos);
+  
+
+
+    // determine the edge collapse
+    pEdge edgeDel = E_exist(oppV,newV);
+    pVertex vDel, vTgt;
+    if( clpsOnOppV ) { vDel = newV; vTgt = oppV; } 
+    else             { vDel = oppV; vTgt = newV; }
+
+    E_collapse(mesh,edgeDel,vDel,vTgt);
+
+    HistorySgl::instance().add((int)type(),OPERATOR_APPLY,1);
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/operator/FaceCollapseOp.h b/Adapt/operator/FaceCollapseOp.h
new file mode 100644
index 0000000..12fb2fc
--- /dev/null
+++ b/Adapt/operator/FaceCollapseOp.h
@@ -0,0 +1,127 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Olivier Pierard, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_EDGESPLITCOLLAPSEOP
+#define _H_EDGESPLITCOLLAPSEOP
+
+#include "MAdOperatorBase.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class faceCollapseOp: public MAdOperatorBase
+  {
+  public:
+
+    faceCollapseOp(pMesh, DiscreteSF *);
+    faceCollapseOp(const faceCollapseOp &);
+    ~faceCollapseOp() {}
+
+    operationType type() const { return MAd_FCOLLAPSE; }
+
+    void collapseOnBoundary(bool, double);
+    void reset(pFace, pEdge, bool);
+
+    void getCavity(pPList *) const;
+
+    void apply();
+
+  private:
+
+    bool checkConstraints() const;
+    bool checkGeometry();
+    bool evaluateShapes();
+    bool evaluateShapes2D();
+    void evaluateLengths() const;
+
+  private:
+  
+    pFace delFace;
+    pEdge delEdge;
+    bool clpsOnOppV;
+    mutable pVertex oppV;
+    double newVPos[3];
+
+    bool constrainBoundary;
+    bool checkVol;
+    double dVTol; // tolerance on the relative change of volume
+  };
+
+
+  // -------------------------------------------------------------------
+  inline faceCollapseOp::faceCollapseOp(const faceCollapseOp & _fc):
+    MAdOperatorBase(_fc)
+  {
+    delFace    = _fc.delFace;
+    delEdge    = _fc.delEdge;
+    clpsOnOppV = _fc.clpsOnOppV;
+    oppV       = _fc.oppV;
+    newVPos[0] = _fc.newVPos[0];
+    newVPos[1] = _fc.newVPos[1];
+    newVPos[2] = _fc.newVPos[2];
+    constrainBoundary = _fc.constrainBoundary;
+    checkVol = _fc.checkVol;
+    dVTol = _fc.dVTol;
+  }
+
+  // -------------------------------------------------------------------
+  inline faceCollapseOp::faceCollapseOp(pMesh _m, DiscreteSF * _sf):
+    MAdOperatorBase(_m,_sf)
+  {
+    delFace = NULL;
+    delEdge = NULL;
+    clpsOnOppV = true;
+    oppV = NULL;
+    newVPos[0] = 0.;
+    newVPos[1] = 0.;
+    newVPos[2] = 0.;
+    constrainBoundary = true;
+    checkVol = false;
+    dVTol = MAdTOL;
+  }
+
+  // -------------------------------------------------------------------
+  // pFace: face which would disapear
+  // pEdge: Edge which would be split
+  // clpsOnOppV: Edge collapse type
+  //             True if collapse from SplitEdge to existing vertex
+  //             False if collapse from existing vertex to SplitEdge
+  // -------------------------------------------------------------------
+  inline void faceCollapseOp::reset(pFace face, pEdge edge, 
+                                    bool typeClps)
+  {
+    delFace = face;
+    delEdge = edge;
+    clpsOnOppV = typeClps;
+
+    double Exyz[2][3];
+    V_coord(E_vertex(delEdge,0),Exyz[0]);
+    V_coord(E_vertex(delEdge,1),Exyz[1]);
+  
+    for(int i=0; i<3; i++) {
+      newVPos[i] = 0.5 * ( Exyz[0][i] + Exyz[1][i] );
+    }
+  }
+
+  // -------------------------------------------------------------------
+  inline void faceCollapseOp::collapseOnBoundary(bool cob, double tolerance)
+  {
+    constrainBoundary = !cob;
+    dVTol = tolerance;
+  }
+  
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/operator/FaceSwapOp.cc b/Adapt/operator/FaceSwapOp.cc
new file mode 100644
index 0000000..a21e1bf
--- /dev/null
+++ b/Adapt/operator/FaceSwapOp.cc
@@ -0,0 +1,194 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "FaceSwapOp.h"
+#include "CallBackManager.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  bool faceSwapOp::checkConstraints() const
+  {
+    if ( EN_constrained((pEntity)face) ) return false;
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool faceSwapOp::checkGeometry()
+  {
+    if ( F_whatInType(face) != 3 )       return false;
+    if ( !fRegions[0] || !fRegions[1] )  return false;
+    if ( R_whatIn(fRegions[0]) != R_whatIn(fRegions[1]) ) return false;
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool faceSwapOp::evaluateShapes()
+  {
+    // this case would lead to an edge swap
+    if ( E_exist(fOppVerts[0],fOppVerts[1]) ) return false;
+
+    double worst = mqm.getElementEvaluator()->bestShapeEver();
+
+    pPList r0Verts = R_vertices(fRegions[0]);
+
+    // collect coordinates of the five vertices
+    double xyzR0[4][3];
+    void * temp1 = 0; 
+    int iV = 0;
+    while( pVertex pV = (pVertex)PList_next(r0Verts,&temp1) ) {
+      V_coord(pV,xyzR0[iV]);
+      iV++;
+    }
+    double xyzV1[3];
+    V_coord(fOppVerts[1],xyzV1);
+
+    // calculate worst shape of the three new regions
+    pPList fVerts = F_vertices(face,1);
+    void * temp2 = 0;
+    while( pVertex fVertex = (pVertex)PList_next(fVerts,&temp2) ) {
+
+      double xyzNewR[4][3];
+      pMSize newRSizes[4] = { NULL, NULL, NULL, NULL };
+    
+      void * temp3 = 0;
+      int iR0V = 0;
+      while( pVertex pVR0 = (pVertex)PList_next(r0Verts,&temp3) ) {
+        if(pVR0 == fVertex) { 
+          newRSizes[iR0V] = sizeField->findSize(fOppVerts[1]);
+          for (int iC=0; iC<3; iC++) xyzNewR[iR0V][iC] = xyzV1[iC];
+          iR0V++;
+        }
+        else {
+          newRSizes[iR0V] = sizeField->findSize(pVR0);
+          for (int iC=0; iC<3; iC++) xyzNewR[iR0V][iC] = xyzR0[iR0V][iC];
+          iR0V++;
+        }
+      }
+    
+      double shape;
+      if( !mqm.getElementEvaluator()->XYZ_R_shape(xyzNewR,newRSizes,&shape) ) {
+        PList_delete(fVerts);
+        PList_delete(r0Verts);
+        return false;
+      }
+      if(shape < worst) worst = shape;
+    }
+    PList_delete(fVerts);
+    PList_delete(r0Verts);
+  
+    results->setWorstShape(worst);
+  
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  void faceSwapOp::evaluateLengths() const
+  {
+    double xyz[2][3];
+    pMSize sizes[2] = { NULL, NULL };
+    for(int iV=0; iV<2; iV++) {
+      V_coord(fOppVerts[iV],xyz[iV]);
+      sizes[iV] = sizeField->findSize(fOppVerts[iV]);
+    }
+
+    double min = sizeField->SF_XYZ_lengthSq(xyz[0], xyz[1],
+                                            sizes[0], sizes[1]);
+    double max = min;
+
+    results->setMinLenSq(min);
+    results->setMaxLenSq(max);
+  }
+
+  // -------------------------------------------------------------------
+  void faceSwapOp::getCavity(pPList * cavity) const
+  {
+    *cavity = PList_new();
+    PList_append(*cavity, fRegions[0]);
+    PList_append(*cavity, fRegions[1]);
+  }
+
+  // -------------------------------------------------------------------
+  void faceSwapOp::apply()
+  {
+    pPList newRegions = PList_new();
+
+    // get the geometric entity on which the cavity is classified
+    pGRegion geoEntity = R_whatIn(fRegions[0]);
+
+    // create new edge
+    pEdge newEdge = M_createE(mesh,fOppVerts[0],fOppVerts[1],(pGEntity)geoEntity);
+
+    // create new faces
+    pFace newFaces[3];
+    pPList fVerts = F_vertices(face,1);
+    void * temp = 0;
+    int iF = 0;
+    while ( pVertex pV = (pVertex)PList_next(fVerts,&temp) ) {
+    
+      pEdge fEdges[3];
+      fEdges[0] = E_exist(fOppVerts[0],pV);
+      fEdges[1] = E_exist(pV,fOppVerts[1]);
+      fEdges[2] = newEdge;
+
+      newFaces[iF] = M_createF(mesh,3,fEdges,(pGEntity)geoEntity);
+
+      iF++;
+    }
+
+    pFace boundaryFaces[2][3];
+    for(int iR=0; iR<2; iR++) {
+      for(int iV=0; iV<3; iV++) {
+        boundaryFaces[iR][iV] = R_vtOpFc(fRegions[iR],(pVertex)PList_item(fVerts,iV));
+      }
+    }
+    PList_delete(fVerts);
+
+    // create new regions
+    for (int iR=0; iR<3; iR++) {
+
+      pFace rFaces[4];
+      rFaces[0] = boundaryFaces[0][iR];
+      rFaces[1] = boundaryFaces[1][iR];
+      rFaces[2] = newFaces[(iR+1)%3];
+      rFaces[3] = newFaces[(iR+2)%3];
+
+      pRegion newR = M_createR(mesh,4,rFaces,(pGEntity)geoEntity);
+      PList_append(newRegions, newR);
+    }
+
+    // list deleted regions
+    pPList oldRegions = PList_new();
+    PList_append(oldRegions,fRegions[0]);
+    PList_append(oldRegions,fRegions[1]);
+
+    // call callback functions
+    CallBackManagerSgl::instance().callCallBacks(oldRegions,
+                                                 newRegions,
+                                                 MAd_FSWAP,
+                                                 (pEntity)face);
+    PList_delete(oldRegions);
+    PList_delete(newRegions);
+
+    // delete old cavity
+    M_removeRegion(mesh,fRegions[0]);
+    M_removeRegion(mesh,fRegions[1]);
+    M_removeFace(mesh,face);
+
+    HistorySgl::instance().add((int)type(),OPERATOR_APPLY,1);
+  }
+
+  // -------------------------------------------------------------------
+
+}
+
+
diff --git a/Adapt/operator/FaceSwapOp.h b/Adapt/operator/FaceSwapOp.h
new file mode 100644
index 0000000..8dda9e9
--- /dev/null
+++ b/Adapt/operator/FaceSwapOp.h
@@ -0,0 +1,89 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_FACESWAPOP
+#define _H_FACESWAPOP
+
+#include "MAdOperatorBase.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class faceSwapOp: public MAdOperatorBase
+  {
+  public:
+
+    faceSwapOp(pMesh, DiscreteSF *);
+    faceSwapOp(const faceSwapOp &);
+    ~faceSwapOp() {}
+
+    operationType type() const { return MAd_FSWAP; }
+  
+    void setSwapFace(pFace);
+
+    void getCavity(pPList *) const;
+
+    void apply();
+
+  private:
+
+    bool checkConstraints() const;
+    bool checkGeometry();
+    bool evaluateShapes();
+    void evaluateLengths() const;
+
+  private:
+
+    pFace face;           // face to be swapped
+    pRegion fRegions[2];  // its regions
+    pVertex fOppVerts[2]; // opposite vertices in regions
+  };
+
+  // -------------------------------------------------------------------
+  inline faceSwapOp::faceSwapOp(const faceSwapOp & _fs):
+    MAdOperatorBase(_fs), face(_fs.face)
+  {
+    fRegions[0]  = _fs.fRegions[0];
+    fRegions[1]  = _fs.fRegions[1];
+    fOppVerts[0] = _fs.fOppVerts[0];
+    fOppVerts[1] = _fs.fOppVerts[1];
+  }
+
+  // -------------------------------------------------------------------
+  inline faceSwapOp::faceSwapOp(pMesh _m, DiscreteSF * _sf):
+    MAdOperatorBase(_m,_sf), face(NULL)
+  {
+    fRegions[0]  = NULL;
+    fRegions[1]  = NULL;
+    fOppVerts[0] = NULL;
+    fOppVerts[1] = NULL;
+  }
+
+  // -------------------------------------------------------------------
+  inline void faceSwapOp::setSwapFace(pFace _face)
+  {
+    face = _face;
+
+    for(int iR=0; iR<2; iR++) {
+      fRegions[iR] = F_region(face,iR);
+      if (fRegions[iR]) fOppVerts[iR] = R_fcOpVt(fRegions[iR],face);
+    }
+
+    results->reset();
+  }
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/operator/MAdOperatorBase.cc b/Adapt/operator/MAdOperatorBase.cc
new file mode 100644
index 0000000..11a7d5f
--- /dev/null
+++ b/Adapt/operator/MAdOperatorBase.cc
@@ -0,0 +1,86 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MAdOperatorBase.h"
+#include "MAdOutput.h"
+
+using std::string;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  bool MAdOperatorBase::evaluate(double * worstShape)
+  {
+    results->reset();
+    *worstShape = mqm.getElementEvaluator()->worstShapeEver();
+
+    History& history = HistorySgl::instance();
+
+    // --- check 1: constraints ---
+    if ( !checkConstraints() ) {
+      history.add((int)type(),OP_CHECKCONSTRAINTS,0);
+      return false;
+    } else {
+      history.add((int)type(),OP_CHECKCONSTRAINTS,1);
+    }
+
+    // --- check 2: geometric model ---
+    if ( !checkGeometry() ) {
+      history.add((int)type(),OP_CHECKGEOMETRY,0);
+      return false;
+    } else {
+      history.add((int)type(),OP_CHECKGEOMETRY,1);
+    }
+
+    // --- check 3: elements validity and shapes ---
+    if ( !evaluateShapes() ) {
+      history.add((int)type(),OP_CHECKSHAPES,0);
+      return false;
+    } else {
+      history.add((int)type(),OP_CHECKSHAPES,1);
+    }
+
+    // --- edge lengths ---
+    evaluateLengths();
+  
+    *worstShape = results->getWorstShape();
+
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  void MAdOperatorBase::exportCavity(string filename) const
+  {
+    pPList cavity = PList_new();
+    getCavity(&cavity);
+    if ( dim == 3 ) {
+      void * temp = NULL;
+      pEntity pe;
+      while ( ( pe = PList_next(cavity,&temp) ) ) {
+        if ( EN_type(pe) != 3 ) continue;
+        pRegion pr = (pRegion) pe;
+        pPList rFaces = R_faces(pr);
+        void * temp2 = NULL;
+        pFace face;
+        while ( ( face = (pFace)PList_next(rFaces,&temp2) ) ) {
+          if ( F_whatInType(face) == 2 ) PList_appUnique(cavity,face);
+        }
+        PList_delete(rFaces);
+      }
+    }
+    printPosEntities(cavity,filename,OD_DIMENSION,sizeField);
+    PList_delete(cavity);
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/operator/MAdOperatorBase.h b/Adapt/operator/MAdOperatorBase.h
new file mode 100644
index 0000000..4a2f6f8
--- /dev/null
+++ b/Adapt/operator/MAdOperatorBase.h
@@ -0,0 +1,149 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MADOPERATORBASE
+#define _H_MADOPERATORBASE
+
+#include "MAdDefines.h"
+#include "DiscreteSF.h"
+#include "ElementStatistics.h"
+#include "MeshQualityManager.h"
+#include "Constraint.h"
+#include "History.h"
+
+#include <string>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  typedef class MAdOperatorBase * pMAdOperator;
+
+  // -------------------------------------------------------------------
+  class MAdOperatorBase
+  {
+  public:
+
+    MAdOperatorBase();
+    MAdOperatorBase(const MAdOperatorBase &);
+    MAdOperatorBase(pMesh, DiscreteSF *);
+    virtual ~MAdOperatorBase();
+
+  public:
+
+    virtual operationType type() const = 0;
+
+    void setSizeField(DiscreteSF *);
+
+    double getWorstShape() const;
+    double getMinLenSq()   const;
+    double getMaxLenSq()   const;
+
+    // get a list of all elements that will be modified
+    virtual void getCavity(pPList *) const = 0;
+    void exportCavity(std::string) const;
+
+    // check if the operation can be performed and evaluate it
+    bool evaluate(double *);
+
+    // apply the operation
+    virtual void apply() = 0;
+  
+  private:
+
+    // --- Checks and evaluations ---
+    // ! Supposed to be called in that order !
+
+    // checks the operation regarding the constraints on mesh entities 
+    // and geometric entities
+    virtual bool checkConstraints() const = 0;
+
+    // checks compatibility of the operation with the geometric model
+    virtual bool checkGeometry()   = 0;
+
+    // checks validity of the resulting elements and evaluates their 
+    // shapes (saves the worst)
+    virtual bool evaluateShapes() = 0;
+
+    // evaluates the resulting minimal and maximal edge lengths
+    virtual void evaluateLengths() const = 0;
+
+    // ------------------------------
+
+  protected:
+
+    pMesh mesh;
+    DiscreteSF * sizeField;
+
+    // quality evaluator
+    MeshQualityManager& mqm;
+
+    // storage for the results of the evaluation
+    mutable ElementStatistics * results;
+
+    // mesh dimension
+    int dim;
+
+  };
+
+  // -------------------------------------------------------------------
+  inline MAdOperatorBase::MAdOperatorBase():
+    mesh(NULL), sizeField(NULL), mqm(MeshQualityManagerSgl::instance()), 
+    results(NULL), dim(0)
+  {}
+
+  // -------------------------------------------------------------------
+  inline MAdOperatorBase::MAdOperatorBase(const MAdOperatorBase & _op):
+    mesh(_op.mesh), sizeField(_op.sizeField),
+    mqm(MeshQualityManagerSgl::instance())
+  {
+    results = new ElementStatistics(*(_op.results));
+    dim = _op.dim;
+  } 
+
+  // -------------------------------------------------------------------
+  inline MAdOperatorBase::MAdOperatorBase(pMesh _mesh, DiscreteSF * _sf):
+    mesh(_mesh), sizeField(_sf), mqm(MeshQualityManagerSgl::instance())
+  { 
+    results = new ElementStatistics(); 
+    dim = M_dim(mesh);
+  }
+
+  // -------------------------------------------------------------------
+  inline MAdOperatorBase::~MAdOperatorBase() 
+  {
+    if (results) delete results;
+  }
+
+  // -------------------------------------------------------------------
+  inline void MAdOperatorBase::setSizeField(DiscreteSF * _sf)
+  {
+    sizeField = _sf;
+  }
+
+  // -------------------------------------------------------------------
+  inline double MAdOperatorBase::getWorstShape() const
+  { return results->getWorstShape(); }
+
+  // -------------------------------------------------------------------
+  inline double MAdOperatorBase::getMinLenSq() const
+  { return results->getMinLenSq(); }
+
+  // -------------------------------------------------------------------
+  inline double MAdOperatorBase::getMaxLenSq() const
+  { return results->getMaxLenSq(); }
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/operator/OperatorTools.cc b/Adapt/operator/OperatorTools.cc
new file mode 100644
index 0000000..dd6ea96
--- /dev/null
+++ b/Adapt/operator/OperatorTools.cc
@@ -0,0 +1,651 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Olivier Pierard, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "OperatorTools.h"
+#include "CallBackManager.h"
+#include "MAdMessage.h"
+
+#include <map>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  bool V_setPosition(pVertex vertex, double target[3])
+  {
+    if( EN_constrained((pEntity)vertex) ) return false;
+    CallBackManagerSgl::instance().callCallBackMoves(vertex,target);
+    pPoint point = V_point(vertex);
+    P_setPos(point,target[0],target[1],target[2]);
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  void E_collapse(pMesh mesh, 
+                  pEdge edgeDel, 
+                  pVertex vDel, 
+                  pVertex vTgt)
+  {
+    pPList eRegions = E_regions(edgeDel);
+
+    // --- 2D collapse case ---
+    if( PList_size(eRegions) == 0 ) {
+      PList_delete(eRegions);
+      E_collapseOnGFace(mesh,edgeDel,vDel,vTgt);
+      return;
+    }
+    
+    // --- build the new mesh ---
+
+    pPList newRegions = PList_new();
+    pPList vDelRegions = V_regions(vDel);
+    void * temp = NULL;
+    while ( pRegion region = (pRegion)PList_next(vDelRegions,&temp) )
+      {
+        if( PList_inList(eRegions,(pEntity)region) ) continue;
+        
+        pFace fExt = R_vtOpFc(region,vDel);
+        
+        // create the region
+        pGEntity rGEntity = (pGEntity)R_whatIn(region);
+        pRegion newR = mesh->add_tet(vTgt,F_vertex(fExt,0),F_vertex(fExt,1),F_vertex(fExt,2),rGEntity);
+        PList_append(newRegions, newR);
+      }
+    PList_delete(eRegions);
+
+    // --- classify new boundary entities ---
+    int gDim = E_whatInType(edgeDel);
+
+    // Classify edges on lines
+    if ( gDim == 1 )
+      {
+        pPList vDelEdges = V_edges(vDel);
+        temp = NULL;
+        pEdge pe;
+        int count = 0;
+        while ( ( pe = (pEdge)PList_next(vDelEdges,&temp) ) ) {
+          if ( pe == edgeDel ) continue;
+          if ( E_whatInType(pe) == 1 ) {
+            pGEntity gEdge2 = E_whatIn(pe);
+            pVertex oppV = E_otherVertex(pe,vDel);
+            pEdge newLineEdge = E_exist(vTgt,oppV);
+            E_setWhatIn(newLineEdge,gEdge2);
+            count++;
+          }
+        }
+        PList_delete(vDelEdges);
+        if ( count != 1 ) {
+          V_info(vDel);
+          E_info(edgeDel);
+          MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                      "Count should be equal to 1, count = %d",count);
+          assert (count == 1);
+        }
+      }
+
+    // classify faces on surfaces
+    if ( gDim <= 2 )
+      {
+        pGEntity gFace;
+        pEdge oppE;
+        pFace newSurfaceFace;
+
+        pPList vDelFaces = V_faces(vDel);
+        temp = NULL;
+        pFace pf;
+        while ( ( pf = (pFace)PList_next(vDelFaces,&temp) ) ) {
+          if ( F_inClosure(pf,edgeDel) ) continue;
+          if ( F_whatInType(pf) == 2 ) {
+            gFace          = F_whatIn(pf);
+            oppE           = F_vtOpEd(pf,vDel);
+            newSurfaceFace = F_exist(oppE,vTgt);
+            F_setWhatIn(newSurfaceFace,gFace);
+          }
+        }
+        PList_delete(vDelFaces);
+      }
+
+    // --- call callback functions ---
+    CallBackManagerSgl::instance().callCallBacks(vDelRegions,
+                                                 newRegions,
+                                                 MAd_ECOLLAPSE,
+                                                 (pEntity)vDel);
+    PList_delete(newRegions);
+
+    // --- delete old cavity ---
+    temp = NULL;
+    while ( pRegion region = (pRegion)PList_next(vDelRegions,&temp) ) {
+      M_removeRegion(mesh,region);
+    }
+    PList_delete(vDelRegions);
+
+    pPList vFaces = V_faces(vDel);
+    temp = NULL;
+    while ( pFace face = (pFace)PList_next(vFaces,&temp) ) {
+      M_removeFace(mesh,face);
+    }
+    PList_delete(vFaces);
+
+    pPList vEdges = V_edges(vDel);
+    temp = NULL;
+    while ( pEdge edge = (pEdge)PList_next(vEdges,&temp) ) {
+      M_removeEdge(mesh,edge);
+    }
+    PList_delete(vEdges);
+
+    M_removeVertex(mesh,vDel);
+  }
+    
+
+    
+    /*
+// This is the old way to make a collapse
+
+    pPList eRegions = E_regions(edgeDel);
+
+    // --- 2D collapse case ---
+    if( PList_size(eRegions) == 0 ) {
+      PList_delete(eRegions);
+      E_collapseOnGFace(mesh,edgeDel,vDel,vTgt);
+      return;
+    }
+
+    // --- list faces to be merged ---
+
+    std::map<pFace,pFace> fOldToNew; // deleted face -> corresponding new (or target) face
+    std::map<pFace,bool>  fDirs;     // if direction of (deleted) face has to be changed
+
+    void * temp1 = 0;
+    while ( pRegion region = (pRegion)PList_next(eRegions,&temp1) ) {
+      
+      pFace fDel, fTgt;
+      
+      pPList rFaces = R_faces(region);
+      void * temp2 = 0;
+      while ( pFace face = (pFace)PList_next(rFaces, &temp2) ) {
+        if (!F_inClosure(face,(pEntity)edgeDel)) {
+          if (F_inClosure(face,(pEntity)vDel)) fDel = face;  // deleted face
+          else                                 fTgt = face;  // target face
+        }
+      }
+      PList_delete(rFaces);
+
+      fOldToNew[fDel] = fTgt;
+      
+      // Choose the direction and classification of target face
+      pEdge edge = F_vtOpEd(fDel,vDel);
+      if( F_whatInType(fDel) < F_whatInType(fTgt) ) {
+        F_setWhatIn( fTgt, F_whatIn(fDel) );
+        if( F_dirUsingEdge(fTgt,edge) != F_dirUsingEdge(fDel,edge) ) {
+          F_chDir(fTgt);
+        }
+      }
+      else {
+        if( F_dirUsingEdge(fTgt,edge) == F_dirUsingEdge(fDel,edge) ) {
+          fDirs[fDel] = true;
+        } 
+        else {
+          fDirs[fDel] = false;
+        }
+      }
+    }
+
+    // --- list edges to be merged ---
+
+    std::map<pEdge,pEdge> eOldToNew; // deleted edge -> corresponding new (or target) edge
+    std::map<pEdge,bool>  eDirs;     // if direction of (deleted) edge has to be changed
+
+    pPList eFaces = E_faces(edgeDel);
+    void * temp3 = 0;
+    while ( pFace face = (pFace)PList_next(eFaces,&temp3) ) {
+      
+      pEdge eDel, eTgt;
+
+      pPList fEdges = F_edges(face);
+      void * temp4 = 0;
+      while ( pEdge edge = (pEdge)PList_next(fEdges, &temp4) ) {
+        if ( edge != edgeDel ) {
+          if (E_inClosure(edge,(pEntity)vDel)) eDel = edge;  // deleted edge
+          else                                 eTgt = edge;  // target edge
+        }
+      }
+      PList_delete(fEdges);
+
+      eOldToNew[eDel] = eTgt;
+      
+      // Choose the classification of target edge
+      if( E_whatInType(eDel) < E_whatInType(eTgt) ) {
+        E_setWhatIn( eTgt, E_whatIn(eDel) );
+      }
+
+      // Choose the direction of target edge
+      if( E_vertex(eDel,0) == E_vertex(eTgt,0) ||
+          E_vertex(eDel,1) == E_vertex(eTgt,1) ) {
+        eDirs[eDel] = true;
+      }
+      else {
+        eDirs[eDel] = false;
+      }
+    }
+    PList_delete(eFaces);
+
+    // --- build the new mesh ---
+
+    pPList newRegions = PList_new();
+    pPList vDelRegions = V_regions(vDel);
+    void * temp5 = 0;
+    while ( pRegion region = (pRegion)PList_next(vDelRegions,&temp5) ) {
+
+      if( PList_inList(eRegions,(pEntity)region) ) continue;
+
+      // need to create a new region
+      pFace rFaces[4];
+
+      pFace fExt = R_vtOpFc(region,vDel);
+
+      for(int iF=0; iF<4; iF++) {
+        
+        pFace face = R_face(region,iF);
+
+        if( face == fExt ) {
+          rFaces[iF] = face;
+          continue;
+        }
+        
+        if ( fOldToNew.find(face) != fOldToNew.end() ) {
+          rFaces[iF] = fOldToNew.find(face)->second;
+        }
+        else {
+          // need to create a new face
+          pEdge fEdges[3];
+
+          for(int iE=0; iE<3; iE++ ) {
+
+            pEdge edge = F_edge(face,iE);
+
+            if( F_inClosure(fExt,(pEntity)edge) ) {
+              fEdges[iE] = edge;
+              continue;
+            }
+        
+            if ( eOldToNew.find(edge) != eOldToNew.end() ) {
+              fEdges[iE] = eOldToNew.find(edge)->second;
+            }
+            else {
+              // need to create a new edge
+
+              pVertex eVertices[2];
+              for(int iV=0; iV<2; iV++) {
+                pVertex pV = E_vertex(edge,iV);
+                if( pV == vDel ) eVertices[iV] = vTgt;
+                else             eVertices[iV] = pV;
+              }
+          
+              // create the edge
+              pGEntity eGEntity = E_whatIn(edge);
+              fEdges[iE] = M_createE(mesh, eVertices[0], eVertices[1], eGEntity);
+              eOldToNew[edge] = fEdges[iE];
+            }
+          }
+      
+          // create the face
+          pGEntity fGEntity = F_whatIn(face);
+          rFaces[iF] = M_createF(mesh, 3, fEdges, fGEntity);
+          fOldToNew[face] = rFaces[iF];
+        }
+      }
+
+      // create the region
+      pGEntity rGEntity = (pGEntity)R_whatIn(region);
+      pRegion newRegion = M_createR(mesh, 4, rFaces, rGEntity);
+      PList_append(newRegions, newRegion);
+    }
+
+    PList_delete(eRegions);
+
+    // --- call callback functions ---
+    CallBackManagerSgl::instance().callCallBacks(vDelRegions,
+                                                 newRegions,
+                                                 MAd_ECOLLAPSE,
+                                                 (pEntity)vDel);
+    PList_delete(newRegions);
+
+    // --- delete old cavity ---
+    void * temp = 0;
+    while ( pRegion region = (pRegion)PList_next(vDelRegions,&temp) ) {
+      M_removeRegion(mesh,region);
+    }
+    PList_delete(vDelRegions);
+
+    pPList vFaces = V_faces(vDel);
+    temp = 0;
+    while ( pFace face = (pFace)PList_next(vFaces,&temp) ) {
+      M_removeFace(mesh,face);
+    }
+    PList_delete(vFaces);
+
+    pPList vEdges = V_edges(vDel);
+    temp = 0;
+    while ( pEdge edge = (pEdge)PList_next(vEdges,&temp) ) {
+      M_removeEdge(mesh,edge);
+    }
+    PList_delete(vEdges);
+
+    M_removeVertex(mesh,vDel);
+
+    */
+
+  // -------------------------------------------------------------------
+  void E_collapseOnGFace(pMesh mesh, 
+                         pEdge edgeDel, 
+                         pVertex vDel, 
+                         pVertex vTgt)
+  {
+    // --- list edges to be merged ---
+
+    std::map<pEdge,pEdge> eOldToNew; // deleted edge -> corresponding new (or target) edge
+    std::map<pEdge,bool>  eDirs;     // if direction of (deleted) edge has to be changed
+
+    pPList eFaces = E_faces(edgeDel);
+    void * temp1 = 0;
+    while ( pFace face = (pFace)PList_next(eFaces,&temp1) ) {
+      
+      pEdge eDel, eTgt;
+
+      pPList fEdges = F_edges(face);
+      void * temp2 = 0;
+      while ( pEdge edge = (pEdge)PList_next(fEdges, &temp2) ) {
+        if ( edge != edgeDel ) {
+          if (E_inClosure(edge,(pEntity)vDel)) eDel = edge;  // deleted edge
+          else                                 eTgt = edge;  // target edge
+        }
+      }
+      PList_delete(fEdges);
+
+      eOldToNew[eDel] = eTgt;
+      
+      // Choose the classification of target edge
+      if( E_whatInType(eDel) < E_whatInType(eTgt) ) {
+        E_setWhatIn( eTgt, E_whatIn(eDel) );
+      }
+
+      // Choose the direction of target edge
+      if( E_vertex(eDel,0) == E_vertex(eTgt,0) ||
+          E_vertex(eDel,1) == E_vertex(eTgt,1) ) {
+        eDirs[eDel] = true;
+      }
+      else {
+        eDirs[eDel] = false;
+      }
+    }
+
+    // --- build the new mesh ---
+
+    pPList newFaces = PList_new();
+    pPList vDelFaces = V_faces(vDel);
+    void * temp3 = 0;
+    while ( pFace face = (pFace)PList_next(vDelFaces,&temp3) ) {
+
+      if( PList_inList(eFaces,(pEntity)face) ) continue;
+
+      // need to create a new face
+      pEdge fEdges[3];
+
+      pEdge eExt = F_vtOpEd(face,vDel);
+
+      for(int iE=0; iE<3; iE++ ) {
+
+        pEdge edge = F_edge(face,iE);
+
+        if( edge == eExt ) {
+          fEdges[iE] = edge;
+          continue;
+        }
+        
+        if ( eOldToNew.find(edge) != eOldToNew.end() ) {
+          fEdges[iE] = eOldToNew.find(edge)->second;
+        }
+        else {
+          // need to create a new edge
+
+          pVertex eVertices[2];
+          for(int iV=0; iV<2; iV++) {
+            pVertex pV = E_vertex(edge,iV);
+            if( pV == vDel ) eVertices[iV] = vTgt;
+            else             eVertices[iV] = pV;
+          }
+          
+          // create the edge
+          pGEntity eGEntity = E_whatIn(edge);
+          fEdges[iE] = M_createE(mesh, eVertices[0], eVertices[1], eGEntity);
+          eOldToNew[edge] = fEdges[iE];
+        }
+      }
+      
+      // create the face
+      pGEntity fGEntity = F_whatIn(face);
+      pFace newFace = M_createF(mesh, 3, fEdges, fGEntity);
+      PList_append(newFaces,newFace);
+    }
+
+    PList_delete(eFaces);
+
+    // --- call callback functions ---
+    CallBackManagerSgl::instance().callCallBacks(vDelFaces,
+                                                 newFaces,
+                                                 MAd_ECOLLAPSE,
+                                                 (pEntity)vDel);
+    PList_delete(newFaces);
+
+    // --- delete old cavity ---
+    void * temp = 0;
+    while ( pFace face = (pFace)PList_next(vDelFaces,&temp) ) {
+      M_removeFace(mesh,face);
+    }
+    PList_delete(vDelFaces);
+
+    pPList vEdges = V_edges(vDel);
+    temp = 0;
+    while ( pEdge edge = (pEdge)PList_next(vEdges,&temp) ) {
+      M_removeEdge(mesh,edge);
+    }
+    PList_delete(vEdges);
+
+    M_removeVertex(mesh,vDel);
+  }
+
+
+  // -------------------------------------------------------------------
+  pVertex E_split(pMesh mesh, pEdge edge, double xyz[3], double t)
+  {
+    // --- build the vertex ---
+
+    pVertex newV = NULL; // the new vertex
+
+    pGEntity edgeGE = E_whatIn(edge); // its classification
+
+    double u[2][2];
+    u[0][0] = -2.; u[0][1] = -2.; u[1][0] = -2.; u[1][1] = -2.;
+    if ( E_params(edge,u) ) {
+      double uV[2];
+      if ( GEN_type(edgeGE) == 2 ) {
+        GF_centerOnGeodesic( (pGFace)edgeGE, t, u, uV );
+      }
+      else {
+        for (int iP=0; iP<2; iP++)  uV[iP] = (1.-t) * u[0][iP] + t * u[1][iP];
+      }
+      newV = M_createVP(mesh, xyz[0], xyz[1], xyz[2], uV[0], uV[1], -1, edgeGE);
+    }
+    else {
+      newV = M_createV(mesh, xyz[0], xyz[1], xyz[2], -1, edgeGE);
+    }
+
+    // --- build the edges ---
+    pPList newEdges = PList_new();
+    pEdge e1 = M_createE(mesh, E_vertex(edge,0), newV, edgeGE);
+    PList_append(newEdges,e1);
+    pEdge e2 = M_createE(mesh, newV, E_vertex(edge,1), edgeGE);
+    PList_append(newEdges,e2);
+    
+    // --- build the faces bordered by new edges ---
+    pPList newFaces = PList_new();
+    pPList eFaces = E_faces(edge);
+    void * temp = NULL;
+    while( pFace face = (pFace)PList_next(eFaces,&temp) ) {
+
+      pGEntity fGE = F_whatIn(face);
+      pEdge newE = M_createE(mesh, newV, F_edOpVt(face,edge), fGE);
+      
+      int iEdge = 0;
+      for( iEdge=0; iEdge< F_numEdges(face); iEdge++) {
+        if( F_edge(face,iEdge) == edge ) break ;
+      }
+      pEdge fEdges[3];
+      fEdges[0] = edge ;
+      fEdges[1] = F_edge(face,(iEdge+1)%3);
+      fEdges[2] = F_edge(face,(iEdge+2)%3);
+
+      pFace newF1, newF2;
+      if( F_edgeDir(face,iEdge) ) {
+
+        pEdge newFEdges1[3] = {e1, newE, fEdges[2]};
+        newF1 = M_createF(mesh, 3, newFEdges1, fGE);
+        EN_attachDataP((pEntity)fEdges[2],"_EdgeSplitMarker_",(void *)newF1);
+
+        pEdge newFEdges2[3] = {e2, fEdges[1], newE};
+        newF2 = M_createF(mesh, 3, newFEdges2, fGE);
+        EN_attachDataP((pEntity)fEdges[1],"_EdgeSplitMarker_",(void *)newF2);
+      }
+      else {
+        pEdge newFEdges1[3] = {e1, fEdges[1], newE};
+        newF1 = M_createF(mesh, 3, newFEdges1, fGE);
+        EN_attachDataP((pEntity)fEdges[1],"_EdgeSplitMarker_",(void *)newF1); 
+        
+        pEdge newFEdges2[3] = {e2, newE, fEdges[2]};
+        newF2 = M_createF(mesh, 3, newFEdges2, fGE);
+        EN_attachDataP((pEntity)fEdges[2],"_EdgeSplitMarker_",(void *)newF2);
+      }
+      EN_attachDataP((pEntity)face,"_EdgeSplitMarker_",(void *)newE);
+      EN_attachDataP((pEntity)newF1,"_EdgeSplitMarker_",face);
+      EN_attachDataP((pEntity)newF2,"_EdgeSplitMarker_",face);
+      
+      PList_append(newFaces,newF1);
+      PList_append(newFaces,newF2);
+    }
+    
+    pPList delRegs = PList_new();
+    pPList eRegs = E_regions(edge);
+    if (eRegs) {
+
+      temp = NULL;
+      while( pRegion region = (pRegion)PList_next(eRegs, &temp) ) {
+
+        pGEntity rGE = (pGEntity)R_whatIn(region);
+
+        pFace extFaces[2];
+
+        // --- build the new face between the two new regions ---
+        pEdge fEdges[3];
+        for(int iF=0, eCount=0, fCount=0; iF<R_numFaces(region); iF++) {
+          pFace face = R_face(region,iF);
+          if( F_inClosure(face,(pEntity)edge) ) {
+            fEdges[eCount++] = (pEdge)EN_dataP((pEntity)face,"_EdgeSplitMarker_");
+          }
+          else {
+            extFaces[fCount++] = face;
+          }
+        }
+        pEdge oppE = R_gtOppEdg(region,edge);
+        fEdges[2] = oppE;
+        //         if( E_vertex(fEdges[0],1) != E_vertex(fEdges[1],0) && 
+        //             E_vertex(fEdges[0],1) != E_vertex(fEdges[1],1) )  {
+        //           pEdge tmpE = fEdges[1] ;
+        //           fEdges[1] = fEdges[2];
+        //           fEdges[2] = tmpE;
+        //         }
+        pFace newF = M_createF(mesh, 3, fEdges, rGE);
+
+        // -- build the regions ---
+        pFace rFaces[4];
+        
+        rFaces[0] = extFaces[0] ;
+        rFaces[1] = newF;
+        int fIndex = 2;
+        for(int i=0; i<F_numEdges(extFaces[0]); i++) {
+          pEdge tmpE = F_edge(extFaces[0],i);
+          if( tmpE != oppE ) {
+            rFaces[fIndex] = (pFace)EN_dataP((pEntity)tmpE,"_EdgeSplitMarker_");
+            fIndex++;
+          }
+        }
+        M_createR(mesh, 4, rFaces, rGE);
+
+        rFaces[0] = extFaces[1] ;
+        rFaces[1] = newF;
+        fIndex = 2;
+        for( int i=0; i < F_numEdges(extFaces[1]); i++ ) {
+          pEdge tmpE = F_edge(extFaces[1],i);
+          if( tmpE != oppE ) {
+            rFaces[fIndex] = (pFace)EN_dataP((pEntity)tmpE,"_EdgeSplitMarker_");
+            fIndex++;
+          }
+        }
+        M_createR(mesh, 4, rFaces, rGE);
+
+        PList_append(delRegs,region);
+      }
+    }
+    PList_delete(eRegs);
+    
+    pPList delEdge = PList_new();
+    PList_append(delEdge,edge);
+    CallBackManagerSgl::instance().callCallBacks(delEdge, newEdges, 
+                                                 MAd_ESPLIT, (pEntity)newV);
+    PList_delete(delEdge);
+    PList_delete(newEdges);
+    
+    // --- remove regions ---
+    temp = NULL;
+    while( pRegion region = (pRegion)PList_next(delRegs,&temp) ) {
+      M_removeRegion(mesh, region);
+    }
+    PList_delete(delRegs);
+    
+    // --- remove and clean faces ---
+    temp = NULL;
+    while( pFace face = (pFace)PList_next(eFaces,&temp) ) {
+
+      EN_removeData((pEntity)face,"_EdgeSplitMarker_");
+      
+      for(int iE=0; iE<F_numEdges(face); iE++) {
+        pEdge iEdge = F_edge(face,iE);
+        if( iEdge != edge ) EN_removeData((pEntity)iEdge,"_EdgeSplitMarker_");
+      }
+
+      M_removeFace(mesh, face);
+    }
+    PList_delete(eFaces);
+    
+    temp = NULL;
+    while( pFace face = (pFace)PList_next(newFaces,&temp) ) {
+      EN_removeData((pEntity)face,"_EdgeSplitMarker_");
+    }
+    PList_delete(newFaces);
+    
+    // --- remove edge ---
+    M_removeEdge(mesh,edge);
+    
+    return newV ;
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/operator/OperatorTools.h b/Adapt/operator/OperatorTools.h
new file mode 100644
index 0000000..1167260
--- /dev/null
+++ b/Adapt/operator/OperatorTools.h
@@ -0,0 +1,48 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_OPERATORTOOLS
+#define _H_OPERATORTOOLS
+
+#include "MSops.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+
+  bool V_setPosition(pVertex, double[3]);
+
+  // --- Related to edge collapse ---
+
+  void E_collapse(pMesh,   // the mesh
+                  pEdge,   // the edge to be collapsed
+                  pVertex, // the vertex to be deleted
+                  pVertex  // the target vertex
+                  );
+
+  void E_collapseOnGFace(pMesh,   // the mesh
+                         pEdge,   // the edge to be collapsed
+                         pVertex, // the vertex to be deleted
+                         pVertex  // the target vertex
+                         );
+
+  // --- Related to edge split ---
+
+  pVertex E_split(pMesh, pEdge, double[3], double t=0.5); 
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
+
diff --git a/Adapt/operator/RegionRemoveOp.cc b/Adapt/operator/RegionRemoveOp.cc
new file mode 100644
index 0000000..d31503f
--- /dev/null
+++ b/Adapt/operator/RegionRemoveOp.cc
@@ -0,0 +1,184 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "RegionRemoveOp.h"
+#include "CallBackManager.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  bool regionRemoveOp::checkConstraints() const
+  {
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool regionRemoveOp::checkGeometry()
+  {
+    // deny if a vertex is classified on a geometrical edge or vertex
+    int nbClassVerts = 0;
+    pPList rVerts = R_vertices(region);
+    void * temp = NULL;
+    while ( pVertex vert = (pVertex) PList_next(rVerts,&temp) ) {
+      if ( EN_whatInType((pEntity)vert) < 2 ) nbClassVerts++;
+    }
+    PList_delete(rVerts);
+    if ( nbClassVerts != 0 ) return false;
+
+    // deny if an edge is classified on a geometrical edge
+    int nbClassEdges = 0;
+    pPList rEdges = R_edges(region);
+    void * temp2 = NULL;
+    while ( pEdge edge = (pEdge) PList_next(rEdges,&temp2) ) {
+      if ( EN_whatInType((pEntity)edge) < 2 ) nbClassEdges++;
+    }
+    PList_delete(rEdges);
+    if ( nbClassEdges != 0 ) return false;
+
+    int nbExternalFaces = 0;
+    for (int iF=0; iF < 4; iF++) {
+
+      pFace face = R_face(region,iF);
+
+      // see which faces will be deleted
+      if ( F_numRegions(face) == 1 ) {
+        nbExternalFaces++;
+        delFace[iF] = true;
+      }
+      else {
+        delFace[iF] = false;
+      }
+    
+      // see on which geometric entity the new 
+      // boundary faces will be classified
+      pGEntity pGE = EN_whatIn((pEntity)face);
+      if ( GEN_type(pGE) == 2 ) {
+        classifyFaces = true;
+        geoFace = pGE;
+      }
+    }
+    // ensure not to create a hole in a volume
+    if ( nbExternalFaces == 0 ) return false;
+
+    return false;
+  }
+
+  // -------------------------------------------------------------------
+  bool regionRemoveOp::evaluateShapes()
+  {
+    double worstShape = mqm.getElementEvaluator()->bestShapeEver();
+    results->setWorstShape( worstShape );
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  void regionRemoveOp::evaluateLengths() const
+  {
+    results->setMinLenSq(1.);
+    results->setMaxLenSq(1.);
+  }
+
+  // -------------------------------------------------------------------
+  void regionRemoveOp::apply()
+  {
+    // --- classify faces ---
+    if (classifyFaces) {
+      for (int iF=0; iF < 4; iF++) {
+        if ( delFace[iF] == false ) {
+          pFace face = R_face(region,iF);
+          F_setWhatIn(face,geoFace);
+        }
+      }
+    }
+
+    // --- list faces to delete ---
+    pPList delF = PList_new();
+    for (int iF=0; iF < 4; iF++) {
+      if ( delFace[iF] == true ) PList_append(delF,R_face(region,iF));
+    }
+
+    // --- list edges to delete ---
+    pPList delE = PList_new();
+    pPList rEdges = R_edges(region);
+    void * temp = NULL;
+    while ( pEdge edge = (pEdge) PList_next(rEdges,&temp) ) {
+      bool toDel = true;
+      pPList eFaces = E_faces(edge);
+      void * temp2 = NULL;
+      while ( pFace face = (pFace) PList_next(eFaces,&temp2) ) {
+        if ( !PList_inList(delF,face) ) { toDel = false; break; }
+      }
+      PList_delete(eFaces);
+      if (toDel) PList_append(delE,edge);
+    }
+    PList_delete(rEdges);
+
+    // --- list vertices to delete ---
+    pPList delV = PList_new();
+    pPList rVerts = R_vertices(region);
+    void * temp3 = NULL;
+    while ( pVertex vert = (pVertex) PList_next(rVerts,&temp3) ) {
+      bool toDel = true;
+      pPList vEdges = V_edges(vert);
+      void * temp4 = NULL;
+      while ( pEdge edge = (pEdge) PList_next(vEdges,&temp4) ) {
+        if ( !PList_inList(delE,edge) ) { toDel = false; break; }
+      }
+      if (toDel) PList_append(delV,vert);
+    }
+    PList_delete(rVerts);
+  
+
+    // --- call callback functions ---
+    pPList emptyList;
+    pPList delEn = PList_new();
+    void * delTmp = NULL;
+    while ( pFace face = (pFace) PList_next(delF,&delTmp) ) PList_append(delEn,face);
+    delTmp = NULL;
+    while ( pEdge edge = (pEdge) PList_next(delE,&delTmp) ) PList_append(delEn,edge);
+    delTmp = NULL;
+    while ( pVertex vert = (pVertex) PList_next(delV,&delTmp) ) PList_append(delEn,vert);
+    CallBackManagerSgl::instance().callCallBacks(delEn,
+                                                 emptyList,
+                                                 MAd_RREMOVE,
+                                                 region);
+    PList_delete(delEn);
+  
+    // --- delete entities ---
+
+    M_removeRegion(mesh,region);
+
+    void * delTmp2 = NULL;
+    while ( pFace face = (pFace) PList_next(delF,&delTmp2) ) {
+      M_removeFace(mesh,face);
+    }
+
+    delTmp2 = NULL;
+    while ( pEdge edge = (pEdge) PList_next(delE,&delTmp2) ) {
+      M_removeEdge(mesh,edge);
+    }
+
+    delTmp2 = NULL;
+    while ( pVertex vertex = (pVertex) PList_next(delV,&delTmp2) ) {
+      M_removeVertex(mesh,vertex);
+    }
+
+    PList_delete(delF);
+    PList_delete(delE);
+    PList_delete(delV);
+
+    HistorySgl::instance().add((int)type(),OPERATOR_APPLY,1);
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/operator/RegionRemoveOp.h b/Adapt/operator/RegionRemoveOp.h
new file mode 100644
index 0000000..48ba6af
--- /dev/null
+++ b/Adapt/operator/RegionRemoveOp.h
@@ -0,0 +1,87 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_REGIONREMOVEOP
+#define _H_REGIONREMOVEOP
+
+#include "MAdOperatorBase.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class regionRemoveOp: public MAdOperatorBase
+  {
+  public:
+
+    regionRemoveOp(pMesh, DiscreteSF *);
+    regionRemoveOp(const regionRemoveOp &);
+    ~regionRemoveOp() {}
+
+    operationType type() const { return MAd_RREMOVE; }
+  
+    void setRegion(pRegion);
+
+    void getCavity(pPList *) const;
+
+    void apply();
+
+  private:
+
+    bool checkConstraints() const;
+    bool checkGeometry();
+    bool evaluateShapes();
+    void evaluateLengths() const;
+
+  private:
+
+    pRegion region;
+
+    bool classifyFaces;
+    pGEntity geoFace;
+
+    bool delFace[4];
+  };
+
+  // -------------------------------------------------------------------
+  inline regionRemoveOp::regionRemoveOp(const regionRemoveOp & _rr):
+    MAdOperatorBase(_rr), region(_rr.region),
+    classifyFaces(_rr.classifyFaces), geoFace(_rr.geoFace)
+  {
+    for (int i=0; i<4; i++) delFace[i] = _rr.delFace[i];
+  }
+
+  // -------------------------------------------------------------------
+  inline regionRemoveOp::regionRemoveOp(pMesh _m, DiscreteSF * _sf):
+    MAdOperatorBase(_m,_sf), region(NULL),
+    classifyFaces(false), geoFace(NULL)
+  {
+    for (int i=0; i<4; i++) delFace[i] = false;
+  }
+
+  // -------------------------------------------------------------------
+  inline void regionRemoveOp::setRegion(pRegion _region)
+  {
+    region = _region;
+  }
+
+  // -------------------------------------------------------------------
+  inline void regionRemoveOp::getCavity(pPList * cavity) const
+  {
+    PList_append(*cavity,region);
+  }
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/operator/SliverFaceHandler.cc b/Adapt/operator/SliverFaceHandler.cc
new file mode 100644
index 0000000..920c9a7
--- /dev/null
+++ b/Adapt/operator/SliverFaceHandler.cc
@@ -0,0 +1,275 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "SliverFaceHandler.h"
+#include "EdgeSwapOp.h"
+#include "EdgeCollapseOp.h"
+#include "FaceCollapseOp.h"
+#include "MeshParametersManager.h"
+#include "MAdOutput.h"
+
+// standard C/C++
+#include <set>
+using std::set;
+#include <sstream>
+using std::stringstream;
+using std::string;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  void sliverFaceHandler::removeSliverFaces(int* nbSliverIn, int* nbSliverOut)
+  {
+    // --- list all slivers ---
+
+    set<pFace> slivers;
+    if (nbSliverIn) (*nbSliverIn) = 0;
+    FIter fIter = M_faceIter(mesh);
+    while( pFace face = FIter_next(fIter) ) {
+      if ( F_isSliver(face) ) {
+        slivers.insert(face);
+        if (nbSliverIn) (*nbSliverIn)++;
+      }
+    }
+    FIter_delete(fIter);
+
+    // --- iterate on slivers elimination attempts ---
+
+    int iter = 0;
+    int maxIter = 5;
+    bool eliminated = true;
+    *nbSliverOut = *nbSliverIn;
+    while ( ( eliminated       ) && 
+            ( *nbSliverOut > 0 ) && 
+            ( iter < maxIter   ) )  {
+
+      eliminated = false;
+
+      set<pFace> oldSlivers;
+
+      // --- process the slivers list ---
+      set<pFace>::iterator sIter = slivers.begin();
+      set<pFace>::iterator sLast = slivers.end();
+      for (; sIter != sLast; sIter++) {
+
+        pFace sliver = *sIter;
+
+        // --- check if the sliver still exists ---
+        if ( oldSlivers.find(sliver) != oldSlivers.end() ) continue;
+
+        // --- check if the sliver is still a sliver ---
+        if ( !F_isSliver(sliver) ) {
+          oldSlivers.insert(sliver);
+          continue;
+        }
+
+        // --- find an appropriate modification ---
+        pMAdOperator modif = NULL;
+        int result = findOperation(sliver,&modif);
+
+        if ( result <= 0 && reportFailures ) reportSliver(sliver);
+      
+        if ( result >= 1 && modif ) {
+
+          // --- prepare to remove deleted faces from sliver list ---
+          pPList cavity;
+          modif->getCavity(&cavity);
+          void * tmp = 0;
+          while( pFace pf = (pFace)PList_next(cavity,&tmp) ) {
+            oldSlivers.insert(pf);
+          }
+          PList_delete(cavity);
+        
+          // --- eliminate the sliver ---
+          modif->apply();
+          eliminated = true;
+          oldSlivers.insert(sliver);
+        }
+
+        if (modif) delete modif;
+      }
+
+      // --- count remaining and list slivers ---
+      slivers.clear();
+      if (nbSliverOut) (*nbSliverOut) = 0;
+      fIter = M_faceIter(mesh);
+      while( pFace face = FIter_next(fIter) ) {
+        if ( F_isSliver(face) ) {
+          slivers.insert(face);
+          if (nbSliverOut) (*nbSliverOut)++;
+        }
+      }
+      FIter_delete(fIter);
+
+      iter++;
+    }
+  }
+
+  // -------------------------------------------------------------------
+  //  Try to find a modification that eliminates the sliver triangle.
+  //  Return:
+  //    0: no modification found
+  //    1: a modification is found but with a resulting sliver (with better shape)
+  //    2: a modification is found with no remaining sliver
+  int sliverFaceHandler::findOperation(pFace face, 
+                                       pMAdOperator* modification)
+  {  
+    MeshParametersManager& mpm = MeshParametersManagerSgl::instance();
+
+    *modification = NULL;
+
+    double bestShape = 0.;
+    mqm.getShape(face,0,&bestShape);
+
+    if ( bestShape >= mpm.getSliverTriBound() ) {
+      printf ("Warning: processing a face which is not a sliver in findOperation\n");
+      return 0;
+    }
+
+    // check edge swaps
+    // -----------------
+
+    edgeSwapOp eSwap(mesh,sizeField);
+//     if( collapseOnBdry )  eSwap.setCheckVolume(0.,dATol);
+  
+    for (int i=0; i<3; i++) {
+  
+      eSwap.setSwapEdge(F_edge(face,i));
+    
+      double worst;
+      if ( eSwap.evaluate(&worst) && worst > bestShape ) {
+        bestShape = worst;
+        if (*modification) delete *modification;
+        *modification = new edgeSwapOp(eSwap);
+        if (bestShape > mpm.getSliverTriBound()) return 2;
+      }
+    }
+
+    // check edge collapses
+    // ---------------------
+
+    edgeCollapseOp eCollapse(mesh,sizeField);
+    eCollapse.collapseOnBoundary(collapseOnBdry,dATol);
+
+    for(int i=0; i<3; i++) {
+    
+      pEdge edge = F_edge(face,i);
+    
+      for (int j=0; j<2; j++) {
+      
+        eCollapse.setCollapseEdge(edge,E_vertex(edge,j),E_vertex(edge,(j+1)%2));
+ 
+        double worst;
+        if (eCollapse.evaluate(&worst) && worst > bestShape ) {
+          bestShape = worst;
+          if (*modification) delete *modification;
+          *modification = new edgeCollapseOp(eCollapse);
+          if (bestShape > mpm.getSliverTriBound()) return 2;
+          //         if (bestShape > mpm.getSliverTriBound()) { printf("Applied edge collapse\n"); return 2;}
+        }
+      }
+    }
+
+    // check face collapse
+    // --------------------
+
+    if ( addNodes )
+      {
+        faceCollapseOp fCollapse(mesh,sizeField);
+        fCollapse.collapseOnBoundary(collapseOnBdry,dATol);
+        
+        for(int iE=0; iE<3; iE++) {
+          
+          pEdge edge = F_edge(face,iE);
+          
+          for (int iDir=0; iDir<2; iDir++) {
+            
+            fCollapse.reset(face,edge,(bool)iDir);
+            
+            double worst;
+            if (fCollapse.evaluate(&worst) && worst > bestShape ) {
+              bestShape = worst;
+              if (*modification) delete *modification;
+              *modification = new faceCollapseOp(fCollapse);
+              if (bestShape > mpm.getSliverTriBound()) return 2;
+              //         if (bestShape > mpm.getSliverTriBound()) { printf("Applied face collapse\n"); return 2;}
+            }
+          }
+        }
+      }
+
+    if( *modification )  return 1;
+
+    return 0;
+  }
+
+  // -------------------------------------------------------------------
+  bool sliverFaceHandler::F_isSliver(pFace face)
+  {
+    MeshParametersManager& mpm = MeshParametersManagerSgl::instance();
+
+    double shape;
+    mqm.getShape(face,0,&shape);
+
+    if( shape < mpm.getSliverTriBound() ) 
+      return true;
+
+    return false;
+  }
+
+  // -------------------------------------------------------------------
+  bool sliverFaceHandler::F_isSliver(pFace face, double * shape)
+  {
+    MeshParametersManager& mpm = MeshParametersManagerSgl::instance();
+
+    mqm.getShape(face,0,shape);
+
+    if( *shape < mpm.getSliverTriBound() ) 
+      return true;
+
+    return false;
+  }
+
+  // -------------------------------------------------------------------
+  void sliverFaceHandler::reportSliver(pFace face)
+  {
+    stringstream ss;
+    string idStr;  ss << reportId;  ss >> idStr;
+
+    string name = reportPrefix + "sliver" + idStr + ".pos";
+  
+    pPList cavity = PList_new();
+
+    PList_append(cavity,face);
+  
+    for (int iV=0; iV<F_numVertices(face); iV++) {
+
+      pVertex vertex = F_vertex(face, iV);
+    
+      pPList vFaces = V_faces(vertex);
+      void * temp = 0;
+      while ( pFace pf = (pFace)PList_next(vFaces,&temp) ) {
+        PList_appUnique(cavity,pf);
+      }
+      PList_delete(vFaces);
+    }
+
+    printPosEntities(cavity,name.c_str(),OD_MEANRATIO,sizeField);
+
+    PList_delete(cavity);
+
+    reportId++;
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/operator/SliverFaceHandler.h b/Adapt/operator/SliverFaceHandler.h
new file mode 100644
index 0000000..53287a0
--- /dev/null
+++ b/Adapt/operator/SliverFaceHandler.h
@@ -0,0 +1,111 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_SLIVERFACEHANDLER
+#define _H_SLIVERFACEHANDLER
+
+#include "MAdOperatorBase.h"
+
+#include <string>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class sliverFaceHandler {
+
+  public:
+
+    sliverFaceHandler(pMesh, DiscreteSF *);
+    ~sliverFaceHandler() {}
+
+  public:
+
+    void removeSliverFaces(int * nbIn=NULL, int * nbOut=NULL);
+
+    void setSizeField(DiscreteSF *);
+
+    // whether we can use operations on boundaries
+    void collapseOnBoundary(bool, double);
+
+    // whether we can use operations that add nodes
+    void newVertexPermission(bool);
+    bool getNewVertexPermission() const { return addNodes; }
+
+    void enableReport(std::string);
+
+  private:
+
+    int findOperation(pFace, pMAdOperator *);
+
+    bool F_isSliver(pFace);
+    bool F_isSliver(pFace, double *);
+
+    void reportSliver(pFace);
+
+  private:
+
+    pMesh mesh;
+    DiscreteSF * sizeField;
+    MeshQualityManager& mqm;
+
+    bool collapseOnBdry;
+    double dATol;
+
+    bool addNodes; // whether or not we can use operators that add nodes 
+                   // (edge split)
+
+    bool   reportFailures;
+    int    reportId;
+    std::string reportPrefix;
+
+  };
+
+  // -------------------------------------------------------------------
+  inline sliverFaceHandler::sliverFaceHandler(pMesh m, DiscreteSF * sf):
+    mesh(m),sizeField(sf), mqm(MeshQualityManagerSgl::instance()), 
+    collapseOnBdry(false), dATol(MAdTOL), addNodes(true), 
+    reportFailures(false),reportId(0),reportPrefix("")
+  {}
+
+  // -------------------------------------------------------------------
+  inline void sliverFaceHandler::setSizeField(DiscreteSF * sf)
+  {
+    sizeField = sf;
+  }
+
+  // -------------------------------------------------------------------
+  inline void sliverFaceHandler::collapseOnBoundary(bool cob, double tolerance)
+  {
+    collapseOnBdry = cob;
+    dATol = tolerance;
+  }
+
+  // -------------------------------------------------------------------
+  inline void sliverFaceHandler::newVertexPermission(bool allow)
+  {
+    addNodes = allow;
+  }
+
+  // -------------------------------------------------------------------
+  inline void sliverFaceHandler::enableReport(std::string prefix)
+  {
+    reportFailures = true; 
+    reportPrefix   = prefix;
+  }
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
+
diff --git a/Adapt/operator/SliverRegionHandler.cc b/Adapt/operator/SliverRegionHandler.cc
new file mode 100644
index 0000000..ddac9d6
--- /dev/null
+++ b/Adapt/operator/SliverRegionHandler.cc
@@ -0,0 +1,1221 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "SliverRegionHandler.h"
+#include "EdgeSplitOp.h"
+#include "EdgeCollapseOp.h"
+#include "FaceCollapseOp.h"
+#include "DESCOp.h"
+#include "EdgeSwapOp.h"
+#include "FaceSwapOp.h"
+#include "VertexMoveOp.h"
+#include "MeshParametersManager.h"
+#include "MAdOutput.h"
+#include "MathUtils.h"
+
+#include <sstream>
+using std::stringstream;
+using std::set;
+using std::ostream;
+using std::string;
+using std::endl;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  void sliverRegionHandler::removeSliverRegions(int* nbSliverIn, int* nbSliverOut)
+  {
+    // --- list all slivers ---
+
+    set<pRegion> slivers;
+    if (nbSliverIn) (*nbSliverIn) = 0;
+    RIter rIter = M_regionIter(mesh);
+    while( pRegion region = RIter_next(rIter) ) {
+      if ( R_isSliver(region) ) {
+        slivers.insert(region);
+        if (nbSliverIn) (*nbSliverIn)++;
+      }
+    }
+    RIter_delete(rIter);
+
+    // --- iterate on slivers elimination attempts ---
+
+    int iter = 0;
+    int maxIter = 5;
+    bool eliminated = true;
+    *nbSliverOut = *nbSliverIn;
+    while ( ( eliminated       ) && 
+            ( *nbSliverOut > 0 ) && 
+            ( iter < maxIter   ) )  {
+
+      eliminated = false;
+
+      set<pRegion> oldSlivers;
+
+      // --- process the slivers list ---
+      set<pRegion>::iterator sIter = slivers.begin();
+      set<pRegion>::iterator sLast = slivers.end();
+      for (; sIter != sLast; sIter++) {
+
+        pRegion sliver = *sIter;
+
+        // --- check if the sliver still exists ---
+        if ( oldSlivers.find(sliver) != oldSlivers.end() ) continue;
+
+        // --- check if the sliver is still a sliver ---
+        if ( !R_isSliver(sliver) ) {
+          oldSlivers.insert(sliver);
+          continue;
+        }
+
+        // --- find an appropriate modification ---
+        pMAdOperator modif = NULL;
+        int result = findOperation(sliver,&modif);
+
+        if ( testOperators ) testOperations(sliver);
+
+        if ( result <= 0 && reportFailures ) reportSliver(sliver);
+      
+        if ( result >= 1 ) {
+
+          assert(modif);
+
+          // --- prepare to remove deleted regions from sliver list ---
+          pPList affReg;
+          modif->getCavity(&affReg);
+          void * tmp = 0;
+          while( pRegion pr = (pRegion)PList_next(affReg,&tmp) ) {
+            oldSlivers.insert(pr);
+          }
+          PList_delete(affReg);
+        
+          // --- eliminate the sliver ---
+          modif->apply();
+          eliminated = true;
+          oldSlivers.insert(sliver);
+        }
+
+        if (modif) delete modif;
+      }
+
+      // --- count remaining and list slivers ---
+      slivers.clear();
+      if (nbSliverOut) (*nbSliverOut) = 0;
+      rIter = M_regionIter(mesh);
+      while( pRegion region = RIter_next(rIter) ) {
+        if ( R_isSliver(region) ) {
+          slivers.insert(region);
+          if (nbSliverOut) (*nbSliverOut)++;
+        }
+      }
+      RIter_delete(rIter);
+
+      iter++;
+    }
+  }
+
+  // -------------------------------------------------------------------
+  //  Try to find an operation that eliminates the sliver.
+  //  Returns:
+  //    0: no modification found
+  //    1: a modification is found but with a resulting sliver (with better shape)
+  //    2: a modification is found with no remaining sliver
+  int sliverRegionHandler::findOperation(pRegion region, 
+                                         pMAdOperator* operation)
+  {  
+    MeshParametersManager& mpm = MeshParametersManagerSgl::instance();
+
+    *operation = NULL;
+
+    double bestShape = 0.;
+    mqm.getShape(region,&bestShape);
+
+    if ( bestShape >= mpm.getSliverTetBound() ) {
+      printf ("Warning: processing a tet which is not a sliver in handleSliverTet\n");
+      return 0;
+    }
+
+    edgeCollapseOp eCollOp (mesh,sizeField);
+    eCollOp.collapseOnBoundary(collapseOnBdry,dVTolClps);
+
+    faceCollapseOp fCollOp (mesh,sizeField);
+    fCollOp.collapseOnBoundary(collapseOnBdry,dVTolClps);
+
+    edgeSwapOp     eSwapOp (mesh,sizeField);
+    eSwapOp.swapOnBoundary(swapOnBdry,dVTolSwap);
+
+    DESCOp         descOp  (mesh,sizeField);
+    edgeSplitOp    eSplitOp(mesh,sizeField);
+    faceSwapOp     fSwapOp (mesh,sizeField);
+    vertexMoveOp   vMoveOp (mesh,sizeField,false);
+
+    pEntity keyEnts[4];
+    int sType = getSliverType(region, keyEnts);
+    if( sType == 0 ) return 0;
+
+    double worst;
+
+    // --- TYPE I slivers ---
+    if( sType == 1 ) 
+      {
+#ifdef MAKESTATS
+        numTypeI_In++;
+#endif
+
+        // check split 
+        // ------------
+        if ( addNodes ) {
+          for(int i=0; i<2; i++) {
+#ifdef MAKESTATS
+            numSplitTested_I++;
+#endif
+            eSplitOp.setSplitEdge((pEdge)keyEnts[i]);
+        
+            if( E_whatInType((pEdge)keyEnts[i]) != 3 ) continue;
+
+            // determine the position of the new vertex
+//             double newPos[3];
+//             E_cavityCenter( (pEdge)keyEnts[i], newPos );
+//             double t = E_linearParams((pEdge)keyEnts[i],newPos);
+//             if( t>1. || t<0. ) continue;
+//             eSplitOp.setSplitPos(newPos);
+
+            worst = -1.;
+            if( eSplitOp.evaluate(&worst) && worst > bestShape &&
+                eSplitOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+                eSplitOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+              bestShape = worst;
+              if(*operation) delete *operation;
+              *operation = new edgeSplitOp(eSplitOp);
+#ifdef MAKESTATS
+              numSplitAvailable_I++;
+              if (bestShape < mpm.getSliverTetBound()) numSplitToSliver_I++;
+#endif
+              if (bestShape > mpm.getSliverTetBound()) break;
+            }
+          }
+          if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+            numSplitOperated_I++;
+#endif
+            return 2;
+          }
+        }
+
+        // check edge collapses
+        // ---------------------
+        for(int i=0; i<6; i++) {
+          pEdge edge = R_edge(region,i);
+          for (int j=0; j<2; j++) {
+#ifdef MAKESTATS
+            numEClpsTested_I++;
+#endif
+            eCollOp.setCollapseEdge(edge,E_vertex(edge,j),E_vertex(edge,1-j));
+
+            worst = -1.;
+            if ( eCollOp.evaluate(&worst) && worst > bestShape &&
+                 eCollOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+                 eCollOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+              bestShape = worst;
+              if (*operation) delete *operation;
+              *operation = new edgeCollapseOp(eCollOp);
+#ifdef MAKESTATS
+              numEClpsAvailable_I++;
+              if (worst < mpm.getSliverTetBound()) numEClpsToSliver_I++;
+#endif 
+              if (bestShape > mpm.getSliverTetBound()) break;
+            }
+          }
+          if (bestShape > mpm.getSliverTetBound()) break;
+        }
+        if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+          numEClpsOperated_I++;
+#endif
+          return 2;
+        }
+
+        // check double edge split collapse
+        // ---------------------------------
+        if ( addNodes ) {
+          for(int i=0; i<2; i++) {
+#ifdef MAKESTATS
+            numDESCTested_I++;
+#endif
+            descOp.setDESC(region,(pEdge)keyEnts[i%2],(pEdge)keyEnts[(i+1)%2]);
+
+            worst = -1.;
+            if( descOp.evaluate(&worst) && worst > bestShape &&
+                descOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+                descOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+              bestShape = worst;
+              if(*operation) delete *operation;
+              *operation = new DESCOp(descOp);
+#ifdef MAKESTATS
+              numDESCAvailable_I++;
+              if (worst < mpm.getSliverTetBound()) numDESCToSliver_I++;
+#endif
+            }
+            if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+              numDESCOperated_I++;
+#endif
+              return 2;          
+            }
+          }
+        }
+
+        // check face collapse
+        // --------------------
+        if ( addNodes ) {
+          for(int i=0; i<2; i++) {
+            for( int ClpsOnvt=1; ClpsOnvt>=0; ClpsOnvt-- ) {
+#ifdef MAKESTATS
+              numFClpsTested_I++;
+#endif
+              fCollOp.reset((pFace)keyEnts[i+2],(pEdge)keyEnts[i], ClpsOnvt);
+  
+              worst = -1.;
+              if( fCollOp.evaluate(&worst) && worst > bestShape &&
+                  fCollOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+                  fCollOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+                bestShape = worst;
+                if (*operation) delete *operation;
+                *operation = new faceCollapseOp(fCollOp); 
+#ifdef MAKESTATS
+                numFClpsAvailable_I++;
+                if (worst < mpm.getSliverTetBound()) {
+                  numFClpsToSliver_I++;
+                }
+#endif
+                if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+                  numFClpsOperated_I++;
+#endif
+                  return 2;
+                }
+              }
+            }
+          }
+        }
+      
+        // check edge swaps
+        // -----------------
+        for(int i=0; i<2; i++) {
+#ifdef MAKESTATS
+          numSwapTested_I++;
+#endif
+          eSwapOp.setSwapEdge((pEdge)keyEnts[i]);
+
+          worst = -1.;
+          if( eSwapOp.evaluate(&worst) && worst > bestShape &&
+              eSwapOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+              eSwapOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+            bestShape = worst;
+            if (*operation) delete *operation;
+            *operation = new edgeSwapOp(eSwapOp); 
+#ifdef MAKESTATS
+            numSwapAvailable_I++;
+            if (worst < mpm.getSliverTetBound()) numSwapToSliver_I++;
+#endif
+            if (bestShape > mpm.getSliverTetBound()) break;
+          }
+        }
+        if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+          numSwapOperated_I++;
+#endif
+          return 2;
+        }
+
+        // check vertex move 
+        // ------------------
+        pPList verts = R_vertices(region);
+        void * temp = NULL;
+        while ( pVertex pv = (pVertex)PList_next(verts,&temp) ) {
+#ifdef MAKESTATS
+          numVMoveTested_I++;
+#endif
+          if( V_whatInType(pv) != 3 ) continue;
+        
+          vMoveOp.setPositionToOptimal(pv);
+
+          worst = -1.;
+          if( vMoveOp.evaluate(&worst) && worst > bestShape &&
+              vMoveOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+              vMoveOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+            bestShape = worst;
+            if(*operation) delete *operation;
+            *operation = new vertexMoveOp(vMoveOp);
+#ifdef MAKESTATS
+            numVMoveAvailable_I++;
+            if (bestShape < mpm.getSliverTetBound()) numVMoveToSliver_I++;
+#endif
+          }
+        }
+        PList_delete(verts);
+        if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+          numVMoveOperated_I++;
+#endif
+          return 2;
+        }
+        
+
+#ifdef MAKESTATS
+        if( *operation ) {
+          switch ((*operation)->type()) {
+          case MAd_ECOLLAPSE:  { numEClpsOperated_I++; break; }
+          case MAd_ESWAP:      { numSwapOperated_I++;  break; }
+          case MAd_FCOLLAPSE:  { numFClpsOperated_I++; break; }
+          case MAd_DESPLTCLPS: { numDESCOperated_I++;  break; }
+          case MAd_ESPLIT:     { numSplitOperated_I++; break; }
+          case MAd_VERTEXMOVE: { numVMoveOperated_I++; break; }
+          default: throw;
+          }
+        }
+#endif
+
+        if( *operation )  return 1;
+
+#ifdef MAKESTATS
+        set<pRegion>::const_iterator sIter = sliversOut.find(region);
+        if (sIter == sliversOut.end() ) {
+          sliversOut.insert(region);
+          numTypeI_Out++;
+        }
+#endif
+      }
+
+    // --- TYPE II slivers ---
+    else 
+      {
+#ifdef MAKESTATS
+        numTypeII_In++;
+#endif
+
+        // check edge collapses
+        // ---------------------
+        for(int i=0; i<6; i++) {
+#ifdef MAKESTATS
+          numEClpsTested_II++;
+#endif
+          pEdge edge = R_edge(region,i);
+          for (int j=0; j<2; j++) {
+            eCollOp.setCollapseEdge(edge,E_vertex(edge,j),E_vertex(edge,(j+1)%2));
+
+            worst = -1.;
+            if( eCollOp.evaluate(&worst) && worst > bestShape &&
+                eCollOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+                eCollOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+              bestShape = worst;
+              if (*operation) delete *operation;
+              *operation = new edgeCollapseOp(eCollOp);
+#ifdef MAKESTATS
+              numEClpsAvailable_II++;
+              if (worst < mpm.getSliverTetBound()) numEClpsToSliver_II++;
+#endif 
+              if (bestShape > mpm.getSliverTetBound()) break;
+            }
+          }
+          if (bestShape > mpm.getSliverTetBound()) break;
+        }
+        if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+          numEClpsOperated_II++;
+#endif
+          return 2;
+        }
+
+        // check face collapse
+        // --------------------
+        if ( addNodes ) {
+          for( int ClpsOnvt=1; ClpsOnvt>=0; ClpsOnvt-- ) {
+#ifdef MAKESTATS
+            numFClpsTested_II++;
+#endif
+            fCollOp.reset((pFace)keyEnts[2],(pEdge)keyEnts[1], ClpsOnvt);
+  
+            worst = -1.;
+            if( fCollOp.evaluate(&worst) && worst > bestShape &&
+                fCollOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+                fCollOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+              bestShape = worst;
+              if (*operation) delete *operation;
+              *operation = new faceCollapseOp(fCollOp);
+#ifdef MAKESTATS
+              numFClpsAvailable_II++;
+              if (bestShape < mpm.getSliverTetBound()) numFClpsToSliver_II++;
+#endif
+            }
+            if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+              numFClpsOperated_II++;
+#endif
+              return 2;
+            }
+          }
+        }
+
+        // check edge swaps
+        // -----------------
+        for(int i=0; i<3; i++) {
+#ifdef MAKESTATS
+          numSwapTested_II++;
+#endif
+          pEdge edge = F_edge((pFace)keyEnts[0],i);
+          eSwapOp.setSwapEdge(edge); 
+
+          worst=-1.;
+          if( eSwapOp.evaluate(&worst) && worst > bestShape &&
+              eSwapOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+              eSwapOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+            bestShape = worst;
+            if (*operation) delete *operation;
+            *operation = new edgeSwapOp(eSwapOp); 
+#ifdef MAKESTATS
+            numSwapAvailable_II++;
+            if (worst < mpm.getSliverTetBound()) numSwapToSliver_II++;
+#endif
+            if (bestShape > mpm.getSliverTetBound()) break;
+          }
+        }
+        if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+          numSwapOperated_II++;
+#endif
+          return 2;
+        }
+      
+        // check face swap on the key face
+        // --------------------------------
+#ifdef MAKESTATS
+        numFSwapTested_II++;
+#endif
+        fSwapOp.setSwapFace((pFace)keyEnts[0]);
+
+        worst = -1.;
+        if( fSwapOp.evaluate(&worst) && worst > bestShape &&
+            fSwapOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+            fSwapOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+          bestShape = worst;
+          if(*operation) delete *operation;
+          *operation = new faceSwapOp(fSwapOp);
+#ifdef MAKESTATS
+          numFSwapAvailable_II++;
+          if (bestShape < mpm.getSliverTetBound()) numFSwapToSliver_II++;
+#endif
+        } 
+        if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+          numFSwapOperated_II++;
+#endif
+          return 2;
+        }
+
+        // check vertex move 
+        // ------------------
+        pPList verts = R_vertices(region);
+        void * temp = NULL;
+        while ( pVertex pv = (pVertex)PList_next(verts,&temp) ) {
+#ifdef MAKESTATS
+          numVMoveTested_II++;
+#endif
+          if( V_whatInType(pv) != 3 ) continue;
+        
+          vMoveOp.setPositionToOptimal(pv);
+
+          worst = -1.;
+          if( vMoveOp.evaluate(&worst) && worst > bestShape &&
+              vMoveOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+              vMoveOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+            bestShape = worst;
+            if(*operation) delete *operation;
+            *operation = new vertexMoveOp(vMoveOp);
+#ifdef MAKESTATS
+            numVMoveAvailable_II++;
+            if (bestShape < mpm.getSliverTetBound()) numVMoveToSliver_II++;
+#endif
+          }
+        }
+        PList_delete(verts);
+        if( *operation && bestShape > mpm.getSliverTetBound() ) {
+#ifdef MAKESTATS
+          numVMoveOperated_II++;
+#endif
+          return 2;
+        }
+
+#ifdef MAKESTATS
+        if( *operation ) {
+          switch ((*operation)->type()) {
+          case MAd_ECOLLAPSE:  { numEClpsOperated_II++;    break; }
+          case MAd_ESWAP:      { numSwapOperated_II++;     break; }
+          case MAd_FSWAP:      { numFSwapOperated_II++;    break; }
+          case MAd_FCOLLAPSE:  { numFClpsOperated_II++;    break; }
+          case MAd_VERTEXMOVE: { numVMoveOperated_II++;    break; }
+          default: throw;
+          }
+        }
+#endif
+
+        if( *operation )  return 1;
+
+#ifdef MAKESTATS
+        set<pRegion>::const_iterator sIter = sliversOut.find(region);
+        if (sIter == sliversOut.end() ) {
+          sliversOut.insert(region);
+          numTypeII_Out++;
+        }
+#endif
+      }
+  
+    return 0;
+  }
+
+  // -------------------------------------------------------------------
+  bool sliverRegionHandler::R_isSliver(pRegion region, double* shape)
+  {
+    MeshParametersManager& mpm = MeshParametersManagerSgl::instance();
+
+    mqm.getShape(region,shape);
+
+    if( *shape < mpm.getSliverTetBound() ) return true;
+    return false;
+  }
+
+  // -------------------------------------------------------------------
+  bool sliverRegionHandler::R_isSliver(pRegion region)
+  {
+    MeshParametersManager& mpm = MeshParametersManagerSgl::instance();
+
+    double shape;
+    mqm.getShape(region,&shape);
+
+    if( shape < mpm.getSliverTetBound() ) return true;
+    return false;
+  }
+
+  // -------------------------------------------------------------------
+  // Gets the type of sliver and the related key entities.
+  // Returns 0 : failure
+  //         1 : type I
+  //         2 : type II
+  int sliverRegionHandler::getSliverType(const pRegion region,
+                                         pEntity keyEnts[4])
+  {
+    pFace   base = R_face(region,0);
+    pVertex oppV = R_fcOpVt(region,base);
+
+    pEdge edges[6];    // the three ordered edges of the tet with base to be base
+    pVertex verts[3];  // the three ordered vertices of the face
+    double fxyz[3][3]; // coordinates of the three vertices of the face
+    double pxyz[3];    // coordinates of the opposite vertex
+    pFace faces[4];    // ordered faces of the tet
+    double area[4];    // areas of the faces
+  
+    for(int i=0; i<3; i++) {
+      edges[i] = F_edge(base,i);
+      if(F_edgeDir(base,i)) verts[i] = E_vertex(edges[i],0);
+      else                  verts[i] = E_vertex(edges[i],1);
+      V_coord(verts[i],fxyz[i]);
+    }
+  
+    faces[0] = base;
+    for(int i=0; i<4; i++) {
+      pFace face = R_face(region,i);
+      if( face == base ) continue;
+      if( F_inClosure(face,(pEntity)edges[0]) ) { faces[1]=face; continue; }
+      if( F_inClosure(face,(pEntity)edges[1]) ) { faces[2]=face; continue; }
+      if( F_inClosure(face,(pEntity)edges[2]) ) faces[3]=face;
+    }
+    
+    for(int i=1; i<3; i++) {
+      for(int j=0; j<3; j++) {
+        pEdge edge = F_edge(faces[i],j);
+        if( edge == edges[i-1] ) continue;
+        if( E_inClosure(edge,(pEntity)verts[0]) ) { edges[3]=edge; continue; }
+        if( E_inClosure(edge,(pEntity)verts[1]) ) { edges[4]=edge; continue; }
+        if( E_inClosure(edge,(pEntity)verts[2]) ) edges[5]=edge;
+      }
+    }
+    
+    V_coord(oppV,pxyz);
+    double proj[3];
+    int bit;
+    pointToTriangle(fxyz,pxyz,proj,&bit,area);
+
+    //            010=2   | 011=3  /  001=1
+    //                    |       /
+    //        ------------+--e2--+-----------
+    //                  v0|     /v2
+    //                    | 7  /
+    //            110=6   e0  e1
+    //                    |  /
+    //                    | /    101=5
+    //                    |/
+    //                  v1+
+    //                   /|
+    //                  / |
+    //                   4
+    
+
+    // determine the key entities
+    switch( bit ) {
+    case 1:{
+      int Emap[] = {0,4,3};
+      int Fmap[] = {0,2,3};
+      keyEnts[0] = (pEntity)faces[1];
+      int index = indexOfMin(area[0],area[2],area[3]);
+      keyEnts[1] = (pEntity)edges[Emap[index]];
+      keyEnts[2] = (pEntity)faces[Fmap[index]];
+      break;
+    }
+    case 2: {
+      int Emap[] = {1,4,5};
+      int Fmap[] = {0,1,3};
+      keyEnts[0] = (pEntity)faces[2];
+      int index = indexOfMin(area[0],area[1],area[3]);
+      keyEnts[1] = (pEntity)edges[Emap[index]];
+      keyEnts[2] = (pEntity)faces[Fmap[index]];
+      break;   
+    }
+    case 3: {
+      keyEnts[0] = (pEntity)edges[2];
+      keyEnts[1] = (pEntity)edges[4];
+      keyEnts[2] = (pEntity)( (area[0]<area[3]) ? faces[0]:faces[3] );
+      keyEnts[3] = (pEntity)( (area[1]<area[2]) ? faces[1]:faces[2] );
+      break; 
+    }   
+    case 4: {
+      int Emap[] = {2,3,5};
+      int Fmap[] = {0,1,2};
+      keyEnts[0] = (pEntity)faces[3];
+      int index = indexOfMin(area[0],area[1],area[2]);
+      keyEnts[1] = (pEntity)edges[Emap[index]];
+      keyEnts[2] = (pEntity)faces[Fmap[index]];
+      break; 
+    }  
+    case 5: {
+      keyEnts[0] = (pEntity)edges[1];
+      keyEnts[1] = (pEntity)edges[3];
+      keyEnts[2] = (pEntity)( (area[0]<area[2]) ? faces[0]:faces[2] );
+      keyEnts[3] = (pEntity)( (area[1]<area[3]) ? faces[1]:faces[3] );
+      break;
+    }
+    case 6: {
+      keyEnts[0] = (pEntity)edges[0];
+      keyEnts[1] = (pEntity)edges[5];
+      keyEnts[2] = (pEntity)( (area[0]<area[1]) ? faces[0]:faces[1] );
+      keyEnts[3] = (pEntity)( (area[2]<area[3]) ? faces[2]:faces[3] );
+      break;
+    }
+    case 7: {
+      int Emap[] = {0,1,2};
+      int Fmap[] = {1,2,3};
+      keyEnts[0] = (pEntity)faces[0];
+      int index = indexOfMin(area[1],area[2],area[3]);
+      keyEnts[1] = (pEntity)edges[Emap[index]];
+      keyEnts[2] = (pEntity)faces[Fmap[index]];
+      break; 
+    }
+    case 0:
+    case 8:
+    case 9:
+    case 10: {
+      break;
+    }
+    default:
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"not a valid value %d",bit);
+    }
+    
+    if ( bit==0 || bit > 7 ) return 0;
+    if ( bit==3 || bit==5 || bit==6 ) return 1;
+    return 2;
+  }
+
+  // -------------------------------------------------------------------
+  void sliverRegionHandler::printStats(ostream& out) const {
+
+#ifdef MAKESTATS
+    out << "\n*** Statistics about the sliverRegionHandler ***\n\n";
+    out << "Slivers considered: " << numTypeI_In+numTypeII_In<<endl;
+    out << "  - Type I: \t"<< numTypeI_In  << "  ( " << numTypeI_Out  << " not resolved )\n";
+    out << "  - Type II:\t"<< numTypeII_In << "  ( " << numTypeII_Out << " not resolved )\n\n";
+
+    out << " \n--- Type I slivers ---\n\n";
+    out << "\t     nbTestedOp\t nbAvailableOp \t nbOperated \t nbLeadToASliver\n";
+    out << "ESplit:\t\t"<<numSplitTested_I << "\t\t" << numSplitAvailable_I<< "\t\t" << numSplitOperated_I<< "\t\t" <<numSplitToSliver_I << "\n";
+    out << "EClps:\t\t"<< numEClpsTested_I << "\t\t" << numEClpsAvailable_I << "\t\t" << numEClpsOperated_I<< "\t\t" <<numEClpsToSliver_I << "\n";
+    out << "DESpltClps:\t"<<numDESCTested_I << "\t\t" << numDESCAvailable_I << "\t\t" <<numDESCOperated_I << "\t\t" <<numDESCToSliver_I << "\n";
+    out << "FClps:\t\t"<<numFClpsTested_I << "\t\t" << numFClpsAvailable_I<< "\t\t" << numFClpsOperated_I<< "\t\t" <<numFClpsToSliver_I << "\n";
+    out << "ESwap:\t\t"<< numSwapTested_I << "\t\t" << numSwapAvailable_I << "\t\t" << numSwapOperated_I<< "\t\t" <<numSwapToSliver_I << "\n";
+    out << "VMove:\t\t"<<numVMoveTested_I << "\t\t" << numVMoveAvailable_I<< "\t\t" << numVMoveOperated_I<< "\t\t" <<numVMoveToSliver_I << "\n";
+
+    out << " \n--- Type II slivers ---\n\n";
+    out << "\t     nbTestedOp\t nbAvailableOp \t nbOperated \t nbLeadToASliver\n";
+    out << "EClps:\t\t"<<numEClpsTested_II << "\t\t" << numEClpsAvailable_II<< "\t\t" << numEClpsOperated_II<< "\t\t" <<numEClpsToSliver_II << "\n";
+    out << "FClps:\t\t"<<numFClpsTested_II << "\t\t" << numFClpsAvailable_II << "\t\t" <<numFClpsOperated_II << "\t\t" << numFClpsToSliver_II<< "\n";
+    out << "ESwap:\t\t"<<numSwapTested_II << "\t\t" << numSwapAvailable_II<< "\t\t" << numSwapOperated_II<< "\t\t" <<numSwapToSliver_II << "\n";
+    out << "FSwap:\t\t"<<numFSwapTested_II << "\t\t" << numFSwapAvailable_II << "\t\t" <<numFSwapOperated_II << "\t\t" << numFSwapToSliver_II<< "\n";
+    out << "VMove:\t\t"<<numVMoveTested_II << "\t\t" << numVMoveAvailable_II<< "\t\t" << numVMoveOperated_II<< "\t\t" <<numVMoveToSliver_II << "\n";
+
+    out << "\n\n";
+
+#else
+
+    cout << "Could not write slivers statistics because SliverRegionHandler was compiled without the flag 'MAKESTATS'\n";
+
+#endif
+
+  }
+
+
+  // -------------------------------------------------------------------
+  void sliverRegionHandler::testOperations(pRegion region)
+  {
+    if (!R_isSliver(region)) return;
+
+    bool solvedSlivGlob = false;
+    bool solvedGlob = false;
+
+    bool solvedSliv = false;
+    bool solved = false;
+
+    double bestShape = 0.;
+    mqm.getShape(region,&bestShape);
+
+    MeshParametersManager& mpm = MeshParametersManagerSgl::instance();
+
+    edgeCollapseOp eCollOp (mesh,sizeField);
+    eCollOp.collapseOnBoundary(collapseOnBdry,dVTolClps);
+
+    faceCollapseOp fCollOp (mesh,sizeField);
+    fCollOp.collapseOnBoundary(collapseOnBdry,dVTolClps);
+
+    edgeSwapOp     eSwapOp (mesh,sizeField);
+    eSwapOp.swapOnBoundary(swapOnBdry,dVTolSwap);
+
+    DESCOp         descOp(mesh,sizeField);
+    edgeSplitOp    eSplitOp(mesh,sizeField);
+    faceSwapOp     fSwapOp(mesh,sizeField);
+    vertexMoveOp   vMoveOp(mesh,sizeField,false);
+
+    pEntity keyEnts[4];
+    int sType = getSliverType(region, keyEnts);
+    if( sType == 0 ) return;
+
+    double worst;
+
+    // --- TYPE I slivers ---
+    if( sType == 1 ) 
+      {
+        tested_I++;
+
+        // check split 
+        // ------------
+        solvedSliv = false;
+        solved = false;
+        for(int i=0; i<2; i++) {
+
+          eSplitOp.setSplitEdge((pEdge)keyEnts[i]);
+        
+          if( E_whatInType((pEdge)keyEnts[i]) != 3 ) continue;
+
+          // determine the position of the new vertex
+//           double newPos[3];
+//           E_cavityCenter( (pEdge)keyEnts[i], newPos );
+//           double t = E_linearParams((pEdge)keyEnts[i],newPos);
+//           if( t>1. || t<0. ) continue;
+//           eSplitOp.setSplitPos(newPos);
+
+          worst = -1.;
+          if( eSplitOp.evaluate(&worst) && worst > bestShape &&
+              eSplitOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+              eSplitOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+            if (worst < mpm.getSliverTetBound()) {
+              solvedSliv = true;
+            }
+            else {
+              solved = true;
+              break;
+            }
+          }
+        }
+        if ( solved ) { solvedGlob=true; splitSolves_I++; }
+        else if ( solvedSliv ) { solvedSlivGlob=true; splitSolvesToSliver_I++; }
+
+        // check edge collapses
+        // ---------------------
+        solvedSliv = false;
+        solved = false;
+        for(int i=0; i<6; i++) {
+          pEdge edge = R_edge(region,i);
+          for (int j=0; j<2; j++) {
+            eCollOp.setCollapseEdge(edge,E_vertex(edge,j),E_vertex(edge,1-j));
+
+            worst = -1.;
+            if ( eCollOp.evaluate(&worst) && worst > bestShape &&
+                 eCollOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+                 eCollOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+              if (worst < mpm.getSliverTetBound()) {
+                solvedSliv = true;
+              }
+              else {
+                solved = true;
+                break;
+              }
+            }
+          }
+          if (worst > mpm.getSliverTetBound()) break;
+        }
+        if ( solved ) { solvedGlob=true; clpsSolves_I++; }
+        else if ( solvedSliv ) { solvedSlivGlob=true; clpsSolvesToSliver_I++; }
+
+        // check double edge split collapse
+        // ---------------------------------
+        solvedSliv = false;
+        solved = false;
+        for(int i=0; i<2; i++) {
+          descOp.setDESC(region,(pEdge)keyEnts[i%2],(pEdge)keyEnts[(i+1)%2]);
+  
+          worst = -1.;
+          if( descOp.evaluate(&worst) && worst > bestShape &&
+              descOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+              descOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+            if (worst < mpm.getSliverTetBound()) {
+              solvedSliv = true;
+            }
+            else {
+              solved = true;
+            }
+          }
+        }
+        if ( solved ) { solvedGlob=true; descSolves_I++; }
+        else if ( solvedSliv ) { solvedSlivGlob=true; descSolvesToSliver_I++; }
+
+        // check face collapse
+        // --------------------
+        solvedSliv = false;
+        solved = false;
+        for(int i=0; i<2; i++) {
+          for( int ClpsOnvt=1; ClpsOnvt>=0; ClpsOnvt-- ) {
+            fCollOp.reset((pFace)keyEnts[i+2],(pEdge)keyEnts[i], ClpsOnvt);
+
+            worst = -1.;
+            if( fCollOp.evaluate(&worst) && worst > bestShape &&
+                fCollOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+                fCollOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+              if (worst < mpm.getSliverTetBound()) {
+                solvedSliv = true;
+              }
+              else {
+                solved = true;
+                break;
+              }
+            }
+          }
+          if( worst > mpm.getSliverTetBound() ) break;
+        }
+        if ( solved ) { solvedGlob=true; fclpsSolves_I++; }
+        else if ( solvedSliv ) { solvedSlivGlob=true; fclpsSolvesToSliver_I++; }
+ 
+        // check edge swaps (2 edges)
+        // ---------------------------
+        solvedSliv = false;
+        solved = false;
+        for(int i=0; i<2; i++) {
+          eSwapOp.setSwapEdge((pEdge)keyEnts[i]);
+
+          worst = -1.;
+          if( eSwapOp.evaluate(&worst) && worst > bestShape &&
+              eSwapOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+              eSwapOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+            if (worst < mpm.getSliverTetBound()) {
+              solvedSliv = true;
+            }
+            else {
+              solved = true;
+              break;
+            }
+          }
+        }
+        if ( solved ) { solvedGlob=true; swapSolves_I++; }
+        else if ( solvedSliv ) { solvedSlivGlob=true; swapSolvesToSliver_I++; }
+
+        // check vertex move 
+        // ------------------
+        solvedSliv = false;
+        solved = false;
+        pPList verts = R_vertices(region);
+        void * temp = NULL;
+        while ( pVertex pv = (pVertex)PList_next(verts,&temp) ) {
+          if( V_whatInType(pv) != 3 ) continue;
+        
+          vMoveOp.setPositionToOptimal(pv);
+
+          worst = -1.;
+          if( vMoveOp.evaluate(&worst) && worst > bestShape &&
+              vMoveOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+              vMoveOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+            if (worst < mpm.getSliverTetBound()) {
+              solvedSliv = true;
+            }
+            else {
+              solved = true;
+              break;
+            }
+          }
+        }
+        PList_delete(verts);
+        if ( solved ) { solvedGlob=true; nodeSolves_I++; }
+        else if ( solvedSliv ) { solvedSlivGlob=true; nodeSolvesToSliver_I++; }
+
+        if (!solvedGlob) {
+          set<pRegion>::const_iterator sIter = notSolved.find(region);
+          if (sIter == notSolved.end() ) {
+            notSolved.insert(region);
+            notSolved_I++;
+            if (solvedSlivGlob) solvedWithSliver_I++;
+          }
+          else {
+            notSolvedDuplicated_I++;
+            if (solvedSlivGlob) solvedWithSliverDuplicated_I++;          
+          }
+        }
+
+      }
+
+    // --- TYPE II slivers ---
+    else 
+      {
+        tested_II++;
+
+        // check edge collapses
+        // ---------------------
+        solvedSliv = false;
+        solved = false;
+        for(int i=0; i<6; i++) {
+          pEdge edge = R_edge(region,i);
+          for (int j=0; j<2; j++) {
+            eCollOp.setCollapseEdge(edge,E_vertex(edge,j),E_vertex(edge,(j+1)%2));
+
+            worst = -1.;
+            if ( eCollOp.evaluate(&worst) && worst > bestShape &&
+                 eCollOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+                 eCollOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+              if (worst < mpm.getSliverTetBound()) {
+                solvedSliv = true;
+              }
+              else {
+                solved = true;
+                break;
+              }
+            }
+          }
+          if (worst > mpm.getSliverTetBound()) break;
+        }
+        if ( solved ) { solvedGlob=true; clpsSolves_II++; }
+        else if ( solvedSliv ) { solvedSlivGlob=true; clpsSolvesToSliver_II++; }
+
+        // check face collapse
+        // --------------------
+
+        solvedSliv = false;
+        solved = false;
+        for( int ClpsOnvt=1; ClpsOnvt>=0; ClpsOnvt-- ) {
+          fCollOp.reset((pFace)keyEnts[2],(pEdge)keyEnts[1], ClpsOnvt);
+  
+          worst = -1.;
+          if( fCollOp.evaluate(&worst) && worst > bestShape &&
+              fCollOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+              fCollOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+            if (worst < mpm.getSliverTetBound()) {
+              solvedSliv = true;
+              break;
+            }
+            else {
+              solved = true;
+              break;
+            }
+          }
+        }
+        if ( solved ) { solvedGlob=true; fclpsSolves_II++; }
+        else if ( solvedSliv ) { solvedSlivGlob=true; fclpsSolvesToSliver_II++; }
+      
+        // check edge swaps
+        // -----------------
+        solvedSliv = false;
+        solved = false;
+        for(int i=0; i<3; i++) {
+          pEdge edge = F_edge((pFace)keyEnts[0],i);
+          eSwapOp.setSwapEdge(edge); 
+
+          worst = -1.;
+          if( eSwapOp.evaluate(&worst) && worst > bestShape &&
+              eSwapOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+              eSwapOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+            if (worst < mpm.getSliverTetBound()) {
+              solvedSliv = true;
+            }
+            else {
+              solved = true;
+              break;
+            }
+          }
+        }
+        if ( solved ) { solvedGlob=true; swapSolves_II++; }
+        else if ( solvedSliv ) { solvedSlivGlob=true; swapSolvesToSliver_II++; }
+      
+        // check face swap
+        // ----------------
+        solvedSliv = false;
+        solved = false;
+        fSwapOp.setSwapFace((pFace)keyEnts[0]);
+
+        worst = -1.;
+        if( fSwapOp.evaluate(&worst) && worst > bestShape &&
+            fSwapOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+            fSwapOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+          if (worst < mpm.getSliverTetBound()) solvedSliv = true;
+          else                                 solved = true;
+        } 
+        if ( solved ) { solvedGlob=true; fswapSolves_II++; }
+        else if ( solvedSliv ) { solvedSlivGlob=true; fswapSolvesToSliver_II++; }
+
+        // check vertex move 
+        // ------------------
+        solvedSliv = false;
+        solved = false;
+        pPList verts = R_vertices(region);
+        void * temp = NULL;
+        while ( pVertex pv = (pVertex)PList_next(verts,&temp) ) {
+          if( V_whatInType(pv) != 3 ) continue;
+        
+          vMoveOp.setPositionToOptimal(pv);
+
+          worst = -1.;
+          if( vMoveOp.evaluate(&worst) && worst > bestShape &&
+              vMoveOp.getMinLenSq() > mpm.getSliverLowerLengthSqBound() &&
+              vMoveOp.getMaxLenSq() < mpm.getSliverUpperLengthSqBound() ) {
+            if (worst < mpm.getSliverTetBound()) {
+              solvedSliv = true;
+            }
+            else {
+              solved = true;
+              break;
+            }
+          }
+        }
+        PList_delete(verts);
+        if ( solved ) { solvedGlob=true; nodeSolves_II++; }
+        else if ( solvedSliv ) { solvedSlivGlob=true; nodeSolvesToSliver_II++; }
+
+        if (!solvedGlob) {
+          set<pRegion>::const_iterator sIter = notSolved.find(region);
+          if (sIter == notSolved.end() ) {
+            notSolved.insert(region);
+            notSolved_II++;
+            if (solvedSlivGlob) solvedWithSliver_II++;
+          }
+          else {
+            notSolvedDuplicated_II++;
+            if (solvedSlivGlob) solvedWithSliverDuplicated_II++;          
+          }
+        }
+      }
+  
+  }
+
+  // -------------------------------------------------------------------
+  void sliverRegionHandler::printOperatorsTest(ostream& out) const
+  {
+    int testedUnique_I = tested_I-solvedWithSliverDuplicated_I-notSolvedDuplicated_I;
+    int solved_I = tested_I-solvedWithSliver_I-notSolved_I-solvedWithSliverDuplicated_I-notSolvedDuplicated_I;
+    int testedUnique_II = tested_II-solvedWithSliverDuplicated_II-notSolvedDuplicated_II;
+    int solved_II = tested_II-solvedWithSliver_II-notSolved_II-solvedWithSliverDuplicated_II-notSolvedDuplicated_II;
+
+    out << "\n*** SliverRegionHandler statistics (every operation is tested) ***\n\n";
+    out << "Slivers considered: " << testedUnique_I+testedUnique_II<<endl;
+    out << "\t    Tested\t Tested dupl.\t   Solved  \t New sliver\t New sl. dupl.\t Not solved\t Not solved dupl.\n";
+    out << "  - Type I: \t"<< testedUnique_I  
+        << "\t\t" << tested_I-testedUnique_I
+        << "\t\t" << solved_I
+        << "\t\t" << solvedWithSliver_I 
+        << "\t\t" << solvedWithSliverDuplicated_I 
+        << "\t\t" << notSolved_I 
+        << "\t\t" << notSolvedDuplicated_I 
+        << "\n";
+    out << "  - Type II: \t"<< testedUnique_II
+        << "\t\t" << tested_II-testedUnique_II
+        << "\t\t" << solved_II
+        << "\t\t" << solvedWithSliver_II 
+        << "\t\t" << solvedWithSliverDuplicated_II 
+        << "\t\t" << notSolved_II 
+        << "\t\t" << notSolvedDuplicated_II
+        << "\n";
+
+    out << " \n--- Type I slivers ---\n\n";
+    out << "\t     Solved\t Solved with a sliver\n";
+    out << "ESwap:\t\t"<< swapSolves_I << "\t\t" << swapSolvesToSliver_I << "\n";
+    out << "EClps:\t\t"<< clpsSolves_I << "\t\t" << clpsSolvesToSliver_I << "\n";
+    out << "FClps:\t\t"<< fclpsSolves_I << "\t\t" << fclpsSolvesToSliver_I << "\n";
+    out << "DESpltClps:\t"<< descSolves_I << "\t\t" << descSolvesToSliver_I << "\n";
+    out << "ESplt:\t\t"<< splitSolves_I << "\t\t" << splitSolvesToSliver_I << "\n";
+    out << "Reloc:\t\t"<< nodeSolves_I << "\t\t" << nodeSolvesToSliver_I << "\n";
+
+    out << " \n--- Type II slivers ---\n\n";
+    out << "\t     Solved\t Solved with a sliver\n";
+    out << "ESwap:\t\t"<< swapSolves_II << "\t\t" << swapSolvesToSliver_II << "\n";
+    out << "FSwap:\t\t"<< fswapSolves_II << "\t\t" << fswapSolvesToSliver_II << "\n";
+    out << "EClps:\t\t"<< clpsSolves_II << "\t\t" << clpsSolvesToSliver_II << "\n";
+    out << "FClps:\t\t"<< fclpsSolves_II << "\t\t" << fclpsSolvesToSliver_II << "\n";
+    out << "Reloc:\t\t"<< nodeSolves_II << "\t\t" << nodeSolvesToSliver_II << "\n";
+
+    out << "\n\n";
+
+  }
+
+  // -------------------------------------------------------------------
+  void sliverRegionHandler::reportSliver(pRegion region)
+  {
+    stringstream ss;
+    string idStr;  ss << reportId;  ss >> idStr;
+
+    string name = reportPrefix + "sliver" + idStr + ".pos";
+  
+    pPList cavity = PList_new();
+
+    PList_append(cavity,region);
+  
+    for (int iV=0; iV<R_numVertices(region); iV++) {
+
+      pVertex vertex = R_vertex(region, iV);
+    
+      pPList vRegs = V_regions(vertex);
+      void * temp = 0;
+      while ( pRegion pr = (pRegion)PList_next(vRegs,&temp) ) {
+        PList_appUnique(cavity,pr);
+      }
+      PList_delete(vRegs);
+    }
+
+    printPosEntities(cavity,name.c_str(),OD_MEANRATIO,sizeField);
+
+    PList_delete(cavity);
+
+    reportId++;
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/operator/SliverRegionHandler.h b/Adapt/operator/SliverRegionHandler.h
new file mode 100644
index 0000000..d2ace63
--- /dev/null
+++ b/Adapt/operator/SliverRegionHandler.h
@@ -0,0 +1,200 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_SLIVERREGIONHANDLER
+#define _H_SLIVERREGIONHANDLER
+
+#include "MAdOperatorBase.h"
+
+#include <set>
+#include <iostream>
+#include <string>
+
+#define MAKESTATS 1
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class sliverRegionHandler {
+
+  public:
+
+    sliverRegionHandler(pMesh, DiscreteSF *);
+    ~sliverRegionHandler() {}
+
+  public:
+
+    void removeSliverRegions(int * nbIn=NULL, int * nbOut=NULL);
+
+    void setSizeField(DiscreteSF *);
+
+    // whether we can use operations on boundaries
+    void collapseOnBoundary(bool, double);
+    void swapOnBoundary(bool, double);
+
+    // whether we can use operations that add nodes
+    void newVertexPermission(bool);
+    bool getNewVertexPermission() const { return addNodes; }
+
+    void enableReport(std::string);
+    void setTestAllOperators(bool);
+
+  private:
+
+    int findOperation(pRegion, pMAdOperator *);
+    bool R_isSliver(pRegion);
+    bool R_isSliver(pRegion, double *);
+
+    int getSliverType(const pRegion, pEntity[4]);
+
+    void reportSliver(pRegion);
+
+  private:
+
+    pMesh mesh;
+    DiscreteSF * sizeField;
+
+    MeshQualityManager& mqm;
+
+    bool collapseOnBdry; // whether or not we can collapse boundary edges
+    double dVTolClps;
+    bool swapOnBdry; // whether or not we can swap boundary edges
+    double dVTolSwap;
+
+    bool addNodes; // whether or not we can use operators that add nodes 
+                   // (edge split, face collapse, DESC)
+
+    bool   reportFailures;
+    int    reportId;
+    std::string reportPrefix;
+
+    bool testOperators;
+
+#ifdef MAKESTATS
+
+  private:
+
+    // statistics:
+
+    int numTypeI_In, numTypeI_Out, numTypeII_In, numTypeII_Out;
+    int numSwapTested_I, numSwapAvailable_I, numSwapOperated_I, numSwapToSliver_I;
+    int numEClpsTested_I, numEClpsAvailable_I, numEClpsOperated_I, numEClpsToSliver_I;
+    int numFClpsTested_I, numFClpsAvailable_I, numFClpsOperated_I, numFClpsToSliver_I;
+    int numDESCTested_I, numDESCAvailable_I, numDESCOperated_I, numDESCToSliver_I;
+    int numSplitTested_I, numSplitAvailable_I, numSplitOperated_I, numSplitToSliver_I;
+    int numVMoveTested_I, numVMoveAvailable_I, numVMoveOperated_I, numVMoveToSliver_I;
+
+    int numSwapTested_II, numSwapAvailable_II, numSwapOperated_II, numSwapToSliver_II;
+    int numEClpsTested_II, numEClpsAvailable_II, numEClpsOperated_II, numEClpsToSliver_II;
+    int numFSwapTested_II, numFSwapAvailable_II, numFSwapOperated_II, numFSwapToSliver_II;
+    int numFClpsTested_II, numFClpsAvailable_II, numFClpsOperated_II, numFClpsToSliver_II;
+    int numVMoveTested_II, numVMoveAvailable_II, numVMoveOperated_II, numVMoveToSliver_II;
+
+    // remaining slivers
+    std::set<pRegion> sliversOut;
+
+#endif
+
+    // test operators
+    std::set<pRegion> sliversIn;
+    int tested_I, tested_II, notSolved_I, notSolved_II, solvedWithSliver_I, solvedWithSliver_II;
+    int notSolvedDuplicated_I, notSolvedDuplicated_II, solvedWithSliverDuplicated_I, solvedWithSliverDuplicated_II;
+
+    int swapSolves_I,clpsSolves_I,fclpsSolves_I,descSolves_I,splitSolves_I,nodeSolves_I;
+    int swapSolvesToSliver_I,clpsSolvesToSliver_I,fclpsSolvesToSliver_I,descSolvesToSliver_I,splitSolvesToSliver_I,nodeSolvesToSliver_I;
+
+    int swapSolves_II, fswapSolves_II, clpsSolves_II, fclpsSolves_II, nodeSolves_II;
+    int swapSolvesToSliver_II, fswapSolvesToSliver_II, clpsSolvesToSliver_II, fclpsSolvesToSliver_II, nodeSolvesToSliver_II;
+
+    // remaining slivers
+    std::set<pRegion> notSolved;
+
+  public:
+
+    void testOperations(pRegion);
+
+    void printStats(std::ostream&) const;
+    void printOperatorsTest(std::ostream&) const;
+
+  };
+
+  // -------------------------------------------------------------------
+  inline sliverRegionHandler::sliverRegionHandler(pMesh m, DiscreteSF * sf):
+    mesh(m),sizeField(sf), mqm(MeshQualityManagerSgl::instance()), 
+    collapseOnBdry(false),dVTolClps(MAdTOL),swapOnBdry(false),dVTolSwap(MAdTOL), 
+    addNodes(true), 
+    reportFailures(false),reportId(0),reportPrefix(""),testOperators(false)
+#ifdef MAKESTATS
+    , numTypeI_In(0), numTypeI_Out(0), numTypeII_In(0), numTypeII_Out(0),
+    numSwapTested_I(0), numSwapAvailable_I(0), numSwapOperated_I(0), numSwapToSliver_I(0),
+    numEClpsTested_I(0), numEClpsAvailable_I(0), numEClpsOperated_I(0), numEClpsToSliver_I(0),
+    numFClpsTested_I(0), numFClpsAvailable_I(0), numFClpsOperated_I(0), numFClpsToSliver_I(0),
+    numDESCTested_I(0), numDESCAvailable_I(0), numDESCOperated_I(0), numDESCToSliver_I(0),
+    numSplitTested_I(0), numSplitAvailable_I(0), numSplitOperated_I(0), numSplitToSliver_I(0),
+    numVMoveTested_I(0), numVMoveAvailable_I(0), numVMoveOperated_I(0), numVMoveToSliver_I(0),
+    numSwapTested_II(0), numSwapAvailable_II(0), numSwapOperated_II(0), numSwapToSliver_II(0),
+    numEClpsTested_II(0), numEClpsAvailable_II(0), numEClpsOperated_II(0), numEClpsToSliver_II(0),
+    numFSwapTested_II(0), numFSwapAvailable_II(0), numFSwapOperated_II(0), numFSwapToSliver_II(0),
+    numFClpsTested_II(0), numFClpsAvailable_II(0), numFClpsOperated_II(0), numFClpsToSliver_II(0),
+    numVMoveTested_II(0), numVMoveAvailable_II(0), numVMoveOperated_II(0), numVMoveToSliver_II(0),
+#endif
+    tested_I(0), tested_II(0), notSolved_I(0), notSolved_II(0), solvedWithSliver_I(0), solvedWithSliver_II(0), 
+    notSolvedDuplicated_I(0), notSolvedDuplicated_II(0), solvedWithSliverDuplicated_I(0), solvedWithSliverDuplicated_II(0),
+    swapSolves_I(0),clpsSolves_I(0),fclpsSolves_I(0),descSolves_I(0),splitSolves_I(0),nodeSolves_I(0), swapSolvesToSliver_I(0),clpsSolvesToSliver_I(0),fclpsSolvesToSliver_I(0),descSolvesToSliver_I(0),splitSolvesToSliver_I(0),nodeSolvesToSliver_I(0), 
+    swapSolves_II(0), fswapSolves_II(0), clpsSolves_II(0), fclpsSolves_II(0), nodeSolves_II(0), swapSolvesToSliver_II(0), fswapSolvesToSliver_II(0), clpsSolvesToSliver_II(0), fclpsSolvesToSliver_II(0), nodeSolvesToSliver_II(0)
+  {}
+
+  // -------------------------------------------------------------------
+  inline void sliverRegionHandler::setSizeField(DiscreteSF * sf)
+  {
+    sizeField = sf;
+  }
+
+  // -------------------------------------------------------------------
+  inline void sliverRegionHandler::collapseOnBoundary(bool cob, double tolerance)
+  {
+    collapseOnBdry = cob;
+    dVTolClps = tolerance;
+  }
+
+  // -------------------------------------------------------------------
+  inline void sliverRegionHandler::swapOnBoundary(bool sob, double tolerance)
+  {
+    swapOnBdry = sob;
+    dVTolSwap = tolerance;
+  }
+
+  // -------------------------------------------------------------------
+  inline void sliverRegionHandler::newVertexPermission(bool allow)
+  {
+    addNodes = allow;
+  }
+
+  // -------------------------------------------------------------------
+  inline void sliverRegionHandler::enableReport(std::string prefix)
+  {
+    reportFailures = true; 
+    reportPrefix   = prefix;
+  }
+
+  // -------------------------------------------------------------------
+  inline void sliverRegionHandler::setTestAllOperators(bool test)
+  {
+    testOperators = test;
+  }
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/operator/VertexMoveOp.cc b/Adapt/operator/VertexMoveOp.cc
new file mode 100644
index 0000000..38492f0
--- /dev/null
+++ b/Adapt/operator/VertexMoveOp.cc
@@ -0,0 +1,437 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "VertexMoveOp.h"
+#include "OperatorTools.h"
+#include "MathUtils.h"
+
+#include <iostream>
+using std::cerr;
+#include <queue>
+using std::queue;
+using std::set;
+using std::multiset;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  vDisplacement::vDisplacement(const vDisplacement& _vDisp)
+  {
+    pv = _vDisp.pv;
+    for(int i=0; i<3; i++)  dxyz[i] = _vDisp.dxyz[i];
+  }
+
+  // -------------------------------------------------------------------
+  vDisplacement::vDisplacement(pVertex v, double disp[3])
+  {
+    pv = v;
+    for(int i=0; i<3; i++)  dxyz[i] = disp[i];
+  }
+
+  // -------------------------------------------------------------------
+  void vDisplacement::scale(double factor)
+  {
+    for(int i=0; i<3; i++)  dxyz[i] = factor * dxyz[i];  
+  }
+
+  // -------------------------------------------------------------------
+  bool vDisplacementLess::operator() (const vDisplacement& vd1,
+                                      const vDisplacement& vd2) const
+  {
+    if (vd1.pv == vd2.pv)
+      if (vd1.dxyz[0] == vd2.dxyz[0])
+        if (vd1.dxyz[1] == vd2.dxyz[1])
+          return (vd1.dxyz[2] < vd2.dxyz[2]);
+        else return (vd1.dxyz[1] < vd2.dxyz[1]);
+      else return (vd1.dxyz[0] < vd2.dxyz[0]);
+    else return (vd1.pv < vd2.pv);
+
+    return false;
+  }
+
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  bool vertexMoveOp::move(std::set<vDisplacement,vDisplacementLess>& _vDisps, 
+                          double factor)
+  {
+    resetDisplacements();
+    set<vDisplacement,vDisplacementLess>::const_iterator vDIt  = _vDisps.begin();
+    set<vDisplacement,vDisplacementLess>::const_iterator vDEnd = _vDisps.end();
+    for (; vDIt != vDEnd; vDIt++) {
+      vDisplacement vDisp = *vDIt;
+      vDisp.scale(factor);
+      vDisps.insert(vDisp);
+    }
+    return operate();
+  }
+
+  // -------------------------------------------------------------------
+  bool vertexMoveOp::move(multiset<vDisplacement,vDisplacementLess>& _vDisps, 
+                          double factor)
+  {
+    resetDisplacements();
+    multiset<vDisplacement,vDisplacementLess>::const_iterator vDIt  = _vDisps.begin();
+    multiset<vDisplacement,vDisplacementLess>::const_iterator vDEnd = _vDisps.end();
+    for (; vDIt != vDEnd; vDIt++) {
+      vDisplacement vDisp = *vDIt;
+      vDisp.scale(factor);
+      vDisps.insert(vDisp);
+    }
+    return operate();
+  }
+
+  // -------------------------------------------------------------------
+  bool vertexMoveOp::move(pVertex v, double disp[3])
+  {
+    return move( vDisplacement(v,disp) );
+  }
+
+  // -------------------------------------------------------------------
+  bool vertexMoveOp::move(vDisplacement vDisp)
+  {
+    resetDisplacements();
+    addVDisplacement(vDisp);
+    return operate();
+  }
+
+  // -------------------------------------------------------------------
+  bool vertexMoveOp::operate()
+  {
+    double shape;
+    if ( !evaluate(&shape) ) return false;
+    apply();
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  void vertexMoveOp::addVDisplacement(pVertex v, double disp[3])
+  {
+    vDisplacement vDisp(v,disp);
+    addVDisplacement(vDisp);
+  }
+
+  // -------------------------------------------------------------------
+  void vertexMoveOp::addVDisplacement(vDisplacement vDisp)
+  {
+    vDisps.insert(vDisp);
+  }
+
+  // -------------------------------------------------------------------
+  void vertexMoveOp::resetDisplacements()
+  {
+    vDisps.clear();
+  }
+
+  // -------------------------------------------------------------------
+  void vertexMoveOp::setDisplacement(pVertex v, double disp[3])
+  {
+    resetDisplacements();
+    addVDisplacement(v,disp);
+  }
+
+  // -------------------------------------------------------------------
+  void vertexMoveOp::setPosition(pVertex v, double pos[3])
+  {
+    double xyz0[3], dxyz[3];
+    V_coord(v,xyz0);
+    diffVec(pos,xyz0,dxyz);
+    setDisplacement(v,dxyz);
+  }
+
+  // -------------------------------------------------------------------
+  void vertexMoveOp::setPositionToOptimal(pVertex v)
+  {
+    double opt[3];
+    if (computeOptimalLocation(v, opt)) setPosition(v, opt);
+  }
+
+  // -------------------------------------------------------------------
+  bool vertexMoveOp::computeOptimalLocation(pVertex vt, double opt[3]) const
+  {
+    if ( V_whatInType(vt) != dim ) return false;
+
+    bool flag = false;
+
+    // --- get original coordinates ---
+    double ori[3]; V_coord(vt,ori);
+
+    // --- get connected faces ---
+    std::set<pFace> fSet;
+    pPList faces = V_faces(vt);
+    void * temp = 0;
+    while ( pFace pf = (pFace) PList_next(faces,&temp) ) fSet.insert(pf);
+    PList_delete(faces);
+
+    // --- get original worst volume ratio ---
+    double oriWorstRatio = F_worstVolumeRatio(fSet);
+  
+    // --- set first trial: the center of the cavity ---
+    V_cavityCenter(vt,opt);
+
+    int iter = 0;
+    while ( iter < 3 && dotProd(opt,ori) > MAdTOL ) {
+
+      // --- get worst vol ratio if we move to optimal ---
+      V_setPosition(vt,opt);
+      double optWorstRatio = F_worstVolumeRatio(fSet);
+
+      // --- if it does not improve volume ratio ---
+      // --- move it if increasing shape ---
+      if( fabs(oriWorstRatio-optWorstRatio) < OPTILOC_MIN_IMPROVE_RATIO ) {
+
+        V_setPosition(vt,ori);
+        double oriWorstShp;
+        mqm.V_worstShape(vt,&oriWorstShp);
+
+        V_setPosition(vt,opt);
+        double optWorstShp;
+        mqm.V_worstShape(vt,&optWorstShp);
+
+        if( (optWorstShp-oriWorstShp) > OPTILOC_MIN_IMPROVE_SHAPE ) { 
+          flag = true; break;
+        }
+      }
+
+      // --- if it improves volume ratio ---
+      if( (oriWorstRatio-optWorstRatio) > OPTILOC_MIN_IMPROVE_RATIO && 
+          optWorstRatio != -1. ) {
+        flag = true; break;
+      }
+
+      // --- underrelax solution ---
+      for(int i=0; i<3; i++)
+        opt[i] = 0.5*(opt[i]+ori[i]);
+
+      iter++;
+    }
+
+    // --- put back the vertex at its original location ---
+    V_setPosition(vt,ori);
+
+    // --- no improvement found ---
+    if (!flag) V_coord(vt,opt);
+
+    return flag;
+  }
+
+  // -------------------------------------------------------------------
+  bool vertexMoveOp::checkConstraints() const
+  {
+    multiset<vDisplacement,vDisplacementLess>::const_iterator vDIt  = vDisps.begin();
+    multiset<vDisplacement,vDisplacementLess>::const_iterator vDEnd = vDisps.end();
+    for (; vDIt != vDEnd; vDIt++) {
+      vDisplacement vd = *vDIt;
+      if ( EN_constrained((pEntity)(vd.pv)) )  return false;
+    }
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool vertexMoveOp::checkGeometry() 
+  {
+    multiset<vDisplacement,vDisplacementLess>::const_iterator vDIt  = vDisps.begin();
+    multiset<vDisplacement,vDisplacementLess>::const_iterator vDEnd = vDisps.end();
+    for (; vDIt != vDEnd; vDIt++) {
+      vDisplacement vd = *vDIt;
+      // check vertex is not on a boundary (if requested)
+      if (fixedBndry)    if ( V_whatInType(vd.pv) < dim ) return false;
+    }
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool vertexMoveOp::evaluateShapes2D()
+  {
+    pPList faces;
+    getCavity(&faces);
+
+    double worstShape = mqm.getElementEvaluator()->bestShapeEver();
+
+    void * temp = NULL;
+    while( pFace face = (pFace) PList_next(faces,&temp) ) {
+
+      double fCoords[3][3];
+      pMSize fSizes[3] = {NULL,NULL,NULL};
+
+      double fOriNor[3];
+      F_normal(face,fOriNor);
+
+      pPList fVerts = F_vertices(face,1);
+      void * temp2 = NULL;
+      int iNode = 0;
+      while ( pVertex pV = (pVertex)PList_next(fVerts,&temp2) ) {
+
+        V_coord(pV,fCoords[iNode]);
+      
+        multiset<vDisplacement,vDisplacementLess>::const_iterator vDIt  = vDisps.begin();
+        multiset<vDisplacement,vDisplacementLess>::const_iterator vDEnd = vDisps.end();
+        for (; vDIt != vDEnd; vDIt++) {
+          if ( (*vDIt).pv == pV ) {
+            for (int iC=0; iC<3; iC++) fCoords[iNode][iC] += (*vDIt).dxyz[iC];
+          }
+        }
+      
+        fSizes[iNode] = sizeField->findSize(pV);
+
+        iNode++;
+      }
+      PList_delete(fVerts);
+
+      // Check if the shape is acceptable and compare it to the worst shape
+      double shape = 0.;
+      if ( !mqm.getElementEvaluator()->XYZ_F_shape(fCoords, fSizes, fOriNor, &shape) ) {
+        PList_delete(faces); 
+        return false;
+      }
+      else {
+        if ( shape < worstShape ) worstShape = shape;
+      }
+    }
+    PList_delete(faces);
+
+    results->setWorstShape(worstShape);
+
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool vertexMoveOp::evaluateShapes()
+  {
+    if (dim == 2) return evaluateShapes2D();
+
+    pPList regs;
+    getCavity(&regs);
+
+    double worstShape = mqm.getElementEvaluator()->bestShapeEver();
+
+    void * temp = NULL;
+    while( pRegion region = (pRegion) PList_next(regs,&temp) ) {
+
+      double rCoords[4][3];
+      pMSize rSizes[4] = {NULL,NULL,NULL,NULL};
+
+      pPList rVerts = R_vertices(region);
+      void * temp2 = NULL;
+      int iNode = 0;
+      while ( pVertex pV = (pVertex)PList_next(rVerts,&temp2) ) {
+
+        V_coord(pV,rCoords[iNode]);
+      
+        multiset<vDisplacement,vDisplacementLess>::const_iterator vDIt  = vDisps.begin();
+        multiset<vDisplacement,vDisplacementLess>::const_iterator vDEnd = vDisps.end();
+        for (; vDIt != vDEnd; vDIt++) {
+          if ( (*vDIt).pv == pV ) {
+            for (int iC=0; iC<3; iC++) rCoords[iNode][iC] += (*vDIt).dxyz[iC];
+          }
+        }
+      
+        rSizes[iNode] = sizeField->findSize(pV);
+
+        iNode++;
+      }
+      PList_delete(rVerts);
+
+      // Check if the shape is acceptable and compare it to the worst shape
+      double shape = 0.;
+      if ( !mqm.getElementEvaluator()->XYZ_R_shape(rCoords, rSizes, &shape) ) {
+        PList_delete(regs); 
+        return false;
+      }
+      else {
+        if ( shape < worstShape ) worstShape = shape;
+      }
+    }
+    PList_delete(regs);
+
+    results->setWorstShape(worstShape);
+
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  void vertexMoveOp::evaluateLengths() const
+  {
+    double minSq = MAdBIG;
+    double maxSq = 0.;
+
+    pPList edges;
+    getAffectedEdges(&edges);
+
+    void* tmp=0;
+    while ( pEdge pe = (pEdge)PList_next(edges,&tmp) ) {
+      double lSq = sizeField->SF_E_lengthSq(pe);
+      if ( lSq > maxSq ) maxSq = lSq;
+      if ( lSq < minSq ) minSq = lSq;
+    }
+
+    PList_delete(edges);
+
+    results->setMaxLenSq(maxSq);
+    results->setMinLenSq(minSq);
+  }
+
+  // -------------------------------------------------------------------
+  void vertexMoveOp::getAffectedEdges(pPList * edges) const
+  {
+    *edges = PList_new();
+    multiset<vDisplacement,vDisplacementLess>::const_iterator vDIt  = vDisps.begin();
+    multiset<vDisplacement,vDisplacementLess>::const_iterator vDEnd = vDisps.end();
+    for (; vDIt != vDEnd; vDIt++) {
+      pPList vEdges = V_edges(vDIt->pv);
+      (*edges) = PList_appPListUnique(*edges,vEdges);
+      PList_delete(vEdges);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void vertexMoveOp::getCavity(pPList * cavity) const
+  {
+    *cavity = PList_new();
+    multiset<vDisplacement,vDisplacementLess>::const_iterator vDIt  = vDisps.begin();
+    multiset<vDisplacement,vDisplacementLess>::const_iterator vDEnd = vDisps.end();
+    for (; vDIt != vDEnd; vDIt++) {
+      if ( dim == 3 ) {
+        pPList vRegs = V_regions(vDIt->pv);
+        (*cavity) = PList_appPListUnique(*cavity,vRegs);
+        PList_delete(vRegs);
+      }
+      else {
+        pPList vFaces = V_faces(vDIt->pv);
+        (*cavity) = PList_appPListUnique(*cavity,vFaces);
+        PList_delete(vFaces);
+      }
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void vertexMoveOp::apply()
+  {
+    multiset<vDisplacement,vDisplacementLess>::const_iterator vDIt  = vDisps.begin();
+    multiset<vDisplacement,vDisplacementLess>::const_iterator vDEnd = vDisps.end();
+    for (; vDIt != vDEnd; vDIt++) {
+      vDisplacement vd = *vDIt;
+
+      double target[3]; V_coord(vd.pv,target);
+      for (int i=0; i < 3; i++)  target[i] += vd.dxyz[i];
+
+      if ( !V_setPosition(vd.pv,target) ) {
+        cerr << "Error: could not move vertex\n"; throw;
+      }
+    }
+    HistorySgl::instance().add((int)type(),OPERATOR_APPLY,1);
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/operator/VertexMoveOp.h b/Adapt/operator/VertexMoveOp.h
new file mode 100644
index 0000000..b4ebce7
--- /dev/null
+++ b/Adapt/operator/VertexMoveOp.h
@@ -0,0 +1,112 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_VERTEXMOVEOP
+#define _H_VERTEXMOVEOP
+
+#include "MAdOperatorBase.h"
+
+#include <set>
+
+#define OPTILOC_MIN_IMPROVE_RATIO  1.e-3
+#define OPTILOC_MIN_IMPROVE_SHAPE  1.e-3
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  // GCTODO: rewrite it simpler
+  struct vDisplacement
+  {
+    vDisplacement(const vDisplacement&);
+    vDisplacement(pVertex, double[3]);
+    void scale(double);
+    pVertex pv;
+    double dxyz[3];    // displacement
+  };
+
+  struct vDisplacementLess
+  {
+    bool operator() (const vDisplacement&, const vDisplacement&) const;
+  };
+
+  // -------------------------------------------------------------------
+  class vertexMoveOp : public MAdOperatorBase
+  {
+  public:
+
+    vertexMoveOp(pMesh, DiscreteSF *, bool _fixBndry=true);
+    vertexMoveOp(const vertexMoveOp &);
+    ~vertexMoveOp() {}
+
+    operationType type() const { return MAd_VERTEXMOVE; }
+
+    void setFixedBndry(bool);
+
+    void resetDisplacements();
+    void addVDisplacement(pVertex, double[3]);
+    void addVDisplacement(vDisplacement);
+    void setDisplacement(pVertex, double[3]);
+    void setPosition(pVertex, double[3]);
+    void setPositionToOptimal(pVertex);
+
+    bool computeOptimalLocation(pVertex, double[3]) const;
+
+    void getAffectedEdges(pPList *) const;
+    void getCavity(pPList *) const;
+
+    void apply();
+    bool move (std::set<vDisplacement,vDisplacementLess>&, double factor=1.0);
+    bool move (std::multiset<vDisplacement,vDisplacementLess>&, double factor=1.0);
+    bool move (pVertex, double[3]);
+    bool move (vDisplacement);
+    bool operate ();
+
+  private:
+
+    bool checkConstraints() const;
+    bool checkGeometry();
+    bool evaluateShapes();
+    bool evaluateShapes2D();
+    void evaluateLengths() const;
+
+  private:
+
+    std::multiset<vDisplacement,vDisplacementLess> vDisps;
+    bool fixedBndry; // indicates if the boundary vertices can move
+  };
+
+  // -------------------------------------------------------------------
+  inline vertexMoveOp::vertexMoveOp(const vertexMoveOp & _vm):
+    MAdOperatorBase(_vm) 
+  {
+    vDisps = _vm.vDisps;
+    fixedBndry = _vm.fixedBndry;
+  }
+
+  // -------------------------------------------------------------------
+  inline vertexMoveOp::vertexMoveOp(pMesh _m, DiscreteSF * _sf, 
+                                    bool _fixBndry): 
+    MAdOperatorBase(_m,_sf), fixedBndry(_fixBndry)
+  {}
+
+  // -------------------------------------------------------------------
+  inline void vertexMoveOp::setFixedBndry(bool fixed)
+  {
+    fixedBndry = fixed;
+  }
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/output/MAdOutput.cc b/Adapt/output/MAdOutput.cc
new file mode 100644
index 0000000..0c7d83c
--- /dev/null
+++ b/Adapt/output/MAdOutput.cc
@@ -0,0 +1,785 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MAdOutput.h"
+#include "MeanRatioEvaluator.h"
+#include "OrientedMeanRatioEvaluator.h"
+#include "MAdMessage.h"
+#include "MathUtils.h"
+#include "LocalSizeField.h"
+#include "MAdResourceManager.h"
+
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+#include <vector>
+using std::vector;
+using std::string;
+using std::set;
+
+namespace MAd {
+
+  // ----------------------------------------------------------------------
+  enum dataType {
+    SCALAR,
+    VECTORIAL
+  };
+
+  dataType getOutputDataType(MAdOutputData t) {
+    switch (t) {
+    case OD_CONSTANT:
+    case OD_MEANRATIO:
+    case OD_SIZEFIELD_MEAN:
+    case OD_SIZEFIELD_MIN:
+    case OD_SIZEFIELD_MAX:
+    case OD_DIMENSION:
+    case OD_ITERORDER:
+    case OD_CURVATURE_DIV:
+    case OD_CURVATURE_MAX:
+    case OD_CURVATURE_MIN:
+      { return SCALAR; break; }
+    case OD_CURVATURE_MAX_VEC:
+    case OD_CURVATURE_MIN_VEC:
+    case OD_ANISO_SF_AXIS0:
+    case OD_ANISO_SF_AXIS1:
+    case OD_ANISO_SF_AXIS2:
+      { return VECTORIAL; break; }
+    }
+    throw;
+  };
+
+  std::string getOutputName( MAdOutputData type ) {
+    switch (type) {
+    case OD_CONSTANT: return "constant field";
+    case OD_MEANRATIO: return "mean ratio";
+    case OD_ORIENTEDMEANRATIO: return "oriented mean ratio";
+    case OD_SIZEFIELD_MEAN: return "mean size (among the 3 directions) in the size field";
+    case OD_SIZEFIELD_MIN: return "minimum size (among the 3 directions) in the size field";
+    case OD_SIZEFIELD_MAX: return "maximum size (among the 3 directions) in the size field";
+    case OD_DIMENSION: return "element dimension";
+    case OD_ITERORDER: return "element id regarding place in iterator";
+    case OD_CURVATURE_DIV: return "divergence of the curvature";
+    case OD_CURVATURE_MAX: return "surface maximum curvature (scalar field)";
+    case OD_CURVATURE_MIN: return "surface minimum curvature (scalar field)";
+    case OD_CURVATURE_MAX_VEC: return "surface maximum curvature (vectorial field)";
+    case OD_CURVATURE_MIN_VEC: return "surface minimum curvature (vectorial field)";
+    case OD_ANISO_SF_AXIS0: return "anisotropic size field along first direction";
+    case OD_ANISO_SF_AXIS1: return "anisotropic size field along second direction";
+    case OD_ANISO_SF_AXIS2: return "anisotropic size field along third direction";
+    }
+    return "unknown output type";
+  };
+
+  // ----------------------------------------------------------------------
+  double* getData(MAdOutputData type, const pEntity pe, const pSField sf=NULL, int id=0)
+  {
+    int dim = EN_type(pe);
+    double * result;
+
+    switch (type) {
+
+    case OD_DIMENSION: {
+      result = new double[4];
+      for (int i=0; i<4; i++) result[i] = (double)dim;
+      return result;
+    }
+
+    case OD_CONSTANT: {
+      result = new double[4];
+      for (int i=0; i<4; i++) result[i] = 1.;
+      return result;
+    }
+
+    case OD_MEANRATIO: {
+      if ( !sf ) {
+        MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                    "No size field given to compute mean ratio");
+      }
+      if ( sf->getType() != DISCRETESFIELD ) {
+        MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                    "Discrete size field required for quality evaluation");
+      }
+      meanRatioEvaluator evalu((DiscreteSF*)sf);
+      double tmp;
+      switch (dim) {
+      case 3:
+        result = new double[4];
+        evalu.R_shape((pRegion)pe,&tmp);
+        for (int i=0; i<4; i++) result[i] = tmp;
+        return result;
+      case 2:
+        result = new double[3];
+        evalu.F_shape((pFace)pe,0,&tmp); 
+        for (int i=0; i<3; i++) result[i] = tmp;
+        return result;
+      default:
+        cerr << "Error in outputs: getData on an element if dimension inferior to 2\n";
+        throw;
+      }
+    }
+
+    case OD_ORIENTEDMEANRATIO: {
+      if ( !sf ) {
+        MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                    "No size field given to compute mean ratio");
+      }
+      if ( sf->getType() != DISCRETESFIELD ) {
+        MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                    "Discrete size field required for quality evaluation");
+      }
+      orientedMeanRatioEvaluator evalu((DiscreteSF*)sf);
+      double tmp;
+      switch (dim) {
+      case 3:
+        result = new double[4];
+        evalu.R_shape((pRegion)pe,&tmp);
+        for (int i=0; i<4; i++) result[i] = tmp;
+        return result;
+      case 2:
+        result = new double[3];
+        evalu.F_shape((pFace)pe,0,&tmp); 
+        for (int i=0; i<3; i++) result[i] = tmp;
+        return result;
+      default:
+        cerr << "Error in outputs: getData on an element if dimension inferior to 2\n";
+        throw;
+      }
+    }
+
+    case OD_ITERORDER: {
+      result = new double[4];
+      for (int i=0; i<4; i++) result[i] = (double)id;
+      return result;
+    }
+
+    case OD_SIZEFIELD_MEAN:
+    case OD_SIZEFIELD_MIN:
+    case OD_SIZEFIELD_MAX: {
+      if ( !sf ) {
+        MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                    "No size field given");
+      }
+      void * temp; 
+      pPList verts;
+      int k;
+      pVertex pv;
+      pMSize size;
+      double h;
+      switch (dim) {
+      case 3:
+        result = new double[4];
+        verts = R_vertices((pRegion)pe);
+        temp = 0 ; k=0;
+        while ( ( pv = (pVertex)PList_next(verts,&temp) ) )
+          {
+            size = sf->getSize(pv);
+            if ( type == OD_SIZEFIELD_MEAN ) h = size->getMeanLength();
+            if ( type == OD_SIZEFIELD_MIN )  h = size->getMinLength();
+            if ( type == OD_SIZEFIELD_MAX )  h = size->getMaxLength();
+            if (size) delete size;
+            result[k] = h;
+            k++;
+          }
+        PList_delete(verts);
+        return result;
+      case 2:
+        result = new double[3];
+        verts = F_vertices( (pFace)pe, 1);
+        temp = 0 ; k=0;
+        while ( ( pv = (pVertex)PList_next(verts,&temp) ) )
+          {
+            size = sf->getSize(pv);
+            if ( type == OD_SIZEFIELD_MEAN ) h = size->getMeanLength();
+            if ( type == OD_SIZEFIELD_MIN )  h = size->getMinLength();
+            if ( type == OD_SIZEFIELD_MAX )  h = size->getMaxLength();
+            if (size) delete size;
+            result[k] = h;
+            k++;
+          }
+        PList_delete(verts);
+        return result;
+      default:
+        cerr << "Error in outputs: getData on an element if dimension inferior to 2\n";
+        throw;
+      }
+    }
+
+    case OD_CURVATURE_DIV: {
+      if ( dim < 3 )
+        {
+#ifdef _HAVE_GMSH_
+          result = new double[4];
+          pGEntity pge = EN_whatIn(pe);
+          if ( GEN_type(pge) != 2 ) {
+            for (int i=0; i<4; i++) result[i] = -1.;
+            return result;
+          }
+          double u[4][2];
+          F_params((pFace)pe,u);
+          for (int iV=0; iV<F_numVertices((pFace)pe); iV++)
+            {
+              result[iV] = GF_curvatureDiv((pGFace)pge, u[iV], 1.e6);
+            }
+          return result;
+#else
+          MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                      "Gmsh required for divergence of surface curvature");
+#endif
+        }
+      else
+        {
+          if ( !sf || ( sf->getType() != LOCALSFIELD ) ) {
+            MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                        "A local size field is required to output divergence of the curvature on elements");
+          }
+          result = new double[4];
+          LocalSizeField * sf_cast = (LocalSizeField *) sf;
+          pRegion pr = (pRegion) pe;
+          for (int iV=0; iV<4; iV++)
+            {
+              if ( sf_cast->getCurvature(R_vertex(pr,iV), &(result[iV])) ) {}
+              else result[iV] = -1.;
+            }
+          return result;
+        }
+      return NULL;
+    }
+
+    case OD_CURVATURE_MAX: {
+#ifdef _HAVE_GMSH_
+      if ( dim != 2 ) {
+        MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                    "Cannot output curvatures on other entities than faces");
+      }
+      result = new double[4];
+      pGEntity pge = EN_whatIn(pe);
+      if ( GEN_type(pge) != 2 ) {
+        for (int i=0; i<4; i++) result[i] = -1.;
+        return result;
+      }
+      double u[4][2];
+      F_params((pFace)pe,u);
+      for (int iV=0; iV<F_numVertices((pFace)pe); iV++)
+        {
+          double dirMax[3], dirMin[3], curvMax, curvMin;
+          GF_curvatures((pGFace)pge, u[iV],
+                        dirMax, dirMin, &curvMax, &curvMin, 1.e6);
+          result[iV] = curvMax;
+        }
+      return result;
+#else
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"Gmsh required for curvature");
+#endif
+    }
+
+    case OD_CURVATURE_MIN: {
+#ifdef _HAVE_GMSH_
+      if ( dim != 2 ) {
+        MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                    "Cannot output curvatures on other entities than faces");
+      }
+      result = new double[4];
+      pGEntity pge = EN_whatIn(pe);
+      if ( GEN_type(pge) != 2 ) {
+        for (int i=0; i<4; i++) result[i] = -1.;
+        return result;
+      }
+      double u[4][2];
+      F_params((pFace)pe,u);
+      for (int iV=0; iV<F_numVertices((pFace)pe); iV++)
+        {
+          double dirMax[3], dirMin[3], curvMax, curvMin;
+          GF_curvatures((pGFace)pge, u[iV],
+                        dirMax, dirMin, &curvMax, &curvMin, 1.e6);
+          result[iV] = curvMin;
+        }
+      return result;
+#else
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"Gmsh required for curvature");
+#endif
+    }
+
+    case OD_CURVATURE_MAX_VEC: {
+#ifdef _HAVE_GMSH_
+      if ( dim != 2 ) {
+        MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                    "Cannot output curvatures on other entities than faces");
+      }
+      result = new double[9];
+      pGEntity pge = EN_whatIn(pe);
+      if ( GEN_type(pge) != 2 ) {
+        for (int i=0; i<9; i++) result[i] = -1.;
+        return result;
+      }
+      double u[3][2];
+      F_params((pFace)pe,u);
+      for (int iV=0; iV<3; iV++)
+        {
+          double dirMax[3], dirMin[3], curvMax, curvMin;
+          GF_curvatures((pGFace)pge, u[iV],
+                        dirMax, dirMin, &curvMax, &curvMin, 1.e6);
+          normalizeVec(dirMax,dirMax);
+          for (int iC=0; iC<3; iC++) result[3*iV+iC] = dirMax[iC] * curvMax;
+        }
+      return result;
+#else
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"Gmsh required for curvature");
+#endif
+    }
+
+    case OD_CURVATURE_MIN_VEC: {
+#ifdef _HAVE_GMSH_
+      if ( dim != 2 ) {
+        MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                    "Cannot output curvatures on other entities than faces");
+      }
+      result = new double[9];
+      pGEntity pge = EN_whatIn(pe);
+      if ( GEN_type(pge) != 2 ) {
+        for (int i=0; i<9; i++) result[i] = -1.;
+        return result;
+      }
+      double u[3][2];
+      F_params((pFace)pe,u);
+      for (int iV=0; iV<3; iV++)
+        {
+          double dirMax[3], dirMin[3], curvMax, curvMin;
+          GF_curvatures((pGFace)pge, u[iV],
+                        dirMax, dirMin, &curvMax, &curvMin, 1.e6);
+          normalizeVec(dirMin,dirMin);
+          for (int iC=0; iC<3; iC++) result[3*iV+iC] = dirMin[iC] * curvMin;
+        }
+      return result;
+#else
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"Gmsh required for curvature");
+#endif
+    }
+
+    case OD_ANISO_SF_AXIS0: 
+    case OD_ANISO_SF_AXIS1: 
+    case OD_ANISO_SF_AXIS2:
+      {
+        if ( !sf ) MAdMsgSgl::instance().error(__LINE__,__FILE__,"No size field given");
+      
+        void * temp; 
+        pPList verts;
+        int k;
+        pVertex pv;
+        switch (dim) {
+        case 3:
+          result = new double[12];
+          verts = R_vertices((pRegion)pe);
+          temp = 0 ; k=0;
+          while ( ( pv = (pVertex)PList_next(verts,&temp) ) )
+            {
+              pMSize size = sf->getSize(pv);
+              double h, dir[3];
+              if ( type == OD_ANISO_SF_AXIS0 ) h = size->direction(0,dir);
+              if ( type == OD_ANISO_SF_AXIS1 ) h = size->direction(1,dir);
+              if ( type == OD_ANISO_SF_AXIS2 ) h = size->direction(2,dir);
+              if (size) delete size;
+              for (int iC=0; iC<3; iC++) result[3*k+iC] = h * dir[iC];
+              k++;
+            }
+          PList_delete(verts);
+          return result;
+        case 2:
+          result = new double[9];
+          verts = F_vertices( (pFace)pe, 1);
+          temp = 0 ; k=0;
+          while ( ( pv = (pVertex)PList_next(verts,&temp) ) )
+            {
+              pMSize size = sf->getSize(pv);
+              double h, dir[3];
+              if ( type == OD_ANISO_SF_AXIS0 ) h = size->direction(0,dir);
+              if ( type == OD_ANISO_SF_AXIS1 ) h = size->direction(1,dir);
+              if ( type == OD_ANISO_SF_AXIS2 ) h = size->direction(2,dir);
+              if (size) delete size;
+              for (int iC=0; iC<3; iC++) result[3*k+iC] = h * dir[iC];
+              k++;
+            }
+          PList_delete(verts);
+          return result;
+        default:
+          MAdMsgSgl::instance().error(__LINE__,__FILE__,"Dimension < 2: %d",dim);
+        }
+    }
+
+    default:
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"Data type not handled in switch");
+    }
+    return 0;
+  }
+
+  // ----------------------------------------------------------------------
+  void writeFaces (const pMesh m, const pSField sf, FILE *f, MAdOutputData type)
+  {
+    int count = 0;
+    FIter fit = M_faceIter(m);
+    while (pFace pf = FIter_next(fit))
+      {
+        double xyz[3][3];
+        F_coordP1(pf, xyz);
+        double* data = getData(type,(pEntity)pf,sf,count);
+        if ( getOutputDataType(type) == SCALAR ) {
+          fprintf (f,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g};\n",
+                   xyz[0][0],xyz[0][1],xyz[0][2],
+                   xyz[1][0],xyz[1][1],xyz[1][2],
+                   xyz[2][0],xyz[2][1],xyz[2][2],
+                   data[0],data[1],data[2]);
+        }
+        if ( getOutputDataType(type) == VECTORIAL ) {
+          fprintf (f,"VT(%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g,%g,%g,%g,%g,%g,%g};\n",
+                   xyz[0][0],xyz[0][1],xyz[0][2],
+                   xyz[1][0],xyz[1][1],xyz[1][2],
+                   xyz[2][0],xyz[2][1],xyz[2][2],
+                   data[0],data[1],data[2],
+                   data[3],data[4],data[5],
+                   data[6],data[7],data[8]);
+        }
+        delete [] data;
+        count++;
+      }
+    FIter_delete(fit);
+  }
+
+  // ----------------------------------------------------------------------
+  void writeRegions (const pMesh m, const pSField sf, FILE *f, MAdOutputData type)
+  {
+    int count = 0;
+    RIter rit = M_regionIter(m);
+    while (pRegion pr = RIter_next(rit))
+      {
+        double xyz[4][3];
+        R_coordP1(pr, xyz);
+        double* data = getData(type,(pEntity)pr,sf,count);
+        if ( getOutputDataType(type) == SCALAR ) {
+          fprintf (f,"SS(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g,%g};\n",
+                   xyz[0][0],xyz[0][1],xyz[0][2],
+                   xyz[1][0],xyz[1][1],xyz[1][2],
+                   xyz[2][0],xyz[2][1],xyz[2][2],
+                   xyz[3][0],xyz[3][1],xyz[3][2],
+                   data[0],data[1],data[2],data[3]);
+        }
+        if ( getOutputDataType(type) == VECTORIAL ) {
+          fprintf (f,"VS(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g};\n",
+                   xyz[0][0],xyz[0][1],xyz[0][2],
+                   xyz[1][0],xyz[1][1],xyz[1][2],
+                   xyz[2][0],xyz[2][1],xyz[2][2],
+                   xyz[3][0],xyz[3][1],xyz[3][2],
+                   data[0],data[1],data[2],data[3],
+                   data[4],data[5],data[6],data[7],
+                   data[8],data[9],data[10],data[11]);
+        }
+        delete [] data;
+        count++;
+      }
+    RIter_delete(rit);
+  }
+
+  // ----------------------------------------------------------------------
+  void MAdGmshOutput (const pMesh m, const pSField sf, const char *fn, MAdOutputData type)
+  {
+    MAdResourceManager& tm   = MAdResourceManagerSgl::instance();
+    double t0 = tm.getTime();
+
+    if ( sf ) MAdMsgSgl::instance().info(-1,__FILE__,
+                                         "Generating output \'%s\' on file \'%s\' with size field \'%s\'",
+                                         getOutputName(type).c_str(), fn, sf->getName().c_str());
+    else      MAdMsgSgl::instance().info(-1,__FILE__,
+                                         "Generating output \'%s\' on file \'%s\'",
+                                         getOutputName(type).c_str(), fn);
+  
+    FILE *f = fopen (fn, "w");
+    if ( !f ) {
+      cerr << "Error: could not open file " << fn << endl; throw;
+    }
+
+    fprintf (f,"View\" mesh \" {\n");
+
+    if (M_dim(m)==2) writeFaces(m,sf,f,type);
+    else             writeRegions(m,sf,f,type);
+
+    fprintf (f,"};\n");
+    fclose (f);
+
+    MAdMsgSgl::instance().info(-1,__FILE__,"Output generated in %f seconds",
+                               tm.getTime()-t0);
+  }
+
+  // ----------------------------------------------------------------------
+  void MAdAttachedNodalDataOutput(const pMesh m, const char *fn, pMeshDataId id)
+  {
+    FILE *f = fopen (fn, "w");
+    if ( !f ) {
+      cerr << "Error: could not open file " << fn << endl; throw;
+    }
+
+    fprintf (f,"View\" mesh \" {\n");
+
+    if (M_dim(m)==2) {
+    
+      FIter fit = M_faceIter(m);
+      while (pFace pf = FIter_next(fit))
+        {
+          // get the coordinates
+          double xyz[3][3];
+          F_coordP1(pf, xyz);
+        
+          // get the data at nodes
+          double data[3];
+          pPList verts = F_vertices(pf,1);
+          void* tmp = 0;
+          int i = 0;
+          while ( pEntity pv = PList_next(verts,&tmp) ) {
+            if ( EN_getDataDbl((pEntity)pv,id,&(data[i])) ) {}
+            else data[i] = -10.;
+            i++;
+          }
+          PList_delete(verts);
+
+          // write an element
+          fprintf (f,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g};\n",
+                   xyz[0][0],xyz[0][1],xyz[0][2],
+                   xyz[1][0],xyz[1][1],xyz[1][2],
+                   xyz[2][0],xyz[2][1],xyz[2][2],
+                   data[0],data[1],data[2]);
+        }
+      FIter_delete(fit);
+    }
+    else {
+
+      RIter rit = M_regionIter(m);
+      while (pRegion pr = RIter_next(rit))
+        {
+          // get the coordinates
+          double xyz[4][3];
+          R_coordP1(pr, xyz);
+        
+          // get the data at nodes
+          double data[4];
+          pPList verts = R_vertices(pr);
+          void* tmp = 0;
+          int i = 0;
+          while ( pEntity pv = PList_next(verts,&tmp) ) {
+            if ( EN_getDataDbl(pv,id,&(data[i])) ) {}
+            else data[i] = -10.;
+            i++;
+          }
+          PList_delete(verts);
+
+          // write an element
+          fprintf (f,"SS(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g,%g};\n",
+                   xyz[0][0],xyz[0][1],xyz[0][2],
+                   xyz[1][0],xyz[1][1],xyz[1][2],
+                   xyz[2][0],xyz[2][1],xyz[2][2],
+                   xyz[3][0],xyz[3][1],xyz[3][2],
+                   data[0],data[1],data[2],data[3]);
+        }
+      RIter_delete(rit);
+  
+    }
+
+    fprintf (f,"};\n");
+    fclose (f);
+  }
+
+  // ----------------------------------------------------------------------
+  void MAdAttachedNodalDataVecOutput(const pMesh m, const char *fn, pMeshDataId id)
+  {
+    FILE *f = fopen (fn, "w");
+    if ( !f ) {
+      cerr << "Error: could not open file " << fn << endl; throw;
+    }
+
+    fprintf (f,"View\" mesh \" {\n");
+
+    if (M_dim(m)==2) {
+    
+      FIter fit = M_faceIter(m);
+      while (pFace pf = FIter_next(fit))
+        {
+          // get the coordinates
+          double xyz[3][3];
+          F_coordP1(pf, xyz);
+        
+          // get the data at nodes
+          double data[3][3];
+          pPList verts = F_vertices(pf,1);
+          void* tmp = 0;
+          int i = 0;
+          while ( pEntity pv = PList_next(verts,&tmp) ) {
+            void * tmpDat = NULL;
+            if ( EN_getDataPtr((pEntity)pv,id,&tmpDat) )
+              {
+                //  vector<double> * vec = (vector<double>*) tmpDat;
+                //  for (int j=0; j<3; j++)  data[i][j] = (*vec)[j];
+                for (int j=0; j<3; j++)  data[i][j] = ((double*)tmpDat)[j];
+              }
+            else
+              {
+                for (int j=0; j<3; j++)  data[i][j] = -10.;
+              }
+            i++;
+          }
+          PList_delete(verts);
+
+          // write an element
+          fprintf (f,"VT(%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g,%g,%g,%g,%g,%g,%g};\n",
+                   xyz[0][0],xyz[0][1],xyz[0][2],
+                   xyz[1][0],xyz[1][1],xyz[1][2],
+                   xyz[2][0],xyz[2][1],xyz[2][2],
+                   data[0][0],data[0][1],data[0][2],
+                   data[1][0],data[1][1],data[1][2],
+                   data[2][0],data[2][1],data[2][2]);
+        }
+      FIter_delete(fit);
+    }
+    else {
+
+      RIter rit = M_regionIter(m);
+      while (pRegion pr = RIter_next(rit))
+        {
+          // get the coordinates
+          double xyz[4][3];
+          R_coordP1(pr, xyz);
+        
+          // get the data at nodes
+          double data[4][3];
+          pPList verts = R_vertices(pr);
+          void* tmp = 0;
+          int i = 0;
+          while ( pEntity pv = PList_next(verts,&tmp) ) {
+            void * tmpDat = NULL;
+            if ( EN_getDataPtr((pEntity)pv,id,&tmpDat) )
+              {
+                //  vector<double> * vec = (vector<double>*) tmpDat;
+                //  for (int j=0; j<3; j++)  data[i][j] = (*vec)[j];
+                for (int j=0; j<3; j++)  data[i][j] = ((double*)tmpDat)[j];
+              }
+            else
+              {
+                for (int j=0; j<3; j++)  data[i][j] = -10.;
+              }
+            i++;
+          }
+          PList_delete(verts);
+
+          // write an element
+          fprintf (f,"VS(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g};\n",
+                   xyz[0][0],xyz[0][1],xyz[0][2],
+                   xyz[1][0],xyz[1][1],xyz[1][2],
+                   xyz[2][0],xyz[2][1],xyz[2][2],
+                   xyz[3][0],xyz[3][1],xyz[3][2],
+                   data[0][0],data[0][1],data[0][2],
+                   data[1][0],data[1][1],data[1][2],
+                   data[2][0],data[2][1],data[2][2],
+                   data[3][0],data[3][1],data[3][2]);
+        }
+      RIter_delete(rit);
+  
+    }
+
+    fprintf (f,"};\n");
+    fclose (f);
+  }
+
+  // -------------------------------------------------------------------
+  void printPosRegions(const set<pRegion> regs, string fn, MAdOutputData type, 
+                       const pSField sf, int id)
+  {
+    FILE *f = fopen (fn.c_str(), "w");
+    fprintf (f,"View\" mesh \" {\n");
+
+    set<pRegion>::const_iterator rIter = regs.begin();
+    for (; rIter != regs.end(); rIter++) {
+      double* data = getData(type,*rIter,sf);
+      double xyz[4][3];
+      R_coordP1(*rIter, xyz);
+      fprintf (f,"SS(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g,%g};\n",
+               xyz[0][0],xyz[0][1],xyz[0][2],
+               xyz[1][0],xyz[1][1],xyz[1][2],
+               xyz[2][0],xyz[2][1],xyz[2][2],
+               xyz[3][0],xyz[3][1],xyz[3][2],
+               data[0],data[1],data[2],data[3]);
+      delete [] data;
+    }
+
+    fprintf (f,"};\n");
+    fclose (f);
+  }
+
+  // -------------------------------------------------------------------
+  void printPosEntities(const pPList ents, string fn, MAdOutputData type, 
+                        const pSField sf, int id)
+  {
+    FILE *f = fopen (fn.c_str(), "w");
+    fprintf (f,"View\" mesh \" {\n");
+
+    void *iter=0;
+    while( pEntity ent = PList_next(ents,&iter) ) {
+      double* data = getData(type,ent,sf);
+      switch ( EN_type(ent) ) {
+      case 0: 
+        {
+          double xyz[3];
+          V_coord((pVertex)ent, xyz);
+          fprintf (f,"SP(%g,%g,%g) {%g};\n",
+                   xyz[0],xyz[1],xyz[2],
+                   data[0]);
+          break;
+        }
+      case 1: 
+        {
+          double xyz[2][3];
+          E_coordP1((pEdge)ent, xyz);
+          fprintf (f,"SL(%g,%g,%g,%g,%g,%g) {%g,%g};\n",
+                   xyz[0][0],xyz[0][1],xyz[0][2],
+                   xyz[1][0],xyz[1][1],xyz[1][2],
+                   data[0],data[1]);
+          break;
+        }
+      case 2: 
+        {
+          double xyz[3][3];
+          F_coordP1((pFace)ent, xyz);
+          fprintf (f,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g};\n",
+                   xyz[0][0],xyz[0][1],xyz[0][2],
+                   xyz[1][0],xyz[1][1],xyz[1][2],
+                   xyz[2][0],xyz[2][1],xyz[2][2],
+                   data[0],data[1],data[2]);
+          break;
+        }
+      case 3: 
+        {
+          double xyz[4][3];
+          R_coordP1((pRegion)ent, xyz);
+          fprintf (f,"SS(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g,%g};\n",
+                   xyz[0][0],xyz[0][1],xyz[0][2],
+                   xyz[1][0],xyz[1][1],xyz[1][2],
+                   xyz[2][0],xyz[2][1],xyz[2][2],
+                   xyz[3][0],xyz[3][1],xyz[3][2],
+                   data[0],data[1],data[2],data[3]);
+          break;
+        }
+      }
+      delete [] data;
+    }
+
+    fprintf (f,"};\n");
+    fclose (f);
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/output/MAdOutput.h b/Adapt/output/MAdOutput.h
new file mode 100644
index 0000000..1246af5
--- /dev/null
+++ b/Adapt/output/MAdOutput.h
@@ -0,0 +1,65 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MADOUTPUT
+#define _H_MADOUTPUT
+
+#include "SizeFieldBase.h"
+#include "MSops.h"
+
+#include <string>
+#include <set>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  typedef enum MAdOutputData {
+    OD_CONSTANT = 0,
+    OD_MEANRATIO = 1,
+    OD_ORIENTEDMEANRATIO = 2,
+    OD_SIZEFIELD_MEAN = 3,
+    OD_SIZEFIELD_MIN = 4,
+    OD_SIZEFIELD_MAX = 5,
+    OD_DIMENSION = 6,
+    OD_ITERORDER = 7,
+    OD_CURVATURE_DIV = 8,
+    OD_CURVATURE_MAX = 9,
+    OD_CURVATURE_MIN = 10,
+    OD_CURVATURE_MAX_VEC = 11,
+    OD_CURVATURE_MIN_VEC = 12,
+    OD_ANISO_SF_AXIS0 = 13,
+    OD_ANISO_SF_AXIS1 = 14,
+    OD_ANISO_SF_AXIS2 = 15
+  } MAdOutputData;
+
+  // -------------------------------------------------------------------
+
+  void MAdGmshOutput(const pMesh m, const pSField sf, 
+                     const char *fn, MAdOutputData type);
+
+  void MAdAttachedNodalDataOutput   (const pMesh m, const char *fn, 
+                                     pMeshDataId id);
+  void MAdAttachedNodalDataVecOutput(const pMesh m, const char *fn, 
+                                     pMeshDataId id);
+
+  void printPosEntities(const pPList ents, std::string fn, MAdOutputData type, 
+                        const pSField sf=NULL, int id=0);
+
+  void printPosRegions(const std::set<pRegion>, std::string fn, MAdOutputData type, 
+                       const pSField sf=NULL, int id=0);
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/quality/ElementEvaluatorBase.h b/Adapt/quality/ElementEvaluatorBase.h
new file mode 100644
index 0000000..75c7329
--- /dev/null
+++ b/Adapt/quality/ElementEvaluatorBase.h
@@ -0,0 +1,67 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_ELEMENTEVALUATORBASE
+#define _H_ELEMENTEVALUATORBASE
+
+#include "DiscreteSF.h"
+#include "MeshDataBaseInterface.h"
+
+#include <string>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  enum evaluationType {
+    UNKNOWNEVALTYPE,
+    MEANRATIO,
+    ORIENTEDMEANRATIO
+  };
+
+  // -------------------------------------------------------------------
+  class elementEvaluatorBase {
+
+  public:
+
+    elementEvaluatorBase(const DiscreteSF * f): sizeField(f) { setDefaultAcptValue(); }
+    virtual ~elementEvaluatorBase() {};
+  
+    void setSizeField(const DiscreteSF * sf) {sizeField = sf;}
+
+    virtual int R_shape(const pRegion r, double * result) const = 0;
+    virtual int F_shape(const pFace f, const double normal[3], double * result) const = 0;
+    virtual int XYZ_R_shape(const double[4][3], const pMSize[4], double * result) const = 0;
+    virtual int XYZ_F_shape(const double[3][3], const pMSize[3], const double normal[3], double * result) const = 0;
+
+    virtual inline double worstShapeEver() const {return 0.;}
+    virtual inline double bestShapeEver()  const {return 1.;}
+    virtual inline double whatsWorst(double shp1, double shp2) const {return std::min(shp1,shp2);}
+
+    virtual evaluationType getType () const = 0;
+    virtual std::string getName () const = 0;
+
+    double getAcceptableValue() { return acptValue; }
+    void setAcptValue(double t) { acptValue = t; }
+    void setDefaultAcptValue() { acptValue = 1.0e-10; }
+
+  protected:
+ 
+    const DiscreteSF * sizeField;
+    double acptValue;
+  };
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/quality/ElementStatistics.h b/Adapt/quality/ElementStatistics.h
new file mode 100644
index 0000000..39798f1
--- /dev/null
+++ b/Adapt/quality/ElementStatistics.h
@@ -0,0 +1,71 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_ELEMENTSTATISTICS
+#define _H_ELEMENTSTATISTICS
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class ElementStatistics {
+
+  public:
+
+    ElementStatistics();
+    ElementStatistics(const ElementStatistics &);
+    ~ElementStatistics() {};
+
+    // interface to set information
+    void reset();
+    void setWorstShape(double v) { worstShape = v; }
+    void setMaxLenSq(double v)   { maxLenSq   = v; }
+    void setMinLenSq(double v)   { minLenSq   = v; }
+
+    // interface to get information
+    double getWorstShape() const { return worstShape; }
+    double getMaxLenSq()   const { return maxLenSq;   }
+    double getMinLenSq()   const { return minLenSq;   }
+
+  private:
+
+    double worstShape;
+    double minLenSq, maxLenSq;
+  };
+
+  // -------------------------------------------------------------------
+  inline ElementStatistics::ElementStatistics()
+  {
+    reset();
+  }
+
+  // -------------------------------------------------------------------
+  inline ElementStatistics::ElementStatistics(const ElementStatistics & eq)
+  {
+    worstShape   = eq.worstShape;
+    minLenSq     = eq.minLenSq;
+    maxLenSq     = eq.maxLenSq;
+  }
+
+  // -------------------------------------------------------------------
+  inline void ElementStatistics::reset()
+  {
+    worstShape = MAdBIG;
+    minLenSq   = MAdBIG;
+    maxLenSq   = 0.0;
+  }
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/quality/MeanRatioEvaluator.cc b/Adapt/quality/MeanRatioEvaluator.cc
new file mode 100644
index 0000000..d41e5d7
--- /dev/null
+++ b/Adapt/quality/MeanRatioEvaluator.cc
@@ -0,0 +1,169 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MeanRatioEvaluator.h"
+
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::string;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  meanRatioEvaluator::meanRatioEvaluator(const DiscreteSF * f): 
+    elementEvaluatorBase(f)
+  {}
+
+  // -------------------------------------------------------------------
+  int meanRatioEvaluator::F_shape(const pFace face, const double normal[3],
+                                  double * shape) const
+  {
+    double fxyz[3][3];
+    pMSize pS[3];
+
+    void *iter=0;
+    int i = 0;
+    pPList fvts=F_vertices(face,1);
+    while( pVertex vt=(pVertex)PList_next(fvts,&iter) ) {
+      pS[i]=sizeField->findSize(vt);
+      V_coord(vt,fxyz[i++]);  
+    }
+    PList_delete(fvts);
+
+    return XYZ_F_shape(fxyz,pS,normal,shape);  
+  }
+
+  // -------------------------------------------------------------------
+  int meanRatioEvaluator::XYZ_F_shape(const double xyz[3][3], const pMSize pS[3], 
+                                      const double nor[3], double * shape) const
+  {
+    if( sizeField->getType() == NULLSFIELD ) {
+      if( ! XYZ_F_shape(xyz,pS[0],nor,shape) )
+        { *shape=0; return 0; }
+      return 1;
+    }
+
+    // use central size to compute shape
+    pMSize pSZ = MS_interpolate(pS[0], pS[1], pS[2], 0.33, 0.33);
+    int res = XYZ_F_shape(xyz, pSZ, nor, shape);
+    if ( pSZ ) delete pSZ;
+    return res;
+
+//     // compute shapes using sizes at every vertex and retain the worst one
+//     double shp[3];
+//     for(int i=0; i<3; i++) {
+//       if( ! XYZ_F_shape(xyz, pS[i], nor, &shp[i]) )
+//         { *shape = 0.; return 0; }
+//     }
+//     *shape = std::min(std::min(shp[0],shp[1]),shp[2]);
+//     return 1;
+  }
+
+  // -------------------------------------------------------------------
+  int meanRatioEvaluator::XYZ_F_shape(const double xyz[3][3], const pMSize pS, 
+                                      const double nor[3], double * shape) const
+  {
+    double aSq,sumSq;
+  
+    aSq = sizeField->SF_XYZ_areaSq(xyz,pS,nor);
+
+    if( aSq <= 0. ) { *shape = 0.; return 0; } 
+  
+    sumSq  = sizeField->SF_XYZ_lengthSq(xyz[1],xyz[0],pS);
+    sumSq += sizeField->SF_XYZ_lengthSq(xyz[2],xyz[0],pS);
+    sumSq += sizeField->SF_XYZ_lengthSq(xyz[1],xyz[2],pS);
+    
+    *shape = 48.*aSq/(sumSq*sumSq);
+
+    if(*shape < acptValue) return 0;
+    else if (*shape > (1.+MAdTOL) ) *shape = 1.;
+
+    return 1;
+  }
+
+  // -------------------------------------------------------------------
+  int meanRatioEvaluator::R_shape(const pRegion rgn, double * shape) const
+  {
+    double rxyz[4][3];
+    pMSize pS[4];
+  
+    void *iter=0;
+    int i=0;
+    pPList verts=R_vertices(rgn);
+    while( pVertex vt=(pVertex)PList_next(verts,&iter) ) {
+      pS[i]=sizeField->findSize(vt);
+      V_coord(vt,rxyz[i++]);
+    }  
+    PList_delete(verts);
+
+    return XYZ_R_shape(rxyz,pS,shape);
+  }
+
+  // -------------------------------------------------------------------
+  int meanRatioEvaluator::XYZ_R_shape(const double xyz[4][3], const pMSize pS[4], 
+                                      double * shape) const
+  {
+    if( sizeField->getType() == NULLSFIELD ) {
+      if( ! XYZ_R_shape(xyz,pS[0],shape) )
+        { *shape=0.; return 0; }
+      return 1;
+    }
+
+    // use central size
+    pMSize pSZ = MS_interpolate(pS[0], pS[1], pS[2], pS[3], 0.25, 0.25, 0.25);
+
+    // use minimal size
+//     pMSize pSZ;
+//     double hmin = MAdBIG;
+//     for(int i=0; i<4; i++) {
+//       if( pS[i] ) {
+//         double s = pS[i]->minSize();
+//         if( s <  hmin ) { hmin = s; pSZ = pS[i]; }
+//       }
+//     }
+//     assert( hmin != MAdBIG );
+
+    int res = XYZ_R_shape(xyz,pSZ,shape);
+    if ( pSZ ) delete pSZ;
+    return res;
+  }
+
+  // -------------------------------------------------------------------
+  int meanRatioEvaluator::XYZ_R_shape(const double xyz[4][3], const pMSize pS, 
+                                      double * shape) const
+  {
+    double vol,sumSq;
+  
+    vol = sizeField->SF_XYZ_volume(xyz,pS);
+
+    if ( vol < 0. ) { *shape = 0.; return 0; }
+  
+    sumSq  = sizeField->SF_XYZ_lengthSq(xyz[1],xyz[0],pS);
+    sumSq += sizeField->SF_XYZ_lengthSq(xyz[2],xyz[0],pS);
+    sumSq += sizeField->SF_XYZ_lengthSq(xyz[3],xyz[0],pS);
+    sumSq += sizeField->SF_XYZ_lengthSq(xyz[3],xyz[1],pS);
+    sumSq += sizeField->SF_XYZ_lengthSq(xyz[3],xyz[2],pS);
+    sumSq += sizeField->SF_XYZ_lengthSq(xyz[1],xyz[2],pS);
+
+    *shape = 15552.*vol*vol/(sumSq*sumSq*sumSq);
+
+    if(*shape < acptValue) return 0;
+    else if (*shape > (1.+MAdTOL) ) *shape = 1.;
+
+    return 1;
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/quality/MeanRatioEvaluator.h b/Adapt/quality/MeanRatioEvaluator.h
new file mode 100644
index 0000000..018242c
--- /dev/null
+++ b/Adapt/quality/MeanRatioEvaluator.h
@@ -0,0 +1,66 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MEANRATIOEVALUATOR
+#define _H_MEANRATIOEVALUATOR
+
+#include "ElementEvaluatorBase.h"
+
+/* -------------------------------------------------------------------
+
+Computes the cubic of the mean ratio of any element of the mesh (tri or tet)
+The mean ratio is expressed as:
+
+For tetrahedrons:
+     
+eta = 12 * ( ( 3*Volume ) ^ (2/3) ) / ( sum(edgeLength^2) )
+
+or equivalently:
+
+eta ^ 3 = 15552 * (Volume) ^ 2 / ( sum(edgeLength^2) ) ^ 3
+
+For triangles:
+
+eta ^ 2 = 48 * ( Area ^ 2 ) / ( sum(edgeLength^2) ) ^ 2
+
+This ensures ratios ranging from 0 (flat element) to 1 (equilateral)
+
+------------------------------------------------------------------- */
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class meanRatioEvaluator : public elementEvaluatorBase
+  {
+  public: 
+    meanRatioEvaluator(const DiscreteSF * f);
+    virtual ~meanRatioEvaluator() {}
+
+    virtual int F_shape(const pFace pf, const double normal[3], double * result) const;
+    virtual int R_shape(const pRegion pr, double * result) const;
+    virtual int XYZ_F_shape(const double[3][3], const pMSize[3], const double normal[3], double * result) const;
+    virtual int XYZ_R_shape(const double[4][3], const pMSize[4], double * result) const;
+
+    virtual evaluationType getType () const {return MEANRATIO;}
+    virtual std::string getName () const {return "Mean ratio";}
+
+  protected:
+    virtual int XYZ_F_shape(const double[3][3], const pMSize pS, const double normal[3], double * result) const;
+    virtual int XYZ_R_shape(const double[4][3], const pMSize pS, double * result) const;
+  };
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/quality/MeshQualityManager.cc b/Adapt/quality/MeshQualityManager.cc
new file mode 100644
index 0000000..03acff6
--- /dev/null
+++ b/Adapt/quality/MeshQualityManager.cc
@@ -0,0 +1,678 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MeshQualityManager.h"
+#include "MeanRatioEvaluator.h"
+#include "OrientedMeanRatioEvaluator.h"
+#include "CallBackManager.h"
+
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::ostream;
+#include <iomanip>
+#include <math.h>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  void QualityDeletingCBFunctionMove (pVertex pv, double *, void *) 
+  {
+    MeshQualityManagerSgl::instance().clearNeighbourShapes(pv);
+  }
+
+  // -------------------------------------------------------------------
+  void QualityDeletingCBFunction (pPList before, pPList after, void *,
+                                  operationType type , pEntity ppp) 
+  {
+    switch (type) {
+    case MAd_ESPLIT: {
+      // In the edge split case, we have to delete the shapes associated to the old elements
+
+      // find the old edge
+      void *tmp=0;
+      pEntity pE = PList_next(before,&tmp);
+
+      // clear all shapes in the neighbour of the edge
+      MeshQualityManagerSgl::instance().clearNeighbourShapes((pEdge) pE);
+    
+      break;
+    } 
+    case MAd_ECOLLAPSE: {
+      // In the edge collapse case, we have to delete the shapes attached to the neighbour elements of the deleted node.
+      // clear all shapes in the neighbour of the deleted node
+      MeshQualityManagerSgl::instance().clearNeighbourShapes((pVertex) ppp);
+  
+      break;
+    }
+    case MAd_FSWAP:{
+      // In the face swap case, we have to delete the shapes associated to the old elements
+      void * temp = NULL;
+      while ( pEntity ent = PList_next(before,&temp) ) {
+        MeshQualityManagerSgl::instance().clearShape(ent);
+      }
+      break;
+    } 
+    case MAd_ESWAP: {
+      // In the edge swap case, we have to delete the shapes associated to the old elements
+      void * temp = NULL;
+      while ( pEntity ent = PList_next(before,&temp) ) {
+        MeshQualityManagerSgl::instance().clearShape(ent);
+      }
+      break;
+    } 
+    case MAd_RREMOVE: {
+      // delete the shape associated to the deleted region
+      MeshQualityManagerSgl::instance().clearShape(ppp);
+      break;
+    }
+    default: {
+      printf("Error in MeshQualityManager: Callback function not implemented for mesh modification %d",
+             type);  
+      throw;
+    }
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void MeshQualityManager::initialize(pMesh m, DiscreteSF * sf, evaluationType type)
+  {
+    mesh = m;
+    sizeField = sf;
+
+    dim = M_dim(mesh);
+    shapeId = MD_newMeshDataId("");
+
+    switch(type) {
+    case MEANRATIO: {
+      if(!evaluator) {
+        evaluator = new meanRatioEvaluator(sizeField);
+      }
+      break;
+    }
+    default: {
+      cerr << "Error: unknown evaluation type when initializing the mesh quality manager\n";
+      throw;
+    }
+    }
+
+    CallBackManagerSgl::instance().registerCallBack(QualityDeletingCBFunction,NULL);
+    CallBackManagerSgl::instance().registerCallBackMove(QualityDeletingCBFunctionMove,NULL);
+
+    if(!histogram) {
+      histogram = new int[10];
+    }
+    if(!histogramAvg) {
+      histogramAvg = new double[10];
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void MeshQualityManager::setMesh(pMesh m)
+  {
+    mesh = m;
+    dim = M_dim(mesh);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshQualityManager::finalize()
+  {
+    clearAllShapes();
+    MD_deleteMeshDataId(shapeId);
+    if (evaluator) {
+      delete evaluator;
+      evaluator=NULL;
+    }
+    if (histogram) {
+      delete [] histogram;
+      histogram=NULL;
+    }
+    if (histogramAvg) {
+      delete [] histogramAvg;
+      histogramAvg=NULL;
+    }
+  }
+
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  void MeshQualityManager::evaluateAllShapes() const
+  {
+    if (!mesh) {
+      cout << "Warning: Could not evaluate shapes in the element evaluator: no mesh specified\n";
+      return;
+    }
+
+    if ( dim == 3 ) {
+      RIter rit = M_regionIter(mesh);
+      while ( pRegion pr = RIter_next(rit) ) {
+        double tmp;
+        if ( !getAttachedShape((pEntity)pr,&tmp) ) {
+          double shape;
+          evaluator->R_shape(pr,&shape);
+          attachShape((pEntity)pr, shape);
+        }
+      }
+      RIter_delete(rit);
+    }
+    else {
+      FIter fit = M_faceIter(mesh);
+      while ( pFace pf = FIter_next(fit) ) {
+        double tmp;
+        if ( !getAttachedShape((pEntity)pf,&tmp) ) {
+          double shape;
+          evaluator->F_shape(pf,0,&shape);
+          attachShape((pEntity)pf, shape);
+        }
+      }
+      FIter_delete(fit);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void MeshQualityManager::evaluateAndReplaceAllShapes() const
+  {
+    if (!mesh) {
+      cout << "Warning: Could not evaluate shapes in the element evaluator: no mesh specified\n";
+      return;
+    }
+
+    if ( dim == 3 ) {
+      RIter rit = M_regionIter(mesh);
+      while ( pRegion pr = RIter_next(rit) ) {
+        double shape;
+        evaluator->R_shape(pr,&shape);
+        attachShape((pEntity)pr, shape);
+      }
+      RIter_delete(rit);
+    }
+    else {
+      FIter fit = M_faceIter(mesh);
+      while ( pFace pf = FIter_next(fit) ) {
+        double shape;
+        evaluator->F_shape(pf,0,&shape);
+        attachShape((pEntity)pf, shape);
+      }
+      FIter_delete(fit);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  int MeshQualityManager::getShape(pFace pf, double normal[3], double * result) const
+  {
+    return evaluator->F_shape(pf,normal,result);
+  }
+
+  // -------------------------------------------------------------------
+  int MeshQualityManager::getShape(pRegion pr, double * result) const
+  {
+    //   return evaluator->R_shape(pr,result);
+    if ( !getAttachedShape((pEntity)pr, result) ) {
+      int flag = evaluator->R_shape(pr,result);
+      attachShape((pEntity)pr,*result);
+      return flag;
+    }
+
+    if ( *result < evaluator->getAcceptableValue() ) return 0;
+    return 1;
+  }
+
+  // -------------------------------------------------------------------
+  void MeshQualityManager::clearAllShapes() const
+  {
+    if (!mesh) {
+      cout << "Warning: Could not clear shapes in the element evaluator: no mesh specified\n";
+      return;
+    }
+
+    if ( dim == 3 ) {
+      RIter rit = M_regionIter(mesh);
+      while ( pRegion pr = RIter_next(rit) ) {
+        clearShape((pEntity)pr);
+      }
+      RIter_delete(rit);
+    }
+    else {
+      FIter fit = M_faceIter(mesh);
+      while ( pFace pf = FIter_next(fit) ) {
+        clearShape((pEntity)pf);
+      }
+      FIter_delete(fit);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void MeshQualityManager::clearShape(pEntity pe) const
+  {
+    EN_deleteData(pe, shapeId);
+  }
+
+  // -------------------------------------------------------------------
+  void MeshQualityManager::clearNeighbourShapes(pVertex pv) const
+  {
+    if ( dim==3 ) {
+      pPList regs = V_regions(pv);
+      void* temp=0;
+      while ( pEntity region = PList_next(regs,&temp) ) {
+        clearShape( region );
+      }
+      PList_delete(regs);
+    }
+    else {
+      pPList faces = V_faces(pv);
+      void* temp=0;
+      while ( pEntity face = PList_next(faces,&temp) ) {
+        clearShape( face );
+      }
+      PList_delete(faces);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void MeshQualityManager::clearNeighbourShapes(pEdge pe) const
+  {
+    if ( dim==3 ) {
+      pPList regs = E_regions(pe);
+      void* temp=0;
+      while ( pEntity region = PList_next(regs,&temp) ) {
+        clearShape( region );
+      }
+      PList_delete(regs);
+    }
+    else {
+      pPList faces = E_faces(pe);
+      void* temp=0;
+      while ( pEntity face = PList_next(faces,&temp) ) {
+        clearShape( face );
+      }
+      PList_delete(faces);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  int MeshQualityManager::V_worstShape(pVertex vt, double* result) const 
+  {
+    pRegion region;
+    pPList rlist = V_regions(vt);
+    double worst = evaluator->bestShapeEver();
+    double shape_1;
+
+    double mtol = evaluator->getAcceptableValue();
+    void *temp=0;
+  
+    if( PList_size(rlist)==0 ) {
+      // 2D case
+      pPList flist = V_faces(vt);
+      pFace face;
+      while( ( face = (pFace)PList_next(flist,&temp) ) ) {
+        getShape(face,0,&shape_1);
+        if( shape_1 <= mtol ) {
+          PList_delete(flist);
+          *result = shape_1;
+          return 0;
+        }
+        if(shape_1 < worst)
+          worst = shape_1;
+      }
+      PList_delete(flist);
+    }
+    else {
+      // 3D case
+      while( ( region = (pRegion)PList_next(rlist,&temp) ) ) {
+        getShape(region,&shape_1);
+        if( shape_1 <= mtol ) {
+          PList_delete(rlist);
+          *result = shape_1;
+          return 0;
+        }
+        if(shape_1 < worst)
+          worst = shape_1;
+      }
+    }
+  
+    PList_delete(rlist);
+    *result = worst;
+    return 1;
+  }
+
+  // -------------------------------------------------------------------
+
+  int MeshQualityManager::E_worstShape(pEdge e, double* result) const {
+  
+    double worst = evaluator->bestShapeEver();
+    double shape_1;
+    double mtol = evaluator->getAcceptableValue();
+
+    // 2D case
+    if( E_numRegions(e)==0 ) {
+      pFace face;
+      for( int i=0; i<E_numFaces(e); i++ ) {
+        face=E_face(e,i);
+        if (!getShape(face,0,&shape_1) || shape_1 <= mtol ) {
+          *result = 0.0; return 0;
+        }
+        if( shape_1 < worst)  worst = shape_1;
+      }
+    }
+    // 3D case
+    else {
+      pPList rlist = E_regions(e);
+      pRegion region; void *temp=0;
+      while( ( region=(pRegion)PList_next(rlist,&temp) ) ) {
+        if ( !getShape(region,&shape_1) || shape_1 <= mtol ) {
+          PList_delete(rlist); *result = 0.0; return 0;
+        }
+        if( shape_1 < worst)  worst = shape_1;
+      }
+      PList_delete(rlist);
+    }
+
+    *result = worst;
+    return 1;
+  }
+
+  // -------------------------------------------------------------------
+
+  int MeshQualityManager::F_worstShape(pFace f, double* result) const {
+  
+    double worst = evaluator->bestShapeEver();
+    double shape_1;
+    double mtol = evaluator->getAcceptableValue();
+
+    pPList rlist = F_regions(f);
+    pRegion region; void *temp=0;
+    while( ( region=(pRegion)PList_next(rlist,&temp) ) ) {
+      if ( !getShape(region,&shape_1) || shape_1 <= mtol ) {
+        PList_delete(rlist); *result = 0.0; return 0;
+      }
+      if( shape_1 < worst)  worst = shape_1;
+    }
+    PList_delete(rlist);
+
+    *result = worst;
+    return 1;
+  }
+
+  // -------------------------------------------------------------------
+  int MeshQualityManager::FList_worstShape(pPList faces, double * result) const
+  {
+    double worst = evaluator->bestShapeEver();
+
+    void* tmp=0;
+    while( pEntity pe = PList_next(faces,&tmp) ) {
+    
+      if ( EN_type(pe) != 2 ) {
+        cerr << "Error: Received an entity of dimension " << EN_type(pe) << " in FList_worstShape\n";
+        throw;
+      }
+    
+      double shape;
+      if ( !getShape( (pFace)pe, 0, &shape) ) {
+        *result = 0;
+        return 0;
+      }
+      else {
+        worst = evaluator->whatsWorst(shape, worst);
+      }
+    }
+
+    *result = worst;
+
+    return 1;
+  }
+
+  // -------------------------------------------------------------------
+  int MeshQualityManager::RList_worstShape(pPList regions, double * result) const
+  {
+    double worst = evaluator->bestShapeEver();
+
+    void* tmp=0;
+    while( pEntity pe = PList_next(regions,&tmp) ) {
+    
+      if ( EN_type(pe) != 3 ) {
+        cerr << "Error: Received an entity of dimension " << EN_type(pe) << " in RList_worstShape\n";
+        throw;
+      }
+    
+      double shape;
+      if ( !getShape( (pRegion)pe, &shape) ) {
+        *result = 0.;
+        return 0;
+      }
+      else {
+        worst = evaluator->whatsWorst(shape, worst);
+      }
+    }
+
+    *result = worst;
+
+    return 1;
+  }
+
+  // -------------------------------------------------------------------
+  void MeshQualityManager::attachShape(pEntity pe, double shape) const
+  {
+    EN_modifyDataDbl(pe, shapeId, shape);
+  }
+
+  // -------------------------------------------------------------------
+  bool MeshQualityManager::getAttachedShape(const pEntity pe, double* result) const
+  {
+    if ( !EN_getDataDbl(pe, shapeId, result) ) return false;
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool MeshQualityManager::checkAttachedShapes() const
+  {
+    bool ok = true;
+
+    int noData = 0;
+    int dataOK = 0;
+    int wrongData = 0;
+
+    if (dim == 3) {
+      RIter rit = M_regionIter(mesh);
+      while ( pRegion pr = RIter_next(rit) ) {
+        double attachedShape;
+        if ( !getAttachedShape((pEntity)pr,&attachedShape) ) noData++;
+        else {
+          double shape;
+          evaluator->R_shape(pr,&shape);
+          if ( fabs(shape - attachedShape) <= 1.e-12 ) dataOK++;
+          else { 
+            cout<<"Warning: wrong shape found: attached: "<<attachedShape<<", real: "<<shape<<endl;
+            wrongData++; 
+            ok = false;
+          }
+        }
+      }
+      RIter_delete(rit);
+    }
+    else {
+      FIter fit = M_faceIter(mesh);
+      while ( pFace pf = FIter_next(fit) ) {
+        double attachedShape;
+        if ( !getAttachedShape((pEntity)pf,&attachedShape) ) noData++;
+        else {
+          double shape;
+          evaluator->F_shape(pf,0,&shape);
+          if ( fabs(shape - attachedShape) <= 1.e-12 ) dataOK++;
+          else { 
+            cout<<"Warning: wrong shape found: attached: "<<attachedShape<<", real: "<<shape<<endl;
+            wrongData++;
+            ok = false;
+          }
+        }
+      }
+      FIter_delete(fit);
+    }
+
+    cout << "\nAttached shapes report:\n\n";
+    cout << "Elements checked: "<<noData+dataOK+wrongData<<endl;
+    cout << "Elements with no attached shape: "<<noData<<endl;
+    cout << "Elements with a correct shape: "<<dataOK<<endl;
+    cout << "Elements with a wrong shape: "<<wrongData<<endl;
+    cout<<endl;
+
+    return ok;
+  }
+
+  // -------------------------------------------------------------------
+  void MeshQualityManager::evaluateSizes()
+  {
+    minAbsoluteSize = MAdBIG;
+    maxAbsoluteSize = 0.;
+    sizesSum = 0.;
+
+    switch( dim )
+      {
+      case 3: {
+        RIter rit = M_regionIter(mesh);
+        while ( pRegion r = RIter_next(rit) ) 
+          {
+            double vol = R_volume(r);
+            minAbsoluteSize = std::min(minAbsoluteSize,vol);
+            maxAbsoluteSize = std::max(maxAbsoluteSize,vol);
+            sizesSum += vol;
+          }
+        RIter_delete(rit);
+        break;
+      }
+      case 2: {
+        FIter fit = M_faceIter(mesh);
+        while ( pFace f = FIter_next(fit) ) 
+          {
+            double area = F_area(f,0);
+            minAbsoluteSize = std::min(minAbsoluteSize,area);
+            maxAbsoluteSize = std::max(maxAbsoluteSize,area);
+            sizesSum += area;
+          }
+        FIter_delete(fit);
+        break;
+      }
+      default: {
+        cerr << "Dimension " << dim << " not handled by meshEvaluator\n";
+        throw;
+      }
+      }
+  }
+
+  // -------------------------------------------------------------------
+  void MeshQualityManager::evaluateShapes()
+  {
+    worstShape = evaluator->bestShapeEver();
+    meanShape = 0.;
+    for (int i=0; i<10; i++) histogram[i]=0;
+    notAcpt = 0;
+
+    switch( dim )
+      {
+      case 3: {
+        nbElem = M_numRegions(mesh);
+        RIter rit = M_regionIter(mesh);
+        while ( pRegion r = RIter_next(rit) ) 
+          {
+            double shape;
+            if ( !getShape(r,&shape) )  notAcpt++;
+            else if (shape < 0.) {cerr << "Error: element with negative quality\n"; throw;}
+            else {
+              if (shape >= 1.) { shape = 1.-MAdTOL; }
+              unsigned int qualityLevel = (unsigned int)floor(shape*10.);
+              if ( qualityLevel == 10 ) qualityLevel = 9;
+              histogram[qualityLevel]++;
+            }
+            meanShape += shape;
+            worstShape = evaluator->whatsWorst(worstShape,shape);
+          }
+        RIter_delete(rit);
+        break;
+      }
+      case 2: {
+        nbElem = M_numFaces(mesh);
+        FIter fit = M_faceIter(mesh);
+        while ( pFace f = FIter_next(fit) ) {
+          double shape;
+          if ( !getShape(f,0,&shape))  histogram[0]++;
+          else if (shape < 0.) {cerr << "Error: element with negative quality\n"; throw;}
+          else if (shape > 1.) { shape = 1.; }
+          else {
+            unsigned int qualityLevel = (unsigned int)floor(shape*10);
+            histogram[qualityLevel]++;
+          }
+          meanShape += shape;
+          worstShape = evaluator->whatsWorst(worstShape,shape);
+        }
+        FIter_delete(fit);
+        break;
+      }
+      default: {
+        cerr << "Dimension " << dim << " not handled by meshEvaluator\n";
+        throw;
+      }
+      }
+
+    meanShape /= nbElem;
+    for (int i=0; i<10; i++) histogramAvg[i] = (double)histogram[i] / nbElem;
+  }
+
+  // -------------------------------------------------------------------
+  void MeshQualityManager::evaluateStatistics()
+  {
+    evaluateSizes();
+    evaluateShapes();
+  }
+
+  // -------------------------------------------------------------------
+  void MeshQualityManager::printStatistics(ostream& out) const
+  {
+    out << "\n ---------- Mesh quality report ----------\n\n";
+    out << "Criterion: " << evaluator->getName() << "\n\n";
+    out << "  Average element quality\t"<<std::setprecision(4)<<meanShape<<"\n";
+    out << "  Worst element quality\t\t"<<std::setprecision(4)<<worstShape<<"\n";
+    out << "  Non acceptable elements\t"<< notAcpt << " \n";
+    out << std::setprecision(2) << std::setw(0); 
+    out << std::fixed;
+
+    out << "\n        --- Histogram ---\n\n";
+
+    for (int i = 0; i < 10; i++) {
+      out <<std::setprecision(1)
+          << "  " << ((double)i)/10. << "  < Q <  " << ((double)(i+1))/10. << "  :  "
+          <<std::setprecision(2)<<std::setw(5)
+          << (histogramAvg[i])*100. <<" % "<<std::setw(7)<< histogram[i]<<" elements\n";
+    }
+    out<<endl;
+
+    out << std::setprecision(6) << std::setw(0); // return to default values
+    out.unsetf(std::ios::floatfield);            // return to default values
+
+    out<<"  Smallest ";
+    if (dim == 3) out <<"volume ";
+    else out<<"area ";
+    out <<"(absolute space)\t"<< minAbsoluteSize << "\n";
+    out<<"  Biggest ";
+    if (dim == 3) out <<"volume ";
+    else out<<"area ";
+    out <<"(absolute space)\t"<< maxAbsoluteSize << "\n";
+    out<<"  Total ";
+    if (dim == 3) out <<"volume ";
+    else out<<"area ";
+    out <<"   (absolute space)\t"<< sizesSum << "\n\n";
+  }
+
+  // -------------------------------------------------------------------
+
+}
+
diff --git a/Adapt/quality/MeshQualityManager.h b/Adapt/quality/MeshQualityManager.h
new file mode 100644
index 0000000..d7cb5fc
--- /dev/null
+++ b/Adapt/quality/MeshQualityManager.h
@@ -0,0 +1,139 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MESHQUALITYMANAGER
+#define _H_MESHQUALITYMANAGER
+
+#include "SizeFieldBase.h"
+#include "ElementEvaluatorBase.h"
+#include "MeshDataBaseInterface.h"
+#include "MAdSingleton.h"
+
+#include <iostream>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class MeshQualityManager {
+
+  public:
+  
+    MeshQualityManager():evaluator(NULL), histogram(NULL), histogramAvg(NULL){};
+    ~MeshQualityManager() {};
+  
+    void initialize(pMesh m, DiscreteSF * sf, evaluationType type);
+    void setMesh(pMesh m);
+    void finalize();
+
+    // -------------------------------------------------------------------
+
+  public:
+
+    const pMeshDataId getShapeId() const { return shapeId; }
+    const elementEvaluatorBase * getElementEvaluator() const { return evaluator; }
+
+    // evaluate missing shapes
+    void evaluateAllShapes() const;
+
+    // evaluate all shapes, replace existing ones
+    void evaluateAndReplaceAllShapes() const;
+
+    // compute and return the shape of the face (no storage for faces)
+    // return 0 if the face is not acceptable, 1 otherwise
+    int getShape(pFace pf, double normal[3], double * result) const;
+
+    // get the shape of the region, compute and store the shape if missing
+    // return 0 if the region is not acceptable, 1 otherwise
+    int getShape(pRegion pr, double * result) const;
+
+    // delete all shapes
+    void clearAllShapes() const;
+
+    // delete the shape of this entity
+    void clearShape(pEntity pe) const;
+
+    // delete all shapes of the elements neighbouring the entity
+    void clearNeighbourShapes(pVertex pv) const;
+    void clearNeighbourShapes(pEdge pe) const;
+
+    // evaluate the worst shape of all elements surrounding one or several entities
+    int V_worstShape(pVertex v, double* result) const;
+    int E_worstShape(pEdge e,   double* result) const;
+    int F_worstShape(pFace f,   double* result) const;
+
+    // evaluate the worst shape in a list of elements
+    int FList_worstShape(pPList faces,   double * result) const;
+    int RList_worstShape(pPList regions, double * result) const;
+
+    // check that the attached shapes are still correct (debugging function)
+    bool checkAttachedShapes() const;
+
+  private:
+
+    // attach a computed shape to the entity
+    void attachShape(pEntity pe, double shape) const;
+
+    // get the shape of an entity if it exists, return false otherwise
+    bool getAttachedShape(const pEntity pe, double* result) const;
+
+  public:
+
+    // Evaluate statistics about elements sizes
+    void evaluateSizes();
+
+    // Evaluate statistics about elements shapes
+    void evaluateShapes();
+
+    // Evaluate all statistics
+    void evaluateStatistics();
+
+    // get statistics ( evaluate it first )
+    double getMeanShape()  const { return meanShape; }
+    double getWorstShape() const { return worstShape; }
+    double getMinSize()    const { return minAbsoluteSize; }
+    double getMaxSize()    const { return maxAbsoluteSize; }
+    void printStatistics(std::ostream& out) const;
+  
+    // -------------------------------------------------------------------
+
+  private:
+
+    pMesh mesh;
+    int dim;
+    DiscreteSF * sizeField;
+
+    elementEvaluatorBase* evaluator;
+
+    pMeshDataId shapeId;
+
+    // --- statistics ---
+    // ------------------
+    int nbElem;
+    double worstShape;
+    double meanShape;
+    double minAbsoluteSize; // Area or volume of the smallest element in usual space (no metric)
+    double maxAbsoluteSize; // Area or volume of the biggest  element in usual space (no metric)
+    double sizesSum;
+    int notAcpt;  // number of non acceptable elements
+    int* histogram; // counters of elements with different qualities
+    double* histogramAvg; // proportion of elements with different qualities
+
+  };
+
+  // -------------------------------------------------------------------
+
+  typedef MAdSingleton<MeshQualityManager> MeshQualityManagerSgl;
+
+}
+
+#endif
diff --git a/Adapt/quality/OrientedMeanRatioEvaluator.cc b/Adapt/quality/OrientedMeanRatioEvaluator.cc
new file mode 100644
index 0000000..0e09bf6
--- /dev/null
+++ b/Adapt/quality/OrientedMeanRatioEvaluator.cc
@@ -0,0 +1,123 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "OrientedMeanRatioEvaluator.h"
+#include "AnisoMeshSize.h"
+
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::string;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  orientedMeanRatioEvaluator::orientedMeanRatioEvaluator(const DiscreteSF * f): 
+    meanRatioEvaluator(f)
+  {}
+
+  // -------------------------------------------------------------------
+  int orientedMeanRatioEvaluator::XYZ_F_shape(const double xyz[3][3], const pMSize pS, 
+                                              const double nor[3], double * shape) const
+  {
+    double aSq,sumSq;
+  
+    aSq = sizeField->SF_XYZ_areaSq(xyz,pS,nor);
+
+    if( aSq <= 0. ) { *shape = 0.; return 0; } 
+  
+    sumSq  = sizeField->SF_XYZ_lengthSq(xyz[1],xyz[0],pS);
+    sumSq += sizeField->SF_XYZ_lengthSq(xyz[2],xyz[0],pS);
+    sumSq += sizeField->SF_XYZ_lengthSq(xyz[1],xyz[2],pS);
+    
+    *shape = 48.*aSq/(sumSq*sumSq);
+
+    if ( pS->getType() == ANISOTROPIC )
+      {
+        double tmp[3]; diffVec(xyz[1],xyz[0],tmp);
+        double cosa = fabs( ((AnisoMeshSize*)pS)->angleWithDir0(tmp) );
+        *shape *= ( fabs( cosa - 0.5 ) + 0.5 );
+        diffVec(xyz[2],xyz[0],tmp);
+        cosa = fabs( ((AnisoMeshSize*)pS)->angleWithDir0(tmp) );
+        *shape *= ( fabs( cosa - 0.5 ) + 0.5 );
+        diffVec(xyz[2],xyz[1],tmp);
+        cosa = fabs( ((AnisoMeshSize*)pS)->angleWithDir0(tmp) );
+        *shape *= ( fabs( cosa - 0.5 ) + 0.5 );
+      }
+
+    if(*shape < acptValue) return 0;
+    else if (*shape > (1.+MAdTOL) ) *shape = 1.;
+
+    return 1;
+  }
+
+  // -------------------------------------------------------------------
+  int orientedMeanRatioEvaluator::XYZ_R_shape(const double xyz[4][3], const pMSize pS, 
+                                              double * shape) const
+  {
+    double vol,sumSq;
+  
+    vol = sizeField->SF_XYZ_volume(xyz,pS);
+
+    if ( vol < 0. ) { *shape = 0.; return 0; }
+  
+    sumSq  = sizeField->SF_XYZ_lengthSq(xyz[1],xyz[0],pS);
+    sumSq += sizeField->SF_XYZ_lengthSq(xyz[2],xyz[0],pS);
+    sumSq += sizeField->SF_XYZ_lengthSq(xyz[3],xyz[0],pS);
+    sumSq += sizeField->SF_XYZ_lengthSq(xyz[3],xyz[1],pS);
+    sumSq += sizeField->SF_XYZ_lengthSq(xyz[3],xyz[2],pS);
+    sumSq += sizeField->SF_XYZ_lengthSq(xyz[1],xyz[2],pS);
+
+    *shape = 15552.*vol*vol/(sumSq*sumSq*sumSq);
+
+    if ( pS->getType() == ANISOTROPIC )
+      {
+        double dir0[3];  pS->direction(0,dir0); normalizeVec(dir0,dir0);
+        double orientFactor = 1.;
+        
+        double tmp[3]; diffVec(xyz[1],xyz[0],tmp); normalizeVec(tmp,tmp);
+        double cosa = fabs( dotProd(dir0,tmp) );
+        orientFactor *= ( fabs( cosa - 0.5 ) + 0.5 );
+        
+        diffVec(xyz[2],xyz[0],tmp); normalizeVec(tmp,tmp);
+        cosa = fabs( dotProd(dir0,tmp) );
+        orientFactor *= ( fabs( cosa - 0.5 ) + 0.5 );
+        
+        diffVec(xyz[3],xyz[0],tmp); normalizeVec(tmp,tmp);
+        cosa = fabs( dotProd(dir0,tmp) );
+        orientFactor *= ( fabs( cosa - 0.5 ) + 0.5 );
+        
+        diffVec(xyz[2],xyz[1],tmp); normalizeVec(tmp,tmp);
+        cosa = fabs( dotProd(dir0,tmp) );
+        orientFactor *= ( fabs( cosa - 0.5 ) + 0.5 );
+        
+        diffVec(xyz[3],xyz[1],tmp); normalizeVec(tmp,tmp);
+        cosa = fabs( dotProd(dir0,tmp) );
+        orientFactor *= ( fabs( cosa - 0.5 ) + 0.5 );
+        
+        diffVec(xyz[3],xyz[2],tmp); normalizeVec(tmp,tmp);
+        cosa = fabs( dotProd(dir0,tmp) );
+        orientFactor *= ( fabs( cosa - 0.5 ) + 0.5 );
+
+        *shape *= orientFactor;
+      }
+
+    if(*shape < acptValue) return 0;
+    else if (*shape > (1.+MAdTOL) ) *shape = 1.;
+
+    return 1;
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/quality/OrientedMeanRatioEvaluator.h b/Adapt/quality/OrientedMeanRatioEvaluator.h
new file mode 100644
index 0000000..c7d4cbb
--- /dev/null
+++ b/Adapt/quality/OrientedMeanRatioEvaluator.h
@@ -0,0 +1,68 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_ORIENTEDMEANRATIOEVALUATOR
+#define _H_ORIENTEDMEANRATIOEVALUATOR
+
+#include "MeanRatioEvaluator.h"
+
+/* -------------------------------------------------------------------
+
+Computes the cubic of the mean ratio of any element of the 
+mesh (tri or tet) penalised (for every edge 'e') by a factor 
+
+   | |cos(alpha_e)| - 0.5 | + 0.5
+
+where 'alpha_e' is the angle of 'e' with the direction of the minimal 
+size. This is equivalent to the mean ratio for isotropic sizes.
+
+The mean ratio is expressed as:
+
+For tetrahedrons:
+     
+  eta = 12 * ( ( 3*Volume ) ^ (2/3) ) / ( sum(edgeLength^2) )
+
+or equivalently:
+
+  eta ^ 3 = 15552 * (Volume) ^ 2 / ( sum(edgeLength^2) ) ^ 3
+
+For triangles:
+
+  eta ^ 2 = 48 * ( Area ^ 2 ) / ( sum(edgeLength^2) ) ^ 2
+
+This ensures ratios ranging from 0 (flat element) to 1 (equilateral)
+
+------------------------------------------------------------------- */
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class orientedMeanRatioEvaluator : public meanRatioEvaluator
+  {
+  public: 
+    orientedMeanRatioEvaluator(const DiscreteSF * f);
+    virtual ~orientedMeanRatioEvaluator() {}
+
+    virtual evaluationType getType () const {return ORIENTEDMEANRATIO;}
+    virtual std::string getName () const {return "Oriented mean ratio";}
+
+  protected:
+    virtual int XYZ_F_shape(const double[3][3], const pMSize pS, const double normal[3], double * result) const;
+    virtual int XYZ_R_shape(const double[4][3], const pMSize pS, double * result) const;
+  };
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/repositioning/GeoMatcher.cc b/Adapt/repositioning/GeoMatcher.cc
new file mode 100644
index 0000000..81dab88
--- /dev/null
+++ b/Adapt/repositioning/GeoMatcher.cc
@@ -0,0 +1,153 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "GeoMatcher.h"
+#include "CallBackManager.h"
+#include "MathUtils.h"
+#include "ModelInterface.h"
+#include "MAdMessage.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  void GeoMatcherCBFunction (pPList before, pPList after, void * data,
+                             operationType type , pEntity ppp) 
+  {
+#ifdef _HAVE_GMSH_
+    geoMatcher * gm = (geoMatcher *)(data);
+
+    switch (type) {
+    case MAd_ESPLIT: { 
+
+      if ( gm->relocationsComputed() ) {
+        MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                    "Applying an edge split during a geometry snapping procedure");
+      }
+
+      // if new point is on a line or surface, you need to find its 
+      // projection on the geometrical entity and impose its new 
+      // location as a Dirichlet BC in the elastic model
+
+      pGEntity pGE = V_whatIn( (pVertex)ppp );
+      int dimBnd = GEN_type(pGE);
+      if ( dimBnd < 3 ) {
+
+        double xyz[3]; // current position of the new point
+        V_coord( (pVertex)ppp, xyz );
+//         printVec(xyz,"Original location");
+
+        double u,v;
+        if ( !V_params((pVertex)ppp,&u,&v) ) {
+          V_info((pVertex)ppp);
+          MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                      "Not a parametric point");
+        }
+
+        double tgt[3]; // the target location
+        switch (dimBnd) {
+        case 2: { // on a surface
+          GF_xyz((pGFace)pGE, u, v, tgt);
+          break;
+        }
+        case 1: { // on a line
+          GE_xyz((pGEdge)pGE, u, tgt);
+          break;
+        }
+        default: {
+          MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                      "Unexpected geometric entity dimension for a new vertex: %d",
+                                      dimBnd);
+        }
+        }
+//         printVec(tgt,"Target location");
+
+        // compute the difference with the current position
+        double dx[3];
+        diffVec(tgt,xyz,dx);
+//         printVec(dx,"DISPLACEMENT");
+      
+        // impose the motion as a Dirichlet BC in the elastic model
+        smallVector dxVec(3);
+        for (int i=0; i<3; i++) dxVec(i) = dx[i];
+        gm->addDirichlet( (pVertex)ppp, dxVec );
+      }
+      break;
+    } 
+    case MAd_ECOLLAPSE: {
+      gm->delDirichlet( (pVertex)ppp );
+      gm->delRelocation( (pVertex)ppp );
+      break;
+    }
+    case MAd_FSWAP:
+    case MAd_ESWAP: {
+      break;
+    }
+    case MAd_RREMOVE: {
+      throw; // some nodes could become parametric: to be checked
+      void * temp = NULL;
+      while ( pEntity pE = PList_next(before,&temp) ) {
+        if ( EN_type(pE) == 0 ) {
+          gm->delDirichlet( (pVertex)pE );
+        }
+      }
+      break;
+    }
+    default: {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Callback function not implemented for mesh modification %d",
+                                  type);
+    }
+    }
+#endif
+  }
+
+  // -------------------------------------------------------------------
+  geoMatcher::geoMatcher(pMesh _mesh):
+    MAdElasticityOp(_mesh)
+  {
+    CallBackManagerSgl::instance().registerCallBack(GeoMatcherCBFunction,this);
+  }
+
+  // -------------------------------------------------------------------
+  geoMatcher::geoMatcher(const geoMatcher& gm):
+    MAdElasticityOp(gm)
+  {
+    CallBackManagerSgl::instance().registerCallBack(GeoMatcherCBFunction,this);
+  }
+
+  // -------------------------------------------------------------------
+  geoMatcher::~geoMatcher()
+  {
+    CallBackManagerSgl::instance().unregisterCallBack(GeoMatcherCBFunction,this);
+  }
+  
+  // -------------------------------------------------------------------
+  void geoMatcher::printFailures(std::ostream& out) const
+  {
+    if ( failures.size() ) {
+      out << "No failure reported in the GeoMatcher\n";
+    }
+    else {
+      out << failures.size() << " failures reported in the GeoMatcher:\n\n";
+      int i = 0;
+      std::list<double>::const_iterator it = failures.begin();
+      for (; it != failures.end(); it++)
+        {
+          out << i << "  ratio: " << *it << "\n";
+          i++;
+        }
+    }
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/repositioning/GeoMatcher.h b/Adapt/repositioning/GeoMatcher.h
new file mode 100644
index 0000000..9533d69
--- /dev/null
+++ b/Adapt/repositioning/GeoMatcher.h
@@ -0,0 +1,45 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_GEOMATCHER
+#define _H_GEOMATCHER
+
+#include "MAdElasticityOp.h"
+#include <list>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class geoMatcher: public MAdElasticityOp
+  {
+
+  public:
+
+    geoMatcher(pMesh);
+    geoMatcher(const geoMatcher&);
+    ~geoMatcher();
+
+    void reportFailure(double ratio) { failures.push_back(ratio); }
+    void printFailures(std::ostream&) const;
+
+  private:
+
+    std::list<double> failures;
+
+  };
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/repositioning/LaplaceSmoothingOp.cc b/Adapt/repositioning/LaplaceSmoothingOp.cc
new file mode 100644
index 0000000..872c794
--- /dev/null
+++ b/Adapt/repositioning/LaplaceSmoothingOp.cc
@@ -0,0 +1,75 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "LaplaceSmoothingOp.h"
+#include "VertexMoveOp.h"
+#include "MeshParametersManager.h"
+#include "MathUtils.h"
+
+#include <vector>
+using std::vector;
+#include <math.h>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  LaplaceSmoothingOp::LaplaceSmoothingOp(pMesh m, DiscreteSF * sf): 
+    nodesRepositioningOp(m,sf)
+  {}
+
+  // -------------------------------------------------------------------
+  int LaplaceSmoothingOp::run(double * L2Norm)
+  {
+    return run(OPTIMAL,L2Norm);
+  }
+
+  // -------------------------------------------------------------------
+  int LaplaceSmoothingOp::run(LaplSmooType type, double * L2Norm)
+  {
+    *L2Norm = 0.0;
+
+    vertexMoveOp * vMove = new vertexMoveOp(mesh,sizeField,true);
+
+    VIter vit = M_vertexIter(mesh);
+    while( pVertex pv = VIter_next(vit) ) {
+
+      if ( V_whatInType(pv) != dim ) continue;
+
+      double ori[3];
+      V_coord(pv,ori);
+
+      double opt[3];
+      if ( type == OPTIMAL ) {
+        if (vMove->computeOptimalLocation(pv, opt)) vMove->setPosition(pv, opt);
+      } else {
+        V_cavityCenter(pv,opt);
+        vMove->setPosition(pv, opt);
+      }
+
+      double worst;
+      if( vMove->evaluate(&worst) ) {
+        vMove->apply();
+        double disp[3];
+        diffVec(ori,opt,disp);
+        *L2Norm += dotProd(disp,disp);
+      }
+
+      vMove->resetDisplacements();
+    }
+
+    return 1;
+  }
+
+  // -------------------------------------------------------------------
+
+}
+
diff --git a/Adapt/repositioning/LaplaceSmoothingOp.h b/Adapt/repositioning/LaplaceSmoothingOp.h
new file mode 100644
index 0000000..ce4804d
--- /dev/null
+++ b/Adapt/repositioning/LaplaceSmoothingOp.h
@@ -0,0 +1,46 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_LAPLACESMOOTHINGOP
+#define _H_LAPLACESMOOTHINGOP
+
+#include "NodesRepositioningOp.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  enum LaplSmooType {
+    FAST,
+    OPTIMAL
+  };
+
+  // -------------------------------------------------------------------
+  class LaplaceSmoothingOp : public nodesRepositioningOp {
+
+  public:
+
+    LaplaceSmoothingOp(pMesh m, DiscreteSF * sf);
+    ~LaplaceSmoothingOp() {}
+
+  public:
+
+    virtual int run(double * L2Norm);
+    virtual int run(LaplSmooType type, double * L2Norm);
+
+  };
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/repositioning/MAdElasticityOp.cc b/Adapt/repositioning/MAdElasticityOp.cc
new file mode 100644
index 0000000..44f291d
--- /dev/null
+++ b/Adapt/repositioning/MAdElasticityOp.cc
@@ -0,0 +1,954 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MAdElasticityOp.h"
+#include "MAdResourceManager.h"
+#include "OperatorTools.h"
+#include "MathUtils.h"
+#include "MAdOutput.h"
+#include "CallBackManager.h"
+
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::make_pair;
+using std::map;
+using std::set;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  void ElasticityOpCBFunction (pPList before, pPList after, void * data,
+                               operationType type , pEntity ppp) 
+  {
+    MAdElasticityOp * elast = (MAdElasticityOp *)(data);
+    if ( !(elast->relocationsComputed()) ) return;
+
+    switch (type) {
+    case MAd_ESPLIT: {
+      
+      // find the old edge
+      void * temp = NULL;
+      pEntity pE = PList_next(before,&temp);
+
+      // take the interpolated displacements between the extremities 
+      // of the edge for the new vertex
+      elast->addVertexOnEdge( (pVertex)ppp, (pEdge)pE );
+
+      break;
+    } 
+    case MAd_ECOLLAPSE: {
+      elast->removeVertex( (pVertex)ppp );
+      break;
+    }
+    case MAd_FSWAP:
+    case MAd_ESWAP: {
+      break;
+    }
+    case MAd_RREMOVE: {
+      void * temp = NULL;
+      while ( pEntity pE = PList_next(before,&temp) ) {
+        if ( EN_type(pE) == 0 ) {
+          elast->removeVertex( (pVertex)pE );
+        }
+      }
+      break;
+    }
+    default: {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Callback function not implemented for mesh modification %d",
+                                  type);
+    }
+    }
+  }
+
+  // -------------------------------------------------------------------
+  MAdElasticityOp::MAdElasticityOp(pMesh m):
+    mesh(m), E(1.), nu(0.45), chi(1.0), computed(false),
+    cavityEqualMesh(false), cavityThickness(3)
+  {
+    dim = M_dim(mesh);
+    CallBackManagerSgl::instance().registerCallBack(ElasticityOpCBFunction,this);
+  }
+
+  // -------------------------------------------------------------------
+  MAdElasticityOp::MAdElasticityOp(const MAdElasticityOp& eop):
+    mesh(eop.mesh), dim(eop.dim), 
+    E(eop.E), nu(eop.nu), chi(eop.chi),
+    computed(eop.computed),
+    cavityEqualMesh(eop.cavityEqualMesh),
+    cavityThickness(eop.cavityThickness)
+  {
+    localIds = eop.localIds;
+    dirichlet = eop.dirichlet;
+    CallBackManagerSgl::instance().registerCallBack(ElasticityOpCBFunction,this);
+  }
+
+  // -------------------------------------------------------------------
+  MAdElasticityOp::~MAdElasticityOp()
+  {
+    CallBackManagerSgl::instance().unregisterCallBack(ElasticityOpCBFunction,this);
+  }
+
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::setMaterials(double _E, double _nu)
+  {
+    E = _E;  nu = _nu;
+  }
+
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::setStiffnessAlterationCoef(double _chi)
+  {
+    chi = _chi;
+  }
+
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::clear()
+  {
+    localIds.clear();
+    cavity.clear();
+    dirichlet.clear();
+    relocations.clear();
+    computed = false;
+  }
+
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::buildCavity()
+  {
+    computed = false;
+
+    if ( cavityEqualMesh ) return;
+
+    int nVertInit = dirichlet.size();
+
+    cavity.clear();
+
+    if ( cavityThickness < 1 ) return;
+
+    set<pVertex> innerNodes; // nodes inside the cavity and dirichlet
+    set<pRegion> prevLayer;
+
+    // --- first layer ---
+    pRegion pr;
+    pVertex pv;
+    map<pVertex,smallVector>::const_iterator dIter = dirichlet.begin();
+    for (; dIter != dirichlet.end(); dIter++) {
+      pv = (*dIter).first;
+      pPList vRegs = V_regions(pv);
+      void * temp = NULL;
+      while ( ( pr = (pRegion)PList_next(vRegs,&temp) ) ) {
+        cavity.insert(pr);
+        prevLayer.insert(pr);
+      }
+      PList_delete(vRegs);
+      innerNodes.insert(pv);
+    }
+
+    // --- next layers ---
+    for (int iL=1; iL < cavityThickness; iL++) {
+      set<pRegion> curLayer;
+      set<pRegion>::const_iterator rIter = prevLayer.begin();
+      for (; rIter != prevLayer.end(); rIter++ ) {
+        pPList rVerts = R_vertices(*rIter);
+        void * temp = NULL;
+        while ( ( pv = (pVertex)PList_next(rVerts,&temp) ) ) {
+          if ( innerNodes.find(pv) == innerNodes.end() ) {
+            pPList vRegs = V_regions(pv);
+            void * temp = NULL;
+            while ( ( pr = (pRegion)PList_next(vRegs,&temp) ) ) {
+              if ( cavity.find(pr) == cavity.end() ) {
+                cavity.insert(pr);
+                curLayer.insert(pr);
+              }
+            }
+            PList_delete(vRegs);
+            innerNodes.insert(pv);
+          }
+        }
+        PList_delete(rVerts);
+      }
+      prevLayer.clear();
+      prevLayer.insert(curLayer.begin(),curLayer.end());
+      curLayer.clear();
+    }
+
+    printf("Built a cavity with %d elements, dirichlet size: %d\n",cavity.size(),dirichlet.size());
+
+  }
+
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::setHomogDirichletBC()
+  {
+    dirichlet.clear();
+    setDirichletBC();
+  }
+
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::setDirichletBC()
+  {
+    computed = false;
+    smallVector zero(3);  zero.set_all(0.);
+
+    set<pVertex> verts;
+    collectBCVertices(&verts);
+
+    set<pVertex>::const_iterator vIter = verts.begin();
+    set<pVertex>::const_iterator vLast = verts.end();
+    for (; vIter != vLast; vIter++) {
+      addDirichlet(*vIter,zero);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::collectBCVertices(set<pVertex> * bcVerts)
+  {
+    if ( cavityEqualMesh ) 
+      {
+        FIter fit = M_faceIter(mesh);
+        while ( pFace pf = FIter_next(fit) ) {
+          if ( EN_whatInType((pEntity)pf) == 2 ) {
+            pPList fV = F_vertices(pf,1);
+            void* tmp=0;
+            while ( pVertex pv = (pVertex)PList_next(fV,&tmp) ) {
+              (*bcVerts).insert(pv);
+            }
+            PList_delete(fV);
+          }
+        }
+        FIter_delete(fit);
+      }
+    else
+      {
+        set<pRegion>::const_iterator cavIter = cavity.begin();
+        for (; cavIter != cavity.end(); cavIter++) {
+          pPList rFaces = R_faces(*cavIter);
+          void * temp = NULL;
+          pFace pf;
+          while ( ( pf = (pFace)PList_next(rFaces,&temp) ) ) {
+            pRegion otherR = F_otherRegion(pf,*cavIter);
+            if ( !otherR || cavity.find(otherR) == cavity.end() ) {
+              pPList fVerts = F_vertices(pf,1);
+              void * temp2 = NULL;
+              pVertex pv;
+              while ( ( pv = (pVertex)PList_next(fVerts,&temp2) ) ) {
+                (*bcVerts).insert(pv);
+              }
+              PList_delete(fVerts);
+            }
+          }
+          PList_delete(rFaces);
+        }
+      }
+  }
+
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::addDirichlet(pVertex pv, smallVector& dxyz)
+  {
+    map<pVertex,smallVector>::iterator dIter = dirichlet.find(pv);
+    if ( dIter != dirichlet.end() ) {
+      smallVector dxyz1 = (*dIter).second;
+      dxyz1.add(dxyz);
+      dirichlet.erase(dIter);
+      dirichlet.insert(make_pair(pv,dxyz1));
+    }
+    else {
+      dirichlet.insert(make_pair(pv,dxyz));
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::delDirichlet(pVertex pv)
+  {
+    map<pVertex,smallVector>::iterator dIter = dirichlet.find(pv);
+    if ( dIter != dirichlet.end() ) {
+      dirichlet.erase(dIter);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::delRelocation(pVertex pv)
+  {
+    map<pVertex,smallVector>::iterator dIter = relocations.find(pv);
+    if ( dIter != relocations.end() ) {
+      relocations.erase(dIter);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  // Generates table of vertex pointers to local ids and returns number
+  // of vertices in the cavity.
+  int MAdElasticityOp::generateVertexIds()
+  {
+    computed = false;
+    localIds.clear();
+
+    int id = 0;
+
+    if (cavityEqualMesh) {
+      VIter vit = M_vertexIter(mesh);
+      while ( pVertex pv = VIter_next(vit) ) {
+        localIds[pv] = id;
+        id++;
+      }
+      VIter_delete(vit);
+    }
+    else {
+      set<pVertex> verts;
+      set<pRegion>::const_iterator cavIter = cavity.begin();
+      for (; cavIter != cavity.end(); cavIter++) {
+        pPList rVerts = R_vertices(*cavIter);
+        void * temp = NULL;
+        while ( pVertex pv = (pVertex)PList_next(rVerts,&temp) ) {
+          if ( verts.find(pv) == verts.end() ) {
+            localIds[pv] = id;
+            id++;
+            verts.insert(pv);
+          }
+        }
+        PList_delete(rVerts);
+      }
+    }
+    return id;
+  }
+
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::addToMatrix(const pRegion pr,
+                                    int nbVert,
+                                    MAdLinearSystemDef * lsys)
+  {
+    int rNodes = R_numVertices(pr);
+    int locSyze = rNodes*dim;
+
+    smallMatrix locK(locSyze,locSyze);
+    element3DMatrix(pr, locK);
+
+    pPList vertsI = R_vertices(pr);
+    pPList vertsJ = R_vertices(pr);
+    void* tmpI = 0;
+    int i = 0;
+    while ( pVertex pvI = (pVertex)PList_next(vertsI,&tmpI) ) {
+
+      int locIdI = localIds[pvI];
+      
+      void* tmpJ = 0;
+      int j = 0;
+      while ( pVertex pvJ = (pVertex)PList_next(vertsJ,&tmpJ) ) {
+        
+        int locIdJ = localIds[pvJ];
+        
+        for (int k=0; k<dim; k++) {
+          for (int l=0; l<dim; l++) {
+            lsys->addToMatrix(nbVert*k + locIdI, nbVert*l+locIdJ, locK(k*rNodes+i,l*rNodes+j));
+          }
+        }
+        j++;
+      }
+      i++;
+    }
+    PList_delete(vertsI);
+    PList_delete(vertsJ);
+  }
+
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::allocateMatrix(int nbVert, MAdLinearSystemDef * lsys)
+  {
+    if (cavityEqualMesh) {
+      VIter vit2 = M_vertexIter(mesh);
+      while ( pVertex pv2 = VIter_next(vit2) ) {
+        int locId = localIds[pv2];
+        int nbNeighbors = V_numEdges(pv2);
+        for (int iDir=0; iDir<3; iDir++) {
+          int row = nbVert*iDir + locId;
+          lsys->set_nnz(row,(nbNeighbors+1)*3);// A node is coupled with all its neighbors, and don't forget himself
+        }
+      }
+      VIter_delete(vit2);
+    }
+    else {
+      map<pVertex,set<pVertex> > conn;
+      set<pRegion>::const_iterator cIter = cavity.begin();
+      for (; cIter != cavity.end(); cIter++) {
+        pPList rEdges = R_edges(*cIter);
+        void * temp = NULL;
+        pEdge edge;
+        pVertex v0, v1;
+        while ( ( edge = (pEdge)PList_next(rEdges,&temp)) ) {
+          v0 = E_vertex(edge,0);
+          v1 = E_vertex(edge,1);
+          conn[v0].insert(v1);
+          conn[v1].insert(v0);
+        }
+        PList_delete(rEdges);
+      }
+        
+      pVertex pv;
+      map<pVertex,set<pVertex> >::const_iterator conIter = conn.begin();
+      for (; conIter != conn.end(); conIter++) {
+        pv = conIter->first;
+        int locId = localIds[pv];
+        int nbNeighbors = conIter->second.size();
+        for (int iDir=0; iDir<3; iDir++) {
+          int row = nbVert*iDir + locId;
+          lsys->set_nnz(row,(nbNeighbors+1)*3);// A node is coupled with all its neighbors, and don't forget himself
+        }
+      }
+    }
+
+    lsys->allocate_matrix();
+  }
+
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::addVertexOnEdge(pVertex pv, pEdge pe)
+  {
+    if ( computed == true )
+      {
+        double t = E_linearParams(pe,pv);
+
+        smallVector dx0, dx1;
+        for (int i=0; i<2; i++)
+          {
+            pVertex vi = E_vertex(pe,i);
+            std::map<pVertex,smallVector >::iterator iter = relocations.find(pv);
+            if ( iter != relocations.end() ) {
+              if (i==0) dx0 = (*iter).second;
+              else      dx1 = (*iter).second;
+            }
+            else return;
+          }
+        smallVector newDx(3);
+        for (int i=0; i<3; i++) newDx(i) = (1.-t) * dx0(i) + t * dx1(i);
+        relocations[pv] = newDx;
+      }
+  }
+
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::removeVertex(pVertex pv)
+  {
+    if ( computed == true ) 
+      {
+        std::map<pVertex,smallVector >::iterator iter = relocations.find(pv);
+        if ( iter != relocations.end() ) {
+          relocations.erase(iter);
+        }
+      }
+  }
+
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::setVertexResult(int nbVert, pVertex pv, 
+                                        const MAdLinearSystemDef * lsys)
+  {
+    // get the vertex id
+    map<pVertex,int>::const_iterator itId = localIds.find(pv);
+    int id = (*itId).second;
+
+    // get the dx
+    smallVector dX(3);
+    for (int iDir=0; iDir<3; iDir++) {
+      int row = nbVert*iDir + id;
+      dX(iDir) = lsys->getFromSolution(row);
+    }
+
+    relocations[pv] = dX;
+  }
+  
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::setResults(int nbVert,
+                                   const MAdLinearSystemDef * lsys)
+  {
+    relocations.clear();
+
+    if (cavityEqualMesh) {
+      pVertex pv;
+      VIter vit = M_vertexIter(mesh);
+      while ( ( pv = VIter_next(vit) ) ) {
+        setVertexResult(nbVert,pv,lsys);
+      }
+      VIter_delete(vit);
+    }
+    else {
+      set<pVertex> vertices;
+      set<pRegion>::const_iterator cIter = cavity.begin();
+      for (; cIter != cavity.end(); cIter++) {
+        pPList rVerts = R_vertices(*cIter);
+        void * temp = NULL;
+        pVertex pv;
+        while ( ( pv = (pVertex)PList_next(rVerts,&temp) ) ) {
+          vertices.insert(pv);
+        }
+        PList_delete(rVerts);
+      }
+
+      set<pVertex>::const_iterator vIter = vertices.begin();
+      for (; vIter != vertices.end(); vIter++) {
+        setVertexResult(nbVert,*vIter,lsys);
+      }
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::printRelocations(std::ostream& out) const
+  {
+    out << "Printing relocation: "<<relocations.size()<<" vertices relocated\n";
+    std::map<pVertex,smallVector>::const_iterator iter = relocations.begin();
+    for(; iter != relocations.end(); iter++)
+      {
+        pVertex pv = (*iter).first;
+        int id = EN_id(pv);
+        pGEntity ge = V_whatIn(pv);
+        int gdim = GEN_type(ge);
+        int gtag = GEN_tag(ge);
+        smallVector dX = (*iter).second;
+        out <<"Vertex "<<pv<<" with id "<<id<<" and class ("<<gdim<<","<<gtag<<"): "<<dX(0)<<" "<<dX(1)<<" "<<dX(2)<<"\n";
+      }
+    
+    out << "Printed relocation: "<<relocations.size()<<" vertices relocated\n";
+  }
+
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::printDirichlet(std::ostream& out) const
+  {
+    out << "Printing dirichlet BCs: "<<dirichlet.size()<<" vertices\n";
+    std::map<pVertex,smallVector>::const_iterator iter = dirichlet.begin();
+    for(; iter != dirichlet.end(); iter++)
+      {
+        pVertex pv = (*iter).first;
+        int id = EN_id(pv);
+        pGEntity ge = V_whatIn(pv);
+        int gdim = GEN_type(ge);
+        int gtag = GEN_tag(ge);
+        smallVector dX = (*iter).second;
+        out <<"Vertex "<<pv<<" with id "<<id<<" and class ("<<gdim<<","<<gtag<<"): "<<dX(0)<<" "<<dX(1)<<" "<<dX(2)<<"\n";
+      }
+    
+    out << "Printed dirichlet BCs: "<<dirichlet.size()<<" vertices\n";
+  }
+
+  // -------------------------------------------------------------------
+  int MAdElasticityOp::compute()
+  {
+    MAdResourceManager& tm = MAdResourceManagerSgl::instance();
+
+    relocations.clear();
+
+    // --------------------------------------------
+    // If there is no element in the cavity, just 
+    // prescribed node relocations (dirichlet) ...
+    // --------------------------------------------
+    if ( !cavityEqualMesh && cavity.empty() ) {
+      MAdMsgSgl::instance().info(__LINE__,__FILE__,
+                                 "Empty cavity for elastic computation");
+      relocations = dirichlet;
+    }
+
+    // --------------------------------------------------
+    // ... if an elastic computation has to be performed
+    // --------------------------------------------------
+    else {
+
+      if ( dim != 3 ) {
+        MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                    "Elasticity model only implemented for dimension 3, current dimension is %d",
+                                    dim);
+      }
+      
+      MeshQualityManagerSgl::instance().evaluateSizes(); // required for detJ0
+
+      MAdResourceManagerSgl::instance().printMemoryUsage("Before elastic system allocation");
+
+      // --- produce the mapping pVertex -> localId ---
+      int nbVert = generateVertexIds();
+
+      // --- create the linear system ---
+      double t_sys0 = tm.getTime();
+      int sysSize = dim * nbVert;
+      MAdLinearSystemDef * lsys = new MAdLinearSystemDef();
+      lsys->allocate(sysSize);
+
+      lsys->setSolver(CG);
+      lsys->setFillIn(4);
+      lsys->setEps(1.e-12);
+
+      lsys->setPrec(1.e-12); // for gmm only
+      lsys->setNoisy(1);    // for gmm only
+
+      // --- allocate the matrix ---
+      allocateMatrix(nbVert,lsys); // for PETSc only
+
+      lsys->zeroMatrix();
+      lsys->zeroRightHandSide();
+
+      double dt_sys = tm.getTime() - t_sys0;
+      MAdMsgSgl::instance().info(-1,__FILE__,
+                                 "Created the system in %f seconds",dt_sys);
+      MAdResourceManagerSgl::instance().printMemoryUsage("Elastic system allocated");
+
+      // --- assemble the matrix ---
+      double t_ass0 = tm.getTime();
+      if (cavityEqualMesh) {
+        RIter rit = M_regionIter(mesh);
+        while ( pRegion pr = RIter_next(rit) ) addToMatrix(pr,nbVert,lsys);
+        RIter_delete(rit);
+      }
+      else {
+        set<pRegion>::const_iterator cavIter = cavity.begin();
+        for (; cavIter != cavity.end(); cavIter++) addToMatrix(*cavIter,nbVert,lsys);
+      }
+      double dt_ass = tm.getTime() - t_ass0;
+      MAdMsgSgl::instance().info(-1,__FILE__,
+                                 "Assembled the matrix in %f seconds",dt_ass);
+      MAdResourceManagerSgl::instance().printMemoryUsage("Matrix assembled");
+
+      // --- apply bc (ugly but it works hum) ---
+      double t_bc0 = tm.getTime();
+      map<pVertex,smallVector>::iterator dIter = dirichlet.begin();
+      map<pVertex,smallVector>::iterator dLast = dirichlet.end();
+      for (; dIter != dLast; dIter++) {
+
+        pVertex pv       = (*dIter).first;
+        smallVector dxyz = (*dIter).second;
+
+        // get the vertex id
+        map<pVertex,int>::const_iterator itId = localIds.find(pv);
+        int id = (*itId).second;
+    
+        for (int iDir=0; iDir<3; iDir++) {
+          int row = nbVert*iDir + id;
+          const double BIG = /*lsys->getFromMatrix(row,row) *  */1.e12;
+          lsys->addToMatrix(row,row,BIG);
+          lsys->addToRightHandSide(row,BIG * dxyz(iDir));
+        }
+    
+      }
+      double dt_bc = tm.getTime() - t_bc0;
+      MAdMsgSgl::instance().info(-1,__FILE__,
+                                 "Applied boundary conditions in %f seconds",dt_bc);
+      MAdResourceManagerSgl::instance().printMemoryUsage("BC applied");
+
+      // --- reorder matrix ---
+      lsys->reorder();
+      MAdResourceManagerSgl::instance().printMemoryUsage("Matrix reordered");
+
+      // --- solve the system ---
+      double t_slv0 = tm.getTime();
+      int converged = lsys->systemSolve();
+      double dt_slv = tm.getTime() - t_slv0;
+      MAdMsgSgl::instance().info(-1,__FILE__,
+                                 "Solved the elastic system (convergence flag: %d) in %f seconds",
+                                 converged,dt_slv);
+      MAdResourceManagerSgl::instance().printMemoryUsage("System solved");
+
+
+      // --- fill relocations with the results ---
+      setResults(nbVert,lsys);
+
+      localIds.clear();
+      delete lsys;
+    }
+
+    dirichlet.clear();
+    cavity.clear();
+
+    computed = true;
+
+    return 1;
+  }
+
+
+  // -------------------------------------------------------------------
+  bool MAdElasticityOp::checkArea(const pFace pf, double ratio)
+  {
+    bool inCavity = false;
+
+    double fxyz[3][3];
+    F_coordP1(pf,fxyz);
+    double oriNorm[3];
+    XYZ_F_normal(fxyz,oriNorm);
+
+    pPList fVerts = F_vertices(pf,1);
+    void * temp = NULL;
+    int i = 0;
+    pVertex pv;
+    while ( ( pv = (pVertex)PList_next(fVerts,&temp) ) ) {
+      std::map<pVertex,smallVector>::const_iterator iter = relocations.find(pv);
+      if ( iter != relocations.end() ) {
+        inCavity = true;
+        for (int j=0; j<3; j++) fxyz[i][j] += ratio * (*iter).second(j);
+      }
+      i++;
+    }
+    PList_delete(fVerts);
+
+    // Do the check only if one of the nodes moved
+    if ( inCavity ) {
+      double tgtNorm[3];
+      XYZ_F_normal(fxyz,tgtNorm);
+      double prod = oriNorm[0] * tgtNorm[0] + oriNorm[1] * tgtNorm[1] + oriNorm[2] * tgtNorm[2];
+      if ( prod <= 0. ) return false;
+    }
+
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  // Cannot use 'cavity': it is hard to maintain if mesh modifications
+  // occur during advancement so it is cleared in 'compute()'.
+  bool MAdElasticityOp::checkAreas(double ratio)
+  {
+    pFace pf;
+    FIter fit = M_faceIter(mesh);
+    while ( ( pf = FIter_next(fit) ) ) {
+      if ( !checkArea(pf,ratio) ) {
+        FIter_delete(fit);
+        return false;
+      }
+    }
+    FIter_delete(fit);
+
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool MAdElasticityOp::checkVolume(const pRegion pr, double ratio)
+  {
+    bool inCavity = false;
+
+    double rxyz[4][3];
+    R_coordP1(pr,rxyz);
+
+    pPList rVerts = R_vertices(pr);
+    void * temp = NULL;
+    int i = 0;
+    pVertex pv;
+    while ( ( pv = (pVertex)PList_next(rVerts,&temp) ) ) {
+      std::map<pVertex,smallVector>::const_iterator iter = relocations.find(pv);
+      if ( iter != relocations.end() ) {
+        inCavity = true;
+        for (int j=0; j<3; j++) rxyz[i][j] += ratio * (*iter).second(j);
+      }
+      i++;
+    }
+    PList_delete(rVerts);
+
+    // Do the check only if one of the nodes moved
+    if ( inCavity && R_XYZ_volume(rxyz) <= MAdTOL ) return false;
+
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  // Cannot use 'cavity': it is hard to maintain if mesh modifications
+  // occur during advancement so it is cleared in 'compute()'.
+  bool MAdElasticityOp::checkVolumes(double ratio)
+  {
+    pRegion pr;
+    RIter rit = M_regionIter(mesh);
+    while ( ( pr = RIter_next(rit) ) ) {
+      if ( !checkVolume(pr,ratio) ) {
+        RIter_delete(rit);
+        return false;
+      }
+    }
+    RIter_delete(rit);
+
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::relocate(double ratio)
+  {
+    pVertex pv;
+    double xyz[3];
+    
+    std::map<pVertex,smallVector>::const_iterator iter = relocations.begin();
+    for(; iter != relocations.end(); iter++)
+      {
+        pv = (*iter).first;
+        V_coord(pv,xyz);
+
+        smallVector dX = (*iter).second;
+
+        xyz[0] += ratio * dX(0);
+        xyz[1] += ratio * dX(1);
+        xyz[2] += ratio * dX(2);
+        if ( !V_setPosition(pv,xyz) ) {
+          MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                      "Could not relocate a node");
+          
+        }
+      }
+  }
+
+  // -------------------------------------------------------------------
+  // Advances the relocation as far as possible
+  // Returns:
+  //    - 0: no relocation possible
+  //    - 1: advanced but not to the final position
+  //    - 2: reached the full prescribed relocation
+  int MAdElasticityOp::advance(double * ratio, double tolerance)
+  {
+    if ( *ratio >= 1.-tolerance ) {
+      *ratio = 1.;
+      return 2;
+    }
+
+    int achieved = 0; // the result returned
+
+    int subIter = 0;
+    const int nbMaxIter = 6;
+
+    double margin = 1. - *ratio; // in [0;1] : the rest of the motion to be performed
+    double curRatio = 1.;        // in [0;1] : the part of the margin that will be tested next
+    double delta = 0.5;          // in [0;1] : the increment/decrement of ratio at next iteration
+    double best = -1.;           // in [0;1] : the best current ratio with positive volumes
+
+    while ( subIter < nbMaxIter )
+      {
+        double totalAdvancement = curRatio * margin + *ratio;
+        bool check;
+        if ( dim == 3 ) check = checkVolumes( curRatio * margin );
+        else            check = checkAreas  ( curRatio * margin );
+        if ( !check ) {
+          curRatio -= delta;
+        }
+        else {
+          best = curRatio;
+          if ( totalAdvancement + tolerance >= 1. ) { achieved = 2; break; }
+          else                                      { achieved = 1; curRatio += delta; }
+        }
+
+        subIter++;
+        delta *= 0.5;
+//         printf("Ratio: %f, margin: %f, achieved: %d, subIter: %d, best: %f, curRatio: %f, delta: %f\n",
+//                *ratio, margin, achieved, subIter, best, curRatio, delta);
+      }
+
+    double moveRatio = 0.;
+    if ( achieved == 2 ) {
+      moveRatio = ( 1. - *ratio );
+      relocate(moveRatio);
+      *ratio = 1.;
+    }
+    else if ( achieved == 1 ) {
+      moveRatio = best * margin;
+      relocate(moveRatio);
+      *ratio += moveRatio;
+    }
+    
+    return achieved;
+  }
+
+  // -------------------------------------------------------------------
+  // Force the relocation even if it leads to negative volumes
+  void MAdElasticityOp::forceRelocation()
+  {
+    relocate(1.);
+  }
+
+  // -------------------------------------------------------------------
+  void MAdElasticityOp::element3DMatrix(pRegion pr, smallMatrix& m) const
+  {
+    int nbNodes = 4;
+    double xyz[4][3];
+    R_coordP1(pr,xyz);
+
+    double FACT = E / (1 + nu);
+    double C11 = FACT * (1 - nu) / (1 - 2 * nu);
+    double C12 = FACT * nu / (1 - 2 * nu);
+    double C44 = (C11 - C12) / 2;
+    const double C[6][6] =
+      { {C11, C12, C12,    0,   0,   0}, 
+        {C12, C11, C12,    0,   0,   0}, 
+        {C12, C12, C11,    0,   0,   0}, 
+        {  0,   0,   0,  C44,   0,   0},
+        {  0,   0,   0,    0, C44,   0}, 
+        {  0,   0,   0,    0,   0, C44} };
+
+    smallMatrix H   (6,6);
+    for (int i=0;i<6;i++)
+      for (int j=0;j<6;j++)
+        H(i,j) = C[i][j];
+
+    smallMatrix B   (6,3*nbNodes);
+    smallMatrix BTH (3*nbNodes,6);
+    smallMatrix BT  (3*nbNodes,6);
+
+    const double gradShpFct[4][3] =
+      { {-1., -1., -1.},
+        { 1.,  0.,  0.},
+        { 0.,  1.,  0.},
+        { 0.,  0.,  1.} };
+
+    double jac [3][3];
+    jac[0][0] = jac[0][1] = jac[0][2] = 0.;
+    jac[1][0] = jac[1][1] = jac[1][2] = 0.;
+    jac[2][0] = jac[2][1] = jac[2][2] = 0.;
+    for(int i = 0; i < nbNodes; i++) {
+      jac[0][0] += xyz[i][0] * gradShpFct[i][0]; jac[0][1] += xyz[i][1] * gradShpFct[i][0]; jac[0][2] += xyz[i][2] * gradShpFct[i][0];
+      jac[1][0] += xyz[i][0] * gradShpFct[i][1]; jac[1][1] += xyz[i][1] * gradShpFct[i][1]; jac[1][2] += xyz[i][2] * gradShpFct[i][1];
+      jac[2][0] += xyz[i][0] * gradShpFct[i][2]; jac[2][1] += xyz[i][1] * gradShpFct[i][2]; jac[2][2] += xyz[i][2] * gradShpFct[i][2];
+    }
+    const double detJ = fabs(jac[0][0] * jac[1][1] * jac[2][2] + jac[0][2] * jac[1][0] * jac[2][1] +
+                             jac[0][1] * jac[1][2] * jac[2][0] - jac[0][2] * jac[1][1] * jac[2][0] -
+                             jac[0][0] * jac[1][2] * jac[2][1] - jac[0][1] * jac[1][0] * jac[2][2]);
+
+    double invjac [3][3];
+    inverseMat (jac, invjac) ;
+
+    double Grads[4][3];
+
+    B.set_all(0.0);
+    BT.set_all(0.0);
+
+    for (int j=0;j<nbNodes;j++){
+
+      Grads[j][0] = invjac[0][0] * gradShpFct[j][0] + invjac[0][1] * gradShpFct[j][1] + invjac[0][2] * gradShpFct[j][2];
+      Grads[j][1] = invjac[1][0] * gradShpFct[j][0] + invjac[1][1] * gradShpFct[j][1] + invjac[1][2] * gradShpFct[j][2];
+      Grads[j][2] = invjac[2][0] * gradShpFct[j][0] + invjac[2][1] * gradShpFct[j][1] + invjac[2][2] * gradShpFct[j][2];
+    
+      BT(j,0) = B(0,j) = Grads[j][0];
+      BT(j,3) = B(3,j) = Grads[j][1];
+      BT(j,4) = B(4,j) = Grads[j][2];
+    
+      BT(j+nbNodes,1) = B(1,j+nbNodes) = Grads[j][1];
+      BT(j+nbNodes,3) = B(3,j+nbNodes) = Grads[j][0];
+      BT(j+nbNodes,5) = B(5,j+nbNodes) = Grads[j][2];
+    
+      BT(j+2*nbNodes,2) = B(2,j+2*nbNodes) = Grads[j][2];
+      BT(j+2*nbNodes,4) = B(4,j+2*nbNodes) = Grads[j][0];
+      BT(j+2*nbNodes,5) = B(5,j+2*nbNodes) = Grads[j][1];
+    }
+  
+    BTH.set_all(0.0);
+    BTH.blas_dgemm (BT,H); 
+  
+    m.set_all(0.0);
+    m.blas_dgemm (BTH,B,detJ,1.0);
+
+    // --- Selective element stiffening ---
+    // reference:
+    // Stein, Tezduyar, Benney "Mesh Moving Techniques for FSI with Large Displacement", ASME, 2003.
+
+    double detJ0 = MeshQualityManagerSgl::instance().getMaxSize();
+    if ( detJ0 <= 0. ) detJ0 = 1.;
+
+    double scaleFactor = pow( detJ0 / detJ, chi);
+    if ( scaleFactor > 1.e12 || scaleFactor < 1.e-12 ) {
+      cout <<"Warning in MAdElasticity: scale factor for element stiffness is "<<scaleFactor<<endl;
+    }
+
+    m.scale ( scaleFactor );
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/repositioning/MAdElasticityOp.h b/Adapt/repositioning/MAdElasticityOp.h
new file mode 100644
index 0000000..d82aafc
--- /dev/null
+++ b/Adapt/repositioning/MAdElasticityOp.h
@@ -0,0 +1,149 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MADELASTICITYOP
+#define _H_MADELASTICITYOP
+
+#include "MAdMatrix.h"
+#include "VertexMoveOp.h"
+#include "MAdLinearSystem.h"
+
+#include <map>
+#include <set>
+
+/*
+  This operator uses an analogy with an elastic medium in order to compute 
+  the displacements of the vertices resulting from a prescribed displacement
+  of the boundaries.
+
+  The steps to make a computation are the following:
+  
+    1. Choose a set of nodal displacements by calling 'addDirichlet'
+        --> build part of 'dirichlet'
+    2. Build a cavity around the nodes for which you prescribed a displacement
+        --> build 'cavity'
+    3. Impose homogenous Dirichlet boudnary conditions to the boundaries 
+       of the cavity with 'setDirichletBC()' (except the nodes with a 
+       prescribed displacement)
+        --> finish building 'dirichlet'
+    4. Compute the displacements with 'compute'
+        --> build 'relocations'
+        --> clear 'cavity' and 'dirichlet'
+        --> 'computed' set to 'true'
+    5. Apply a part of the displacement to the mesh with 'advance' 
+       (as much as you can)
+    6. Once nodes are fully relocated, call 'clear'
+        --> clear all
+        --> computed set to 'false'
+*/
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class MAdElasticityOp {
+
+  public:
+
+    MAdElasticityOp(pMesh m);
+    MAdElasticityOp(const MAdElasticityOp&);
+    virtual ~MAdElasticityOp();
+
+  public:
+
+    void clear();
+
+    int meshDim() const { return dim; }
+
+    void setMaterials(double _E, double _nu);
+    void setStiffnessAlterationCoef(double _chi);
+
+    void setCavityEqualMesh(bool _m, int thickness)
+    {
+      cavityEqualMesh = _m;
+      cavityThickness = thickness;
+    }
+
+    void buildCavity();
+
+    void setDirichletBC();
+    void setHomogDirichletBC();
+    void addDirichlet(pVertex pv, smallVector& dxyz);
+    void delDirichlet(pVertex pv);
+
+    int  compute();
+    bool relocationsComputed() const { return computed; }
+    void delRelocation(pVertex pv);
+
+    // Advances the relocation as far as possible
+    // Returns:
+    //    - 0: no relocation possible
+    //    - 1: advanced but not to the final position
+    //    - 2: reached the full prescribed relocation
+    int  advance(double * ratio, double tolerance=MAdTOL);
+    void forceRelocation();
+
+    void removeVertex(pVertex);
+    void addVertexOnEdge(pVertex, pEdge);
+
+    // debugging functions
+    void printRelocations(std::ostream& out) const;
+    void printDirichlet(std::ostream& out) const;
+
+  private:
+
+    int generateVertexIds();
+    void collectBCVertices(std::set<pVertex> * bcVerts);
+  
+    void element3DMatrix (pRegion pr, smallMatrix& m) const;
+    void addToMatrix(const pRegion, int, MAdLinearSystemDef *);
+    void allocateMatrix(int, MAdLinearSystemDef *);
+
+    void setVertexResult(int, pVertex, const MAdLinearSystemDef *);
+    void setResults(int, const MAdLinearSystemDef *);
+
+    bool checkArea(const pFace, double ratio);
+    bool checkAreas(double ratio);
+    bool checkVolume(const pRegion, double ratio);
+    bool checkVolumes(double ratio);
+    void relocate(double ratio);
+
+  private:
+
+    pMesh mesh;
+    int dim;
+
+    double E, nu;
+
+    // exponent of the alteration of stiffness based on elements size:
+    // chi=0 => no alteration
+    // chi increases => smaller elements stiffer
+    double chi;
+
+    bool computed;
+
+    std::map<pVertex,int> localIds;
+
+    bool cavityEqualMesh;
+    int cavityThickness;
+    std::set<pRegion> cavity;
+
+    std::map<pVertex,smallVector > dirichlet;
+    std::map<pVertex,smallVector > relocations;
+
+  };
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/repositioning/MobileObject.cc b/Adapt/repositioning/MobileObject.cc
new file mode 100644
index 0000000..aa731ea
--- /dev/null
+++ b/Adapt/repositioning/MobileObject.cc
@@ -0,0 +1,496 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MobileObject.h"
+#include "NodalDataManager.h"
+
+#include <iostream>
+using std::cerr;
+using std::cout;
+using std::endl;
+#include <string.h>
+using std::set;
+//using std::multiset;
+using std::list;
+using std::pair;
+using std::vector;
+using std::string;
+
+namespace MAd {
+
+  // ----------------------------------------------------------------------
+  mobileObject::mobileObject(const pMesh m, string _name):
+    mesh(m),name(_name),prescribeType(""),DxParsed(NULL),
+    velType(NOFORMULATION),VParsed(NULL)//, Cxyz(NULL), Vxyz(NULL)
+  {
+#ifdef PARALLEL
+    MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                "Mobile objects not supported in parallel");
+#endif
+  }
+
+  // ----------------------------------------------------------------------
+  mobileObject::~mobileObject()
+  {
+    if (DxParsed) { delete DxParsed; DxParsed = NULL; }
+    if (VParsed)  { delete VParsed;  VParsed  = NULL; }
+  }
+
+  // ----------------------------------------------------------------------
+  void mobileObject::setDxKinematics(vector<string> _str)
+  {
+    if ( strcmp(prescribeType.c_str(),"") ) {
+      cerr << "Error: imposing a position on an object with another imposed movement: "<<prescribeType<<"\n";
+      throw;
+    }
+    prescribeType = "Displacement";
+
+    if (DxParsed) delete DxParsed;
+    DxParsed = new MAdStringFieldEvaluator(_str);
+  }
+
+  // ----------------------------------------------------------------------
+  void mobileObject::setVKinematics(velocityFormulation type, double V[3], 
+                                    double C[3], vector<string> _str)
+  {
+    if ( strcmp(prescribeType.c_str(),"") ) {
+      cerr << "Error: imposing a velocity on an object with another imposed movement: "<<prescribeType<<"\n";
+      throw;
+    }
+    prescribeType = "Velocity";
+      
+    velType = type; 
+    if ( V ) {
+      for (int i=0; i<3; i++)  Vxyz[i] = V[i];
+    }
+    if ( C ) {
+      for (int i=0; i<3; i++)  Cxyz[i] = C[i];
+    }
+    if (type == PARSED)  VParsed = new MAdStringFieldEvaluator(_str);
+  }
+
+  // ----------------------------------------------------------------------
+  void mobileObject::addLocalSField(LocalSizeField* lsf)
+  {
+    sizes.insert(lsf);
+  }
+
+  // ----------------------------------------------------------------------
+  void mobileObject::addGEntity(int type, int tag)
+  {
+    geomEntities.push_back(std::make_pair(type,tag));
+    addVerticesOnGEntity(type,tag);
+  }
+
+  // ----------------------------------------------------------------------
+  void mobileObject::reAddVertices()
+  {
+    vertices.clear();
+    list<pair<int,int> >::const_iterator it = geomEntities.begin();
+    list<pair<int,int> >::const_iterator itEnd = geomEntities.end();
+    for (; it != itEnd; it++)  addVerticesOnGEntity(it->first, it->second);
+  }
+
+  // ----------------------------------------------------------------------
+  void mobileObject::addVerticesOnGEntity(int type, int tag)
+  {
+    switch (type) {
+    case 0:
+      {
+        VIter vit = M_vertexIter(mesh);
+        while (pVertex pv = VIter_next(vit))
+          {
+            pGEntity pg = EN_whatIn((pEntity)pv);
+            int pgType = EN_whatInType( (pEntity) pv );
+            if(pg)
+              if (GEN_tag(pg) == tag && pgType == 0)
+                {
+                  vertices.insert(pv);
+                }
+          }
+        VIter_delete(vit);
+        break;
+      }
+    case 1:
+      {
+        EIter eit = M_edgeIter(mesh);
+        while (pEdge pe = EIter_next(eit))
+          {
+            pGEntity pg = EN_whatIn((pEntity)pe);
+            int pgType = EN_whatInType( (pEntity) pe );
+            if(pg)
+              if (GEN_tag(pg) == tag && pgType == 1)
+                {
+                  vertices.insert(E_vertex (pe,0));
+                  vertices.insert(E_vertex (pe,1));
+                }
+          }
+        EIter_delete(eit);
+      }
+    case 2:
+      {
+        FIter fit = M_faceIter(mesh);
+        while (pFace pf = FIter_next(fit))
+          {
+            pGEntity pg = EN_whatIn((pEntity)pf);
+            int pgType = EN_whatInType( (pEntity) pf );
+            if(pg)
+              if (GEN_tag(pg) == tag && pgType == 2)
+                {
+                  vertices.insert(F_vertex (pf,0));
+                  vertices.insert(F_vertex (pf,1));
+                  vertices.insert(F_vertex (pf,2));
+                }
+          }
+        FIter_delete(fit);
+      }
+    case 3:
+      {
+        RIter rit = M_regionIter(mesh);
+        while (pRegion pr = RIter_next(rit))
+          {
+            pGEntity pg = EN_whatIn((pEntity)pr);
+            int pgType = EN_whatInType( (pEntity) pr );
+            if(pg)
+              if (GEN_tag(pg) == tag && pgType == 3)
+                {
+                  vertices.insert(R_vertex (pr,0));
+                  vertices.insert(R_vertex (pr,1));
+                  vertices.insert(R_vertex (pr,2));
+                  vertices.insert(R_vertex (pr,3));
+                }
+          }
+        RIter_delete(rit);
+      }
+    }
+  }
+
+  // ----------------------------------------------------------------------
+  void mobileObject::computePrescribedDisplacement (double t, double dt)
+  {
+    if ( !(NodalDataManagerSgl::instance().isCoordinates()) ) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Allocate initial coordinates before making any move (use AdaptInterface::storeInitialCoordinates())");
+    }
+  
+    prescribedDisplacement.clear();
+    reAddVertices();
+  
+    if ( !strcmp(prescribeType.c_str(),"Velocity") ) 
+      {
+        double V[3]; V[0]=0.; V[1]=0.; V[2]=0.; 
+        if (velType == RANDOM_TRANSLATION) 
+          randomVelocity(V);
+        set<pVertex> :: iterator itV    = vertices.begin();
+        set<pVertex> :: iterator itVEnd = vertices.end();
+        for ( ; itV != itVEnd ; ++itV)
+          {
+            double dx[3];
+            double xyz[3]; V_coord (*itV,xyz);
+            if ( velType != RANDOM_TRANSLATION)
+              velocityFunction(xyz,t,V);
+            dx[0] = V[0] * dt;
+            dx[1] = V[1] * dt;
+            dx[2] = V[2] * dt;
+          
+            vDisplacement disp(*itV,dx);
+            prescribedDisplacement.insert(disp);
+          }
+      }
+
+    else if ( !strcmp(prescribeType.c_str(),"Displacement") ) 
+      {
+        set<pVertex> :: iterator itV    = vertices.begin();
+        set<pVertex> :: iterator itVEnd = vertices.end();
+        for ( ; itV != itVEnd ; ++itV)
+          {
+            // get initial position
+            vector<double> xyz0;
+            NodalDataManagerSgl::instance().getStoredCoordinates(*itV,xyz0);
+          
+            // get prescribed displacement (relative to and evaluated on initial position)
+            double dx0[3];
+            DxParsed->eval(xyz0,t,dx0);
+          
+            // get current position
+            double xyz[3]; V_coord (*itV,xyz);
+
+            // get new position
+            double xyznew[3];
+            for (int i=0; i<3; i++)  xyznew[i] = xyz0[i] + dx0[i];
+
+            // compute the displacement
+            double dx[3];
+            dx[0] = xyznew[0] - xyz[0];
+            dx[1] = xyznew[1] - xyz[1];
+            dx[2] = xyznew[2] - xyz[2];
+          
+            vDisplacement disp(*itV,dx);
+            prescribedDisplacement.insert(disp);
+          }
+      }
+
+    else {
+      cerr<< "Error: no kinematics specified for this object\n";
+      throw;
+    }
+  }
+
+  // ----------------------------------------------------------------------
+  void mobileObject::describe (std::ostream& out) const 
+  {
+    out << "Object \'" << name.c_str() << "\' carries "
+        << vertices.size() << " nodes with xyz velocity:\n"
+        << "  *  Vx: "<<Vxyz[0]<<"\n"
+        << "  *  Vy: "<<Vxyz[1]<<"\n"
+        << "  *  Vz: "<<Vxyz[2]<<"\n"
+        << " and analytical velocity formulation "<<velType<<"\n\n";
+  }
+
+  // ----------------------------------------------------------------------
+  // generates velocities between -1 and 1
+  void mobileObject::randomVelocity(double* V)
+  {
+    V[0] = (  (  (double)rand() / ((double)(RAND_MAX)+(double)(1))  ) - 0.5  ) * 2.;
+    V[1] = (  (  (double)rand() / ((double)(RAND_MAX)+(double)(1))  ) - 0.5  ) * 2.;
+    V[2] = (  (  (double)rand() / ((double)(RAND_MAX)+(double)(1))  ) - 0.5  ) * 2.;
+  }
+
+  // ----------------------------------------------------------------------
+  void mobileObject::velocityFunction(double* xyz, double t, double* V)
+  {
+    double x = xyz[0];
+    double y = xyz[1];
+    double z = xyz[2];
+
+    switch (velType) 
+      {
+      case NOFORMULATION:
+        {
+          MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                      "Velocity formulation: NOFORMULATION");
+        }
+      case PARSED:
+        {
+          VParsed->eval(xyz,t,V);
+          break;
+        }
+      case TRANSLATION:
+        {
+          V[0] = Vxyz[0]; V[1] = Vxyz[1]; V[2] = Vxyz[2];
+          break;
+        }
+      case FULLRANDOM:
+        {
+          randomVelocity(V);
+          break;
+        }
+      case RANDOM_TRANSLATION:
+        {
+          MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+                                        "VelocityFunction with tag RANDOM_TRANSLATION should not be used");
+          randomVelocity(V);
+          break;
+        }
+      case ISOMETRY: // expansion 
+        {
+          V[0] = Vxyz[0] * ( x - Cxyz[0] );
+          V[1] = Vxyz[1] * ( y - Cxyz[1] );
+          V[2] = Vxyz[2] * ( z - Cxyz[2] );
+          break;
+        }
+      case ROTATION: // rotation
+        { 
+          double velYZ = Vxyz[0];
+          double velZX = Vxyz[1];
+          double velXY = Vxyz[2];
+          double rYZ = sqrt ( (y - Cxyz[1])*(y - Cxyz[1]) + (z - Cxyz[2])*(z - Cxyz[2]) );
+          double rZX = sqrt ( (x - Cxyz[0])*(x - Cxyz[0]) + (z - Cxyz[2])*(z - Cxyz[2]) );
+          double rXY = sqrt ( (x - Cxyz[0])*(x - Cxyz[0]) + (y - Cxyz[1])*(y - Cxyz[1]) );
+          double angleYZ = atan2((y - Cxyz[1]), (z - Cxyz[2]));
+          double angleZX = atan2((z - Cxyz[2]), (x - Cxyz[0]));
+          double angleXY = atan2((x - Cxyz[0]), (y - Cxyz[1]));
+          V[0] = 0                               - velZX * rZX * sin(angleZX) + velXY * rXY * cos(angleXY) ;
+          V[1] = 0 +  velYZ * rYZ * cos(angleYZ)                              - velXY * rXY * sin(angleXY) ;
+          V[2] = 0 -  velYZ * rYZ * sin(angleYZ) + velZX * rZX * cos(angleZX)                            ;
+          break;	
+        }
+      case SHEAR_YZ: // shear plane YZ  
+        {
+          V[0] = Vxyz[0] * ( x - Cxyz[0] );
+          V[1] = Vxyz[1] * ( x - Cxyz[0] );
+          V[2] = Vxyz[2] * ( x - Cxyz[0] );
+          break;	
+        }
+      case SHEAR_ZX: // shear plane ZX  
+        {
+          V[0] = Vxyz[0] * ( y - Cxyz[1] );
+          V[1] = Vxyz[1] * ( y - Cxyz[1] );
+          V[2] = Vxyz[2] * ( y - Cxyz[1] );
+          break;	
+        }
+      case SHEAR_XY: // shear plane XY  
+        {
+          V[0] = Vxyz[0] * ( z - Cxyz[2] );
+          V[1] = Vxyz[1] * ( z - Cxyz[2] );
+          V[2] = Vxyz[2] * ( z - Cxyz[2] );
+          break;	
+        }
+      case BENCH2: // bench 2 
+        {
+          double Xmax0 = 10.;
+          double X = Xmax0 + Vxyz[0] * t;
+          V[0] = Vxyz[0] * x / X;
+          V[1] = 0.0;
+          V[2] = 0.0;
+          break;
+        }
+      case CROSS_EXPANSION_WITH_ROTATION: // cross expantion with rotation
+        {
+          double cx = 0.45;
+          double cy = 0.35 ;
+          double r = sqrt ((x - cx)*(x - cx) + (y - cy)*(y - cy));
+          double tt = atan2((x - cx), (y - cy));
+          V[0] = 0 +  4*r * cos(tt) + sin(tt) * .3;
+          V[1] = 0 -  4*r * sin(tt) + cos(tt) * .3;
+          V[2] = 0;
+          break;	
+        }
+      default:
+        {
+          MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                      "Unknowm velocity formulation %d",velType);
+        }
+      }
+  }
+
+  // ----------------------------------------------------------------------
+  // ----------------------- MOBILE OBJECTS SET ---------------------------
+  // ----------------------------------------------------------------------
+  mobileObjectSet::mobileObjectSet(): elasticOp(NULL)
+  {
+  }
+
+  // ----------------------------------------------------------------------
+  mobileObjectSet::~mobileObjectSet() 
+  {
+    clear();
+    if (elasticOp) delete elasticOp;
+  }
+
+  // ----------------------------------------------------------------------
+  void mobileObjectSet::clear()
+  {
+    mobSet.clear();
+  }
+
+  // ----------------------------------------------------------------------
+  void mobileObjectSet::insert(mobileObject* mob)
+  {
+    mobSet.insert(mob);
+  }
+
+  // ----------------------------------------------------------------------
+  void mobileObjectSet::describe(std::ostream& out) const
+  {
+    out << "\n--- Mobile objects set description ---\n\n";
+    set<mobileObject*>::const_iterator groupIt = mobSet.begin(); 
+    set<mobileObject*>::const_iterator groupItEnd = mobSet.end(); 
+    for ( ; groupIt != groupItEnd ; ++groupIt) {
+      (*groupIt)->describe(out);
+    }
+  }
+
+  // ----------------------------------------------------------------------
+  void mobileObjectSet::computePrescribedDisplacement (double t, double dt)
+  {
+    prescribedDisplacement.clear();
+
+    set<mobileObject*>::const_iterator groupIt = mobSet.begin(); 
+    set<mobileObject*>::const_iterator groupItEnd = mobSet.end(); 
+    for ( ; groupIt != groupItEnd ; ++groupIt) {
+
+      // compute the forced displacement for each object
+      (*groupIt)->computePrescribedDisplacement (t,dt);
+
+      // gather all displacements
+      set<vDisplacement,vDisplacementLess> objDisp = (*groupIt)->getPrescribedDisplacement();
+      set<vDisplacement,vDisplacementLess>::const_iterator itObjDx = objDisp.begin();
+      for(; itObjDx != objDisp.end(); itObjDx++) {
+        vDisplacement vdisp(*itObjDx);
+        prescribedDisplacement.insert(vdisp);
+      }
+    }
+  }
+
+  // ----------------------------------------------------------------------
+  int mobileObjectSet::partlyMove(vertexMoveOp& vMoveOp, double t, double dt, double * part)
+  {
+    computePrescribedDisplacement(t, dt);
+  
+    int ok = 0;
+    const int maxNumReduct = 8;
+    const double reductFactor = 0.5;
+    *part = 1.0;
+    cout<<"Attempts to move vertices: [ ";
+    for (int i=0; i < maxNumReduct; i++) {
+      cout <<"* ";
+      if (!vMoveOp.move(prescribedDisplacement,*part))  *part *= reductFactor;
+      else { ok = 1; break;}
+    }
+    cout << "]\n";
+    return ok;
+  }
+
+  // ----------------------------------------------------------------------
+  void mobileObjectSet::setupElasticRepositioning(pMesh mesh, double t, double dt, 
+                                                  double chi, bool meshIsCavity,
+                                                  int cavityThickness)
+  {
+    if ( mobSet.empty() ) return;
+
+    // setup the elastic operator
+    if (elasticOp) { delete elasticOp; elasticOp = NULL; }
+    elasticOp = new MAdElasticityOp(mesh);
+    if ( chi >= 0. ) elasticOp->setStiffnessAlterationCoef(chi);
+    elasticOp->setCavityEqualMesh(meshIsCavity,cavityThickness);
+
+    // prescribe bcs
+    computePrescribedDisplacement(t, dt);
+    set<vDisplacement,vDisplacementLess>::const_iterator dIter = prescribedDisplacement.begin();
+    set<vDisplacement,vDisplacementLess>::const_iterator dLast = prescribedDisplacement.end();
+    for (; dIter != dLast; dIter++) {
+      pVertex vert = (*dIter).pv;
+      smallVector disp(3);
+      for (int i=0; i<3; i++)  disp(i) = (*dIter).dxyz[i];
+      elasticOp->addDirichlet(vert,disp);
+    }
+
+    elasticOp->buildCavity();
+    elasticOp->setDirichletBC();
+
+    // compute elastic repositioning
+    elasticOp->compute();
+  }
+
+  // ----------------------------------------------------------------------
+  int mobileObjectSet::reposition(double * ratio)
+  {
+    if ( mobSet.empty() ) return true;
+    int flag = elasticOp->advance(ratio);
+    if ( flag == 2 ) elasticOp->clear();
+    return flag;
+  }
+
+  // ----------------------------------------------------------------------
+
+}
diff --git a/Adapt/repositioning/MobileObject.h b/Adapt/repositioning/MobileObject.h
new file mode 100644
index 0000000..8621260
--- /dev/null
+++ b/Adapt/repositioning/MobileObject.h
@@ -0,0 +1,149 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MOBILEOBJECT
+#define _H_MOBILEOBJECT
+
+#include "VertexMoveOp.h"
+#include "MAdStringFieldEvaluator.h"
+#include "LocalSizeField.h"
+#include "MSops.h"
+#include "MAdElasticityOp.h"
+
+#include <set>
+#include <list>
+#include <utility>
+#include <vector>
+#include <string>
+
+namespace MAd {
+
+  // ----------------------------------------------------------------------
+  enum velocityFormulation {
+    NOFORMULATION,
+    PARSED,
+    TRANSLATION,
+    FULLRANDOM,
+    RANDOM_TRANSLATION,
+    ISOMETRY,
+    ROTATION,
+    SHEAR_YZ,
+    SHEAR_ZX,
+    SHEAR_XY,
+    BENCH2,
+    CROSS_EXPANSION_WITH_ROTATION
+  };
+
+  // ----------------------------------------------------------------------
+  class mobileObject {
+
+  public:
+
+    mobileObject(const pMesh m,std::string _name="");
+    mobileObject(const mobileObject & mob);
+    ~mobileObject();
+
+    void setName(std::string nm) {name = nm;}
+    void setDxKinematics(std::vector<std::string> _Vstr);
+    void setVKinematics(velocityFormulation type, double V[3], 
+                        double C[3], std::vector<std::string> _Vstr);
+    void addLocalSField(LocalSizeField* lsf);
+    void addGEntity(int type, int tag);
+    void reAddVertices();
+
+    void computePrescribedDisplacement (double t, double dt);
+
+    void describe (std::ostream& out=std::cout) const;
+    const std::set<pVertex> getVertices() const {return vertices;}
+    std::set<vDisplacement,vDisplacementLess> getPrescribedDisplacement () const {return prescribedDisplacement;}
+    std::set<LocalSizeField* > getSizes() const { return sizes; }
+
+  private:
+
+    void addVerticesOnGEntity(int type, int tag);
+    void clearDisplacement();
+
+    void randomVelocity(double* V);
+    void velocityFunction(double xyz[3], double t, double* V);
+
+  private:
+
+    const pMesh mesh;
+    std::string name;
+    std::list<std::pair<int,int> > geomEntities; // list of (type,tag) 
+    std::set<pVertex> vertices;
+
+    // Parameters describing the kinematics
+    std::string prescribeType;
+    // for position ...
+    MAdStringFieldEvaluator* DxParsed; // displacement relative to and evaluated on initial position
+    // ... or velocity
+    velocityFormulation velType;
+    double Cxyz[3], Vxyz[3];
+    MAdStringFieldEvaluator* VParsed; // velocity evaluated on current position
+
+    //   // Parameters describing the size around
+    std::set<LocalSizeField* > sizes;
+
+    std::set<vDisplacement,vDisplacementLess> prescribedDisplacement;
+  };
+
+  // ----------------------------------------------------------------------
+  class mobileObjectSet {
+
+  public:
+
+    mobileObjectSet();
+    ~mobileObjectSet();
+
+    // larger possible motion by trials without volume nodes repositioning
+    int partlyMove(vertexMoveOp& vMoveOp, double t, double dt, double * part);
+
+    // move objects and reposition volume nodes. Needs the elastic operator. 
+    void setupElasticRepositioning(pMesh mesh, double t, double dt,double chi=-1,
+                                   bool meshIsCavity=true, int cavityThickness=3);
+
+    // Advances the relocation as far as possible
+    // Returns:
+    //    - 0: no relocation possible
+    //    - 1: advanced but not to the final position
+    //    - 2: reached the full prescribed relocation
+    int reposition(double * ratio);
+
+    // empty or fill the set
+    void clear();
+    void insert(mobileObject*);
+
+    std::set<vDisplacement,vDisplacementLess> getPrescribedDisplacement () const {return prescribedDisplacement;}
+    std::set<mobileObject*> getObjects() const {return mobSet;}
+
+    void describe(std::ostream& out=std::cout) const;
+ 
+  private:
+
+    // compute the objects displacement in a time interval
+    void computePrescribedDisplacement (double t, double dt) ;
+
+  private:
+
+    std::set<mobileObject*> mobSet;
+    std::set<vDisplacement,vDisplacementLess> prescribedDisplacement;
+
+    MAdElasticityOp * elasticOp;
+  };
+
+  // ----------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/repositioning/NodesRepositioningOp.h b/Adapt/repositioning/NodesRepositioningOp.h
new file mode 100644
index 0000000..ef5daf4
--- /dev/null
+++ b/Adapt/repositioning/NodesRepositioningOp.h
@@ -0,0 +1,59 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_NODESREPOSITIONINGOP
+#define _H_NODESREPOSITIONINGOP
+
+#include "DiscreteSF.h"
+#include "MeshQualityManager.h"
+#include "MeshDataBaseInterface.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  enum repositionType {
+    LAPLACE_FAST,
+    LAPLACE_OPTIMAL
+  };
+
+  // -------------------------------------------------------------------
+  class nodesRepositioningOp {
+
+  public:
+
+    nodesRepositioningOp(pMesh m, DiscreteSF * sf): 
+      mesh(m), sizeField(sf), mqm(MeshQualityManagerSgl::instance())
+    {
+      dim = 3;
+      if ( M_numRegions(mesh) == 0 ) dim = 2;
+    }
+    virtual ~nodesRepositioningOp() {}
+
+  public:
+
+    virtual int run(double * L2Norm)=0;
+
+  protected:
+
+    pMesh mesh;
+    int dim;
+    DiscreteSF * sizeField;
+    MeshQualityManager& mqm;
+
+  };
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/sizeField/AnalyticalSField.cc b/Adapt/sizeField/AnalyticalSField.cc
new file mode 100644
index 0000000..28f5b4a
--- /dev/null
+++ b/Adapt/sizeField/AnalyticalSField.cc
@@ -0,0 +1,382 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "AnalyticalSField.h"
+#include "MAdTimeManager.h"
+#include "IsoMeshSize.h"
+#include "AnisoMeshSize.h"
+#include "MathUtils.h"
+#include "MAdMessage.h"
+
+#include <math.h>
+#include <stdio.h>
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  // Constructors / destructors
+  // -------------------------------------------------------------------
+  AnalyticalSField::AnalyticalSField():
+    SizeFieldBase(), sFct(NULL), isotropic(true), evaluator(NULL)
+  {
+    setSize("1.");
+  }
+
+  // -------------------------------------------------------------------
+  AnalyticalSField::AnalyticalSField(std::string h):
+    SizeFieldBase(), sFct(NULL), isotropic(true), evaluator(NULL)
+  {
+    setSize(h);
+  }
+
+  // -------------------------------------------------------------------
+  AnalyticalSField::AnalyticalSField(std::vector<std::string> _h,
+                                     std::vector<std::string> _e0,
+                                     std::vector<std::string> _e1,
+                                     std::vector<std::string> _e2):
+    SizeFieldBase(), sFct(NULL), isotropic(false), evaluator(NULL)
+  {
+    setSize(_h,_e0,_e1,_e2);
+  }
+
+  // -------------------------------------------------------------------
+  AnalyticalSField::AnalyticalSField(sizeFunction f): 
+    SizeFieldBase(), sFct(f), isotropic(false),
+    evaluator(NULL)
+  {}
+
+  // -------------------------------------------------------------------
+  AnalyticalSField::~AnalyticalSField()
+  {
+    if (evaluator) delete evaluator;
+  }
+
+  // -------------------------------------------------------------------
+  void AnalyticalSField::describe() const {
+  
+    cout << "\nDescribing analytical size field: \n\n";
+  
+    cout << "  Orientation:   \t";
+    if (isotropic) cout << "Isotropic\n\n";
+    else           cout << "Anisotropic\n\n";
+
+    cout << "  Representation:\t";
+    if (sFct) cout << "Size Function\n\n";
+    else {
+      if (isotropic) {
+        cout << "String:\n";
+        cout << "   Size:  " << h0 << "\n\n";
+      }
+      else {
+        cout << "Strings:\n";
+
+        cout << "   - Sizes:\n";
+        cout << "     * " << h0 << "\n";
+        cout << "     * " << h1 << "\n";
+        cout << "     * " << h2 << "\n";
+
+        cout << "   - Vectors:\n";
+        cout << "     * " << e0[0] <<"\t" << e0[1] <<"\t" << e0[2] <<"\n";
+        cout << "     * " << e1[0] <<"\t" << e1[1] <<"\t" << e1[2] <<"\n";
+        cout << "     * " << e2[0] <<"\t" << e2[1] <<"\t" << e2[2] <<"\n";
+
+        cout << "\n";
+      }
+    }
+
+  }
+
+  // -------------------------------------------------------------------
+  // Size imposition
+  // -------------------------------------------------------------------
+  void AnalyticalSField::setSize(const std::string h)
+  {
+    if (sFct) throw;
+
+    isotropic = true;
+
+    h0 = h;
+    h1 = h;
+    h2 = h;
+    e0.resize(3);
+    e1.resize(3);
+    e2.resize(3);
+    e0[0] = "1."; e0[1] = "0."; e0[2] = "0.";
+    e1[0] = "0."; e1[1] = "1."; e1[2] = "0.";
+    e2[0] = "0."; e2[1] = "0."; e2[2] = "1.";
+
+    if(evaluator) delete evaluator;
+    evaluator = new MAdStringFieldEvaluator(1,h.c_str());
+  }
+
+  // -------------------------------------------------------------------
+  void AnalyticalSField::setSize(std::vector<std::string> _h,
+                                 std::vector<std::string> _e0,
+                                 std::vector<std::string> _e1,
+                                 std::vector<std::string> _e2)
+  {
+    if (sFct) throw;
+
+    isotropic = false;
+
+    h0 = _h[0];
+    h1 = _h[1];
+    h2 = _h[2];
+    e0 = _e0;
+    e1 = _e1;
+    e2 = _e2;
+
+    if(evaluator) delete evaluator;
+    evaluator = new MAdStringFieldEvaluator(12,
+                                            h0.c_str(), h1.c_str(), h2.c_str(), 
+                                            e0[0].c_str(), e0[1].c_str(), e0[2].c_str(),
+                                            e1[0].c_str(), e1[1].c_str(), e1[2].c_str(),
+                                            e2[0].c_str(), e2[1].c_str(), e2[2].c_str());
+  }
+
+  // -------------------------------------------------------------------
+  void AnalyticalSField::setSize(sizeFunction f)
+  {
+    if (evaluator) throw;
+    sFct = f;
+  }
+
+  // -------------------------------------------------------------------
+  // Evaluate a local size
+  // -------------------------------------------------------------------
+  pMSize AnalyticalSField::eval(const double xyz[3]) const
+  {
+    double time = MAdTimeManagerSgl::instance().getTime();
+
+    if(sFct)  return (*sFct)(xyz,time);
+
+    else {
+      if (isotropic) {
+        double h;
+        evaluator->eval(xyz,time,&h);
+        return new IsoMeshSize(h);
+      }
+      else {
+        double vals[12];
+        evaluator->eval(xyz,time,vals);
+        double h[3]        = {vals[0], vals[1], vals[2]};
+        double e[3][3]     = { {vals[3], vals[4], vals[5]},
+                               {vals[6], vals[7], vals[8]},
+                               {vals[9], vals[10], vals[11]} };
+        return new AnisoMeshSize(e,h);
+      }
+    }
+    return NULL;
+  }
+
+  // -------------------------------------------------------------------
+  pMSize AnalyticalSField::getSize(const pVertex pv) const
+  {
+    double xyz[3];
+    V_coord(pv,xyz);
+    return eval(xyz);
+  }
+
+  // -------------------------------------------------------------------
+  pMSize AnalyticalSField::getSizeOnEntity(const pEntity, 
+                                           const double xyz[3]) const
+  {
+    return eval(xyz);
+  }
+
+  // -------------------------------------------------------------------
+  // Length squared computation
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  double AnalyticalSField::SF_VV_lengthSq(const pVertex pV0, 
+                                          const pVertex pV1) const
+  {
+    double xyz[2][3];
+    V_coord(pV0,xyz[0]);
+    V_coord(pV1,xyz[1]);
+
+    pMSize pS[2];
+    pS[0] = getSize(pV0);
+    pS[1] = getSize(pV1);
+
+    double lSq = SF_XYZ_lengthSq(xyz[0],xyz[1],pS[0],pS[1]);
+  
+    if ( pS[0] ) delete pS[0];
+    if ( pS[1] ) delete pS[1];
+
+    return lSq;
+  }
+
+  // -------------------------------------------------------------------
+  double AnalyticalSField::SF_XYZ_lengthSq(const double xyz0[3], 
+                                           const double xyz1[3], 
+                                           const pMSize pS0, 
+                                           const pMSize pS1) const
+  {
+    if( pS0 )
+      {
+        double e[3];
+        diffVec(xyz0,xyz1,e);
+        double lenSq0 = pS0->normSq(e);
+        if ( pS1 )
+          {
+            double lenSq1 = pS1->normSq(e);
+            return sqrt(lenSq0*lenSq1);
+          }
+        else return lenSq0;
+      }
+    else {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"No size defined");
+    }
+    return 0.;
+  }
+
+  // -------------------------------------------------------------------
+  // Area squared computation
+  // -------------------------------------------------------------------
+
+  double AnalyticalSField::SF_F_areaSq(const pFace face) const
+  {
+    double area = 0.;
+
+    double xyz[3][3];
+    F_coordP1(face,xyz);
+  
+    void * temp = 0;
+    pPList fVerts = F_vertices(face,1);
+    while( pVertex pV = (pVertex)PList_next(fVerts,&temp) )
+      {
+        pMSize pS = getSize(pV);
+        area += SF_XYZ_areaSq(xyz,pS,0);
+        if (pS) delete pS;
+      }
+    PList_delete(fVerts);
+  
+    area /= F_numVertices(face);
+
+    return area;
+  }
+
+  // -------------------------------------------------------------------
+  double AnalyticalSField::SF_XYZ_areaSq(const double fxyz[3][3], 
+                                         const pMSize pS, 
+                                         const double norDir[3]) const
+  {
+    if( !pS ) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"No size defined");
+    }
+
+    // get the two first edges
+    double e01[3],e02[3];
+    diffVec(fxyz[1],fxyz[0],e01);
+    diffVec(fxyz[2],fxyz[0],e02);
+    
+    double nor[3];
+    crossProd(e01,e02,nor);
+
+    double l1SqInv = 1. / pS->lengthSqInDir(e01);
+    double l2SqInv = 1. / pS->lengthSqInDir(e02);
+
+    if( norDir && dotProd(norDir,nor) < MAdTOL ) return 0.;
+
+    double areaSq = 0.25 * dotProd(nor,nor) * l1SqInv * l2SqInv;
+    if( areaSq < MAdTOL ) return 0.;
+
+    return areaSq;
+  }
+
+  // -------------------------------------------------------------------
+  // Volume computation
+  // -------------------------------------------------------------------
+
+  double AnalyticalSField::SF_R_volume(const pRegion region) const
+  {
+    double vol = 0.;
+
+    double xyz[4][3];
+    R_coordP1(region,xyz);
+
+    pPList rVerts = R_vertices(region);
+    void * temp = 0;
+    while( pVertex pV = (pVertex)PList_next(rVerts,&temp) )
+      {
+        pMSize pS = getSize(pV);
+        vol += SF_XYZ_volume(xyz,pS);
+        if (pS) delete pS;
+      }
+    PList_delete(rVerts);
+
+    vol /= R_numVertices(region);
+
+    return vol;
+  }
+
+  // -------------------------------------------------------------------
+  double AnalyticalSField::SF_XYZ_volume(const double xyz[4][3], 
+                                         const pMSize pS) const
+  {
+    if( !pS ) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"No size defined");
+    }
+
+    double physVol = R_XYZ_volume(xyz);
+  
+    return ( physVol / (pS->size(0)*pS->size(1)*pS->size(2)) );
+  }
+
+  // -------------------------------------------------------------------
+  // Center of edge computation
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  double AnalyticalSField::SF_E_center(const pEdge edge, double center[3], 
+                                       double * reducSq, pMSize * cSize) const
+  {
+    return SF_VV_center(E_vertex(edge,0),E_vertex(edge,1),center,reducSq,cSize);
+  }
+
+  // -------------------------------------------------------------------
+  double AnalyticalSField::SF_VV_center(const pVertex v0, const pVertex v1,
+                                        double center[3], double * reducSq, 
+                                        pMSize * cSize) const
+  {
+    double xyz[2][3];
+    V_coord(v0,xyz[0]);
+    V_coord(v1,xyz[1]);
+
+    pMSize pS[2];
+    pS[0] = getSize(v0);
+    pS[1] = getSize(v1);
+
+    double cParam = SF_XYZ_center(xyz,pS,center,reducSq,cSize);
+
+    if ( pS[0] ) delete pS[0];
+    if ( pS[1] ) delete pS[1];
+
+    return cParam;
+  }
+
+  // -------------------------------------------------------------------
+  void AnalyticalSField::scale(double fact)
+  {
+    printf("Not implemented (AnalyticalSField::scale)\n");
+    throw;  
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/AnalyticalSField.h b/Adapt/sizeField/AnalyticalSField.h
new file mode 100644
index 0000000..8fb179f
--- /dev/null
+++ b/Adapt/sizeField/AnalyticalSField.h
@@ -0,0 +1,94 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_ANALYTICALSFIELD
+#define _H_ANALYTICALSFIELD
+
+#include "SizeFieldBase.h"
+#include "MAdStringFieldEvaluator.h"
+
+#include <vector>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  typedef pMSize (*sizeFunction)(const double[3],double);
+
+  // -------------------------------------------------------------------
+  class AnalyticalSField: public SizeFieldBase
+  {
+  public:
+
+    AnalyticalSField();
+    AnalyticalSField(std::string);
+    AnalyticalSField(std::vector<std::string>,std::vector<std::string>,
+                     std::vector<std::string>,std::vector<std::string>);
+    AnalyticalSField(sizeFunction);
+    ~AnalyticalSField();
+
+  public:
+
+    sFieldType getType() const { return ANALYTICALSFIELD; }
+    void describe() const;
+
+    void scale(double);
+
+    // set the size
+    void setSize(sizeFunction);
+    void setSize(const std::string);
+    void setSize(std::vector<std::string>,std::vector<std::string>,
+                 std::vector<std::string>,std::vector<std::string>);
+
+    // get the size at a location (allocate space!)
+    pMSize getSize(const pVertex) const;
+    pMSize getSizeOnEntity(const pEntity, const double[3]) const;
+
+    // edge length (squared)
+    double SF_VV_lengthSq(const pVertex, const pVertex) const;
+    double SF_XYZ_lengthSq(const double[3], const double[3],
+                           const pMSize, const pMSize=NULL) const;
+
+    // face area (squared)
+    double SF_F_areaSq(const pFace) const;
+    double SF_XYZ_areaSq(const double[3][3], const pMSize,
+                         const double[3]) const;
+
+    // region volume
+    double SF_R_volume(const pRegion) const;
+    double SF_XYZ_volume(const double[4][3], const pMSize) const;
+
+    // center and its associated size
+    double SF_E_center(const pEdge, double[3], double * reducSq, pMSize *) const;
+    double SF_VV_center(const pVertex, const pVertex,
+                        double[3], double * reducSq, pMSize *) const;
+
+  private:
+
+    // description of the sizes if we use functions
+    sizeFunction sFct;
+
+    // description of the sizes if we use strings
+    bool isotropic;
+    std::string h0, h1, h2;
+    std::vector<std::string> e0, e1, e2;
+    MAdStringFieldEvaluator * evaluator;
+
+  private:
+
+    pMSize eval(const double[3]) const;
+  };
+
+}
+
+// -------------------------------------------------------------------
+#endif
diff --git a/Adapt/sizeField/AnisoMeshSize.cc b/Adapt/sizeField/AnisoMeshSize.cc
new file mode 100644
index 0000000..f494fc9
--- /dev/null
+++ b/Adapt/sizeField/AnisoMeshSize.cc
@@ -0,0 +1,280 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "AnisoMeshSize.h"
+#include "MathUtils.h"
+#include "MAdMessage.h"
+#include "MAdDefines.h"
+#include "MeshParametersManager.h"
+
+#include <iostream>
+using std::string;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  AnisoMeshSize::AnisoMeshSize(double dirs[3][3], double _h[3]):
+    MeshSizeBase()
+  {
+    if( _h[0] <= 0. || _h[1] <= 0. || _h[2] <= 0. ) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Negative size(s): %f %f %f",
+                                  _h[0], _h[1], _h[2]);
+    }
+
+    double t1[3], t2[3], t3[3];
+    double l1,l2,l3;
+
+    // sort the sizes from lowest to highest and fill first direction (GCRemark: not useful)
+    int hMin = indexOfMin(_h[0], _h[1], _h[2]);
+    l1 = 1. / (_h[hMin] * _h[hMin]);
+    double normInv = 1. / sqrt ( dirs[hMin][0] * dirs[hMin][0] + 
+                                 dirs[hMin][1] * dirs[hMin][1] + 
+                                 dirs[hMin][2] * dirs[hMin][2]   );
+    for (int i=0; i<3; i++) t1[i] = dirs[hMin][i] * normInv;
+
+    hMin++;
+    if( _h[(hMin+1)%3] > _h[(hMin)%3] )
+      {
+        l2 = 1. / (_h[hMin%3] * _h[hMin%3]);
+        l3 = 1. / (_h[(hMin+1)%3] * _h[(hMin+1)%3]);
+        hMin  = hMin%3;
+      }
+    else
+      {
+        l2 = 1. / (_h[(hMin+1)%3] * _h[(hMin+1)%3]);
+        l3 = 1. / (_h[hMin%3] * _h[hMin%3]);
+        hMin = (hMin+1)%3;
+      }
+
+    // project dir 1 so that it is perpendicular to dir 0
+    double cosa = dotProd(t1,dirs[hMin]);
+    double vec[3];
+    for( int i=0; i<3; i++ ) vec[i] = dirs[hMin][i] - cosa * t1[i];
+    normInv = 1. / sqrt ( vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2] );
+    for (int i=0; i<3; i++) t2[i] = vec[i] * normInv;
+    
+    // find last dir as the direction orthogonal to the two previous ones
+    crossProd(t1,t2,t3);
+
+    // build the metric
+    M = MAdMetric(l1,l2,l3,t1,t2,t3);
+  }
+
+  // -------------------------------------------------------------------
+  AnisoMeshSize::AnisoMeshSize(double dir[3], double hDir, double hTg):
+    MeshSizeBase()
+  {
+    if( hDir <= 0. || hTg <= 0. ) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"Negative size(s): %f %f",
+                                  hDir, hTg);
+    }
+    
+    double e[3][3];
+    double len[3];
+
+    // see if 'dir' is the direction of the minimal length
+    int iDir = 0;
+    if ( hDir > hTg ) iDir = 2;
+
+    // set the 'dir' direction and its length
+    normalizeVec(dir,e[iDir]);
+    len[iDir] = 1. / ( hDir * hDir );
+
+    // set other sizes in the right order
+    len[(iDir+1)%3] = 1. / ( hTg * hTg );
+    len[(iDir+2)%3] = len[(iDir+1)%3];
+
+    // find a perpendicular direction to dir
+    double dummy[3];
+    dummy[0] = 2. * ( e[iDir][0] + 1.3654364 );
+    dummy[1] = 3. * ( e[iDir][1] + 3.1368136 );
+    dummy[2] = 5. * ( e[iDir][2] + 7.3683686 );
+    normalizeVec(dummy,dummy);
+    double cosa = dotProd(e[iDir],dummy);
+    for( int i=0; i<3; i++ ) dummy[i] -= cosa * e[iDir][i];
+    normalizeVec(dummy,e[(iDir+1)%3]);
+    
+    // find last dir as the direction orthogonal to the two previous ones
+    crossProd(e[iDir],e[(iDir+1)%3],e[(iDir+2)%3]);
+
+    // build the metric
+    M = MAdMetric(len[0],len[1],len[2],e[0],e[1],e[2]);
+  }
+
+  // -------------------------------------------------------------------
+  AnisoMeshSize::AnisoMeshSize(double h):
+    MeshSizeBase()
+  {
+    M = MAdMetric( 1./(h*h) );
+  }
+
+  // -------------------------------------------------------------------
+  AnisoMeshSize::AnisoMeshSize(const AnisoMeshSize &pm):
+    MeshSizeBase()
+  {
+    M = pm.M;
+  }
+
+  // -------------------------------------------------------------------
+  MeshSizeType AnisoMeshSize::getType() const 
+  {
+    return ANISOTROPIC;
+  }
+
+  // -------------------------------------------------------------------
+  void AnisoMeshSize::intersect(const pMSize pMS1, const pMSize pMS2)
+  {
+    M = intersection(pMS1->getMetric(),pMS2->getMetric());
+  }
+
+  // -------------------------------------------------------------------
+  void AnisoMeshSize::interpolate(const pMSize pMS0, const pMSize pMS1, 
+                                  double param)
+  {
+    M = interpolation(pMS0->getMetric(),pMS1->getMetric(),param);
+  }
+
+  // -------------------------------------------------------------------
+  void AnisoMeshSize::interpolate(const pMSize pMS0, const pMSize pMS1, 
+                                  const pMSize pMS2, double u, double v)
+  {
+    M = interpolation(pMS0->getMetric(), pMS1->getMetric(), 
+                      pMS2->getMetric(), u, v);
+  }
+
+  // -------------------------------------------------------------------
+  void AnisoMeshSize::interpolate(const pMSize pMS0, const pMSize pMS1, 
+                                  const pMSize pMS2, const pMSize pMS3, 
+                                  double u, double v, double w)
+  {
+    M = interpolation(pMS0->getMetric(), pMS1->getMetric(), 
+                      pMS2->getMetric(), pMS3->getMetric(), 
+                      u, v, w);
+  }
+
+  // -------------------------------------------------------------------
+  double AnisoMeshSize::size(int i) const
+  {
+    doubleMatrix V = doubleMatrix(3,3);
+    doubleVector S = doubleVector(3);
+    M.eig(V,S,true);
+    double s = 1. / sqrt( S(i) );
+    if ( std::isnan(s) ) return MeshParametersManagerSgl::instance().getBigLength();
+    return s;
+  }
+
+  // -------------------------------------------------------------------
+  void AnisoMeshSize::sizes(double _h[3]) const
+  {
+    doubleMatrix V = doubleMatrix(3,3);
+    doubleVector S = doubleVector(3);
+    M.eig(V,S,true);
+    for (int i=0; i<3; i++) {
+      _h[i] = ( 1. / sqrt( S(i) ) );
+      if ( std::isnan(_h[i]) ) _h[i] = MeshParametersManagerSgl::instance().getBigLength();
+    }
+  }
+
+  // -------------------------------------------------------------------
+  double AnisoMeshSize::direction(int i, double dir[3]) const 
+  {
+    doubleMatrix V = doubleMatrix(3,3);
+    doubleVector S = doubleVector(3);
+    M.eig(V,S,true); // each column of V is a direction, S gives corresponding 1/h^2
+    for (int iC=0; iC<3; iC++) dir[iC] = V(iC,i);
+    double s = 1. / sqrt( S(i) );
+    if ( std::isnan(s) ) return MeshParametersManagerSgl::instance().getBigLength();
+    return s;
+  }
+
+  // -------------------------------------------------------------------
+  void AnisoMeshSize::scale(int dir, double factor)
+  {
+    MAdMsgSgl::instance().error(__LINE__,__FILE__,"Not implemented");
+  }
+
+  // -------------------------------------------------------------------
+  void AnisoMeshSize::scale(double factor)
+  {
+    MAdMsgSgl::instance().error(__LINE__,__FILE__,"Not implemented");
+  }
+
+  // -------------------------------------------------------------------
+  double AnisoMeshSize::getMeanLength() const
+  {
+    doubleMatrix V = doubleMatrix(3,3);
+    doubleVector S = doubleVector(3);
+    M.eig(V,S,false);
+    double mean = 0.;
+    for (int i=0; i<3; i++) mean += 1. / sqrt( S(i) );
+    return ( MAdTHIRD * mean );
+  }
+
+  // -------------------------------------------------------------------
+  double AnisoMeshSize::getMinLength() const
+  {
+    doubleMatrix V = doubleMatrix(3,3);
+    doubleVector S = doubleVector(3);
+    M.eig(V,S,false);
+    int i = indexOfMax(S(0),S(1),S(2));
+    return ( 1. / sqrt( S(i) ) );
+  }
+
+  // -------------------------------------------------------------------
+  double AnisoMeshSize::getMaxLength() const
+  {
+    doubleMatrix V = doubleMatrix(3,3);
+    doubleVector S = doubleVector(3);
+    M.eig(V,S,false);
+    int i = indexOfMin(S(0),S(1),S(2));
+    return ( 1. / sqrt( S(i) ) );
+  }
+
+  // -------------------------------------------------------------------
+  // get the square of the norm in the metric
+  double AnisoMeshSize::normSq(const double vec[3]) const
+  {
+    return dot(vec,M,vec);
+  }
+
+  // -------------------------------------------------------------------
+  // get the square of desired edge length along 'vec'
+  double AnisoMeshSize::lengthSqInDir(const double vec[3]) const
+  {
+    double tmp[3];
+    normalizeVec(vec,tmp);
+    return ( 1. / dot(tmp,M,tmp) );
+  }
+    
+  // -------------------------------------------------------------------
+  // get the cosine of the angle with the direction of the minimal size
+  double AnisoMeshSize::angleWithDir0(const double dir[3]) const
+  {
+    double tmp[3];
+    normalizeVec(dir,tmp);
+    double dir0[3];
+    direction(0,dir0);
+    normalizeVec(dir0,dir0);
+    return dotProd(tmp,dir0);
+  }
+
+  // -------------------------------------------------------------------
+  void AnisoMeshSize::print(string name) const
+  {
+    std::cout<<"Printing AnisoMeshSize \'"<<name<<"\' ("<<this<<")\n";
+    M.print("Mesh size metric");
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/AnisoMeshSize.h b/Adapt/sizeField/AnisoMeshSize.h
new file mode 100644
index 0000000..b212a10
--- /dev/null
+++ b/Adapt/sizeField/AnisoMeshSize.h
@@ -0,0 +1,79 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_ANISOMESHSIZE
+#define _H_ANISOMESHSIZE
+
+#include "MeshSizeBase.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  // This class stores an anisotropic mesh size (prescribed edge length)
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  class AnisoMeshSize : public MeshSizeBase {
+
+  public:
+  
+    AnisoMeshSize(double e[3][3], double _h[3]);
+    AnisoMeshSize(double e[3], double hDir, double hTg);
+    AnisoMeshSize(double h=1.);
+    AnisoMeshSize(const AnisoMeshSize &);
+    ~AnisoMeshSize() {};
+
+  public:
+
+    MeshSizeType getType() const;
+    MAdMetric getMetric() const { return M; }
+
+    void   intersect(const pMSize pMS0, const pMSize pMS1);
+
+    void   interpolate(const pMSize, const pMSize, double);
+    void   interpolate(const pMSize, const pMSize, const pMSize, 
+                       double, double);
+    void   interpolate(const pMSize, const pMSize, const pMSize, const pMSize, 
+                       double, double, double);
+
+    double direction(int i, double dir[3]) const;
+    double size(int i=0) const;
+    void   sizes(double _h[3]) const;
+
+    // get the square of the norm in the metric
+    double normSq(const double vec[3]) const;
+
+    double lengthSqInDir(const double dir[3]) const ;
+    
+    // get the cosine of the angle with the direction of the minimal size
+    double angleWithDir0(const double dir[3]) const;
+
+    double getMeanLength() const;
+    double getMinLength() const;
+    double getMaxLength() const;
+
+    void   scale(int, double);
+    void   scale(double);
+
+    void   print(std::string name="") const;
+  
+  private:
+
+    MAdMetric M;
+  };
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/sizeField/DiscreteSF.cc b/Adapt/sizeField/DiscreteSF.cc
new file mode 100644
index 0000000..420f3b4
--- /dev/null
+++ b/Adapt/sizeField/DiscreteSF.cc
@@ -0,0 +1,80 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "DiscreteSF.h"
+#include "IsoMeshSize.h"
+#include "AnisoMeshSize.h"
+
+using namespace MAd;
+
+// -------------------------------------------------------------------
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  DiscreteSF::DiscreteSF(pMesh m, std::string name): SizeFieldBase(name)
+  {
+    mesh = m;
+    dim = M_dim(mesh);
+
+    pMSizeFieldId = MD_newMeshDataId("");
+  }
+ 
+  // -------------------------------------------------------------------
+  DiscreteSF::~DiscreteSF()
+  {
+    MD_deleteMeshDataId(pMSizeFieldId);
+  }
+
+  // -------------------------------------------------------------------
+  void DiscreteSF::deleteSize(pEntity entity)
+  {
+    void * temp;
+    if( EN_getDataPtr(entity,pMSizeFieldId,&temp) ) {
+      EN_deleteData(entity,pMSizeFieldId);
+      delete (pMSize)temp; 
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void DiscreteSF::setSize(pEntity ent, 
+                           double dirs[3][3],
+                           double h[3])
+  {
+    pMSize pS = new AnisoMeshSize(dirs,h);
+    setSize(ent,pS);
+  }
+
+
+  // -------------------------------------------------------------------
+  void DiscreteSF::setSize(pEntity ent, double h)
+  {
+    pMSize pS = new IsoMeshSize(h);
+    setSize(ent,pS);
+  }
+
+  // -------------------------------------------------------------------
+  void DiscreteSF::setSize(pEntity pEnt, pMSize pS)
+  {
+    void * temp;
+    if( EN_getDataPtr(pEnt,pMSizeFieldId,&temp) ) {
+      delete (pMSize)temp;
+      EN_modifyDataPtr(pEnt,pMSizeFieldId,pS);
+    }
+    else {
+      EN_attachDataPtr(pEnt,pMSizeFieldId,pS);
+    }
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/DiscreteSF.h b/Adapt/sizeField/DiscreteSF.h
new file mode 100644
index 0000000..1a839c9
--- /dev/null
+++ b/Adapt/sizeField/DiscreteSF.h
@@ -0,0 +1,103 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_DISCRETESF
+#define _H_DISCRETESF
+
+#include "SizeFieldBase.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  enum DiscreteSFType {
+    UNKNOWN_DSFTYPE,
+    VERTEX_P1_DSFTYPE
+  };
+
+  // -------------------------------------------------------------------
+  class DiscreteSF : public SizeFieldBase
+  {
+  public:
+
+    DiscreteSF(pMesh, std::string name="");
+    ~DiscreteSF();
+
+    sFieldType getType() const { return DISCRETESFIELD; }
+    virtual DiscreteSFType discretization() const = 0;
+    pMesh getMesh() { return mesh; }
+
+    // delete sizes
+    virtual void cleanUp() = 0;
+    void deleteSize(pEntity);
+
+    // Intersect with another size field
+    virtual void intersect(const pSField) = 0;
+
+    // smooth the size field
+    virtual void smooth(double) = 0;
+
+    // set a size at all vertices 
+    virtual void setCurrentSize() = 0;
+    virtual void setCurvatureSize(bool aniso, 
+                                  double alpha=2., // prescribe 2*PI*alpha edges around a circle
+                                  double hMin=1.e-4) = 0; // minimal size
+    virtual void setAllVSizes(pMSize) = 0;
+    virtual void setAllVSizes(double[3][3], double[3]) = 0;
+    virtual void setAllVSizes(double) = 0;
+    virtual void scale(double) = 0;
+
+    // set the size at a vertex 
+    void setSize(pEntity, double[3][3], double[3]);
+    void setSize(pEntity, pMSize);
+    void setSize(pEntity, double);
+
+    // get the size at a location (allocate space!)
+    virtual pMSize getSize(const pVertex) const = 0;
+    virtual pMSize getSizeOnEntity(const pEntity, const double[3]) const = 0;
+
+    // get the size at a vertex (do not allocate space)
+    virtual const pMSize findSize(const pVertex) const = 0;
+    virtual pMSize findSize(const pVertex) = 0;
+
+    // edge length (squared)
+    virtual double SF_VV_lengthSq(const pVertex, const pVertex) const = 0;
+    virtual double SF_XYZ_lengthSq(const double[3], const double[3],
+                                   const pMSize, const pMSize=NULL) const = 0;
+
+    // face area (squared)
+    virtual double SF_F_areaSq(const pFace) const = 0;
+    virtual double SF_XYZ_areaSq(const double[3][3], const pMSize,
+                                 const double[3]) const = 0;
+    
+    // region volume
+    virtual double SF_R_volume(const pRegion) const = 0;
+    virtual double SF_XYZ_volume(const double[4][3], const pMSize) const = 0;
+
+    // center and its associated size
+    virtual double SF_E_center(const pEdge, double[3], double *reducSq, pMSize *) const = 0;
+    virtual double SF_VV_center(const pVertex, const pVertex,
+                                double[3], double *reducSq, pMSize *) const = 0;
+
+  protected:
+
+    pMesh mesh;
+    int dim;
+    pMeshDataId pMSizeFieldId;
+
+  };
+
+}
+
+// -------------------------------------------------------------------
+
+#endif
diff --git a/Adapt/sizeField/IsoMeshSize.cc b/Adapt/sizeField/IsoMeshSize.cc
new file mode 100644
index 0000000..0ee6c99
--- /dev/null
+++ b/Adapt/sizeField/IsoMeshSize.cc
@@ -0,0 +1,176 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "IsoMeshSize.h"
+#include "MathUtils.h"
+#include "MAdMessage.h"
+
+#include <stdio.h>
+#include <iostream>
+#include <stdlib.h>
+using std::string;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  IsoMeshSize::IsoMeshSize(double _h):
+    MeshSizeBase()
+  {
+    h = _h;
+  }
+
+  // -------------------------------------------------------------------
+  IsoMeshSize::IsoMeshSize(const IsoMeshSize &pm):
+    MeshSizeBase()
+  {
+    h = pm.size();
+  }
+
+  // -------------------------------------------------------------------
+  MeshSizeType IsoMeshSize::getType() const 
+  {
+    return ISOTROPIC;
+  }
+
+  // -------------------------------------------------------------------
+  void IsoMeshSize::intersect(const pMSize pMS0, const pMSize pMS1)
+  {
+    if ( pMS0->getType() != ISOTROPIC || 
+         pMS1->getType() != ISOTROPIC    ) {
+      printf("Error: intersecting anisotropic sizes in isotropic mesh size\n");
+      exit(1);
+    }
+
+    double h0 = ((IsoMeshSize*)pMS0)->size();
+    double h1 = ((IsoMeshSize*)pMS1)->size();
+    h = std::min(h0,h1);
+  }
+
+  // -------------------------------------------------------------------
+  void IsoMeshSize::interpolate(const pMSize pMS0, const pMSize pMS1, 
+                                double param)
+  {
+    if ( pMS0->getType() != ISOTROPIC || 
+         pMS1->getType() != ISOTROPIC    ) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"Anisotropic size(s)");
+    }
+
+    double h0 = ((IsoMeshSize*)pMS0)->size();
+    double h1 = ((IsoMeshSize*)pMS1)->size();
+    h = h0 + param * ( h1 - h0 );
+  }
+
+  // -------------------------------------------------------------------
+  void IsoMeshSize::interpolate(const pMSize pMS0, const pMSize pMS1, 
+                                const pMSize pMS2, double u, double v)
+  {
+    if ( pMS0->getType() != ISOTROPIC || 
+         pMS1->getType() != ISOTROPIC || 
+         pMS2->getType() != ISOTROPIC    ) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"Anisotropic size(s)");
+    }
+
+    double h0 = ((IsoMeshSize*)pMS0)->size();
+    double h1 = ((IsoMeshSize*)pMS1)->size();
+    double h2 = ((IsoMeshSize*)pMS2)->size();
+    h = (1.-u-v) * h0 + u * h1 + v * h2;
+  }
+
+  // -------------------------------------------------------------------
+  void IsoMeshSize::interpolate(const pMSize pMS0, const pMSize pMS1, 
+                                const pMSize pMS2, const pMSize pMS3,
+                                double u, double v, double w)
+  {
+    if ( pMS0->getType() != ISOTROPIC || 
+         pMS1->getType() != ISOTROPIC || 
+         pMS2->getType() != ISOTROPIC || 
+         pMS3->getType() != ISOTROPIC    ) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"Anisotropic size(s)");
+    }
+
+    double h0 = ((IsoMeshSize*)pMS0)->size();
+    double h1 = ((IsoMeshSize*)pMS1)->size();
+    double h2 = ((IsoMeshSize*)pMS2)->size();
+    double h3 = ((IsoMeshSize*)pMS3)->size();
+    h = (1.-u-v-w) * h0 + u * h1 + v * h2 + w * h3;
+  }
+
+  // -------------------------------------------------------------------
+  double IsoMeshSize::direction(int i, double dir[3]) const 
+  {
+    for (int c=0; c<3; c++) dir[c] = 0.;
+    dir[i] = 1.;
+    return h;
+  }
+
+  // -------------------------------------------------------------------
+  double IsoMeshSize::size(int i) const {
+    return h;
+  }
+
+  // -------------------------------------------------------------------
+  void IsoMeshSize::sizes(double _h[3]) const {
+    _h[0] = _h[1] = _h[2] = h;
+  }
+
+  // -------------------------------------------------------------------
+  double IsoMeshSize::getMeanLength() const 
+  {
+    return h;
+  }
+
+  // -------------------------------------------------------------------
+  double IsoMeshSize::getMinLength() const 
+  {
+    return h;
+  }
+
+  // -------------------------------------------------------------------
+  double IsoMeshSize::getMaxLength() const 
+  {
+    return h;
+  }
+
+  // -------------------------------------------------------------------
+  void IsoMeshSize::setSize(double _h)
+  {
+    h = _h;
+  }
+
+  // -------------------------------------------------------------------
+  void IsoMeshSize::scale(double factor)
+  {
+    h *= factor;
+  }
+
+  // -------------------------------------------------------------------
+  double IsoMeshSize::normSq(const double vec[3]) const
+  {
+    return ( dotProd(vec,vec) / (h*h) );
+  }
+
+  // -------------------------------------------------------------------
+  double IsoMeshSize::lengthSqInDir(const double vec[3]) const
+  {
+    return h*h;
+  }
+
+  // -------------------------------------------------------------------
+  void IsoMeshSize::print(string name) const
+  {
+    std::cout<<"Printing IsoMeshSize \'"<<name<<"\' ("<<this<<")\n";
+    std::cout<<"  h:\t"<<h<<"\n";
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/IsoMeshSize.h b/Adapt/sizeField/IsoMeshSize.h
new file mode 100644
index 0000000..9ac8216
--- /dev/null
+++ b/Adapt/sizeField/IsoMeshSize.h
@@ -0,0 +1,74 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_ISOMESHSIZE
+#define _H_ISOMESHSIZE
+
+#include "MeshSizeBase.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  // This class stores an isotropic mesh size (prescribed edge length)
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  class IsoMeshSize : public MeshSizeBase {
+
+  public:
+  
+    IsoMeshSize(double _h=-1.);
+    IsoMeshSize(const IsoMeshSize &);
+    ~IsoMeshSize() {};
+
+  public:
+
+    MeshSizeType getType() const;
+    MAdMetric getMetric() const { return MAdMetric(1./(h*h)); }
+
+    void   intersect(const pMSize pMS0, const pMSize pMS1);
+    void   intersect(const pMSize pMS);
+
+    void   interpolate(const pMSize, const pMSize, double);
+    void   interpolate(const pMSize, const pMSize, const pMSize, 
+                       double, double);
+    void   interpolate(const pMSize, const pMSize, const pMSize, const pMSize, 
+                       double, double, double);
+
+    double direction(int i, double dir[3]) const;
+    double size(int i=0) const;
+    void   sizes(double _h[3]) const;
+    double normSq(const double vec[3]) const;
+    double lengthSqInDir(const double dir[3]) const ;
+
+    double getMeanLength() const;
+    double getMinLength() const;
+    double getMaxLength() const;
+
+    void   setSize(double);
+
+    void   scale(int, double);
+    void   scale(double);
+
+    void   print(std::string name="") const;
+  
+  private:
+
+    double h;
+  };
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/sizeField/LocalSizeField.cc b/Adapt/sizeField/LocalSizeField.cc
new file mode 100644
index 0000000..584288f
--- /dev/null
+++ b/Adapt/sizeField/LocalSizeField.cc
@@ -0,0 +1,542 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "LocalSizeField.h"
+#include "IsoMeshSize.h"
+#include "AnisoMeshSize.h"
+#include "MathUtils.h"
+#include "MAdMessage.h"
+#include "MeshParametersManager.h"
+#include "MAdTimeManager.h"
+#include "MAdResourceManager.h"
+
+#include <iostream>
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::set;
+using std::string;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  LocalSizeField::LocalSizeField(pMesh m, string name, bool _distToFaces):
+    SizeFieldBase(name), mesh(m), geoDim(-1),
+    isotropic(true), radius(-1.), sizeN(""), sizeT(""),
+    sEvalN(NULL), sEvalT(NULL), 
+    distToFaces(_distToFaces), dFct(mesh, distToFaces), 
+    limit(false), tgSizeLimitCoef(MAdBIG), maxCurv(MAdBIG)
+  {
+#ifdef PARALLEL
+    MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                "Local size fields not supported in parallel");
+#endif
+  }
+  
+  // -------------------------------------------------------------------
+  LocalSizeField::LocalSizeField(const LocalSizeField& _lsf): dFct(NULL,false)
+  {
+    throw;
+  }
+  
+  // -------------------------------------------------------------------
+  LocalSizeField::~LocalSizeField()  
+  {
+    if ( sEvalN ) delete sEvalN;
+    if ( sEvalT ) delete sEvalT;
+  }
+
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  void LocalSizeField::addGeometricEntity(int type, int tag)
+  {
+    // check that the new entity has the same dimension as the previous ones
+    if ( geoDim < 0 ) geoDim = type;
+    else if ( geoDim != type ) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Trying to insert a geo entity with dim %d while another entity with dim %d was previously inserted",
+                                  type, geoDim);
+    }
+
+    geomEntities.insert( GM_entityByTag(M_model(mesh),type,tag) );
+  }
+
+  // -------------------------------------------------------------------
+  void LocalSizeField::setIsoSize(double _radius, string _sizeN)
+  {
+    isotropic = true;
+    radius = _radius;
+    sizeN = _sizeN;
+    sizeT = "";
+    if( sEvalN ) delete sEvalN;
+    sEvalN = new MAdStringFieldEvaluator(1,sizeN.c_str());
+  }
+
+  // -------------------------------------------------------------------
+  void LocalSizeField::setAnisoSize(double _radius, string _sizeN, 
+                                    string _sizeT)
+  {
+    isotropic = false;
+    radius = _radius;
+    sizeN = _sizeN;
+    sizeT = _sizeT;
+    if( sEvalN ) delete sEvalN;
+    if( sEvalT ) delete sEvalT;
+    sEvalN = new MAdStringFieldEvaluator(1,sizeN.c_str());
+    sEvalT = new MAdStringFieldEvaluator(1,sizeT.c_str());
+  }
+
+  // -------------------------------------------------------------------
+  void LocalSizeField::setCurvatureLimiter(double onTgSize, double _maxCurv)
+  {
+    limit = true;
+    tgSizeLimitCoef = onTgSize;
+    maxCurv = _maxCurv;
+  }
+
+  // -------------------------------------------------------------------
+  pMSize LocalSizeField::getSize(const pVertex pv) const
+  {
+    // get the distance
+    double dist = dFct.getDistance(pv);
+
+    double dxyz[3] = {0., 0., 0.};  dxyz[0] = dist;
+
+    // get the time
+    double time = MAdTimeManagerSgl::instance().getTime();
+
+    // get the sizes for this distance at this time
+    double sizeN_d, sizeT_d;
+    sEvalN->eval(dxyz,time,&sizeN_d);
+    if ( !isotropic ) sEvalT->eval(dxyz,time,&sizeT_d);
+
+    pMSize theSize;
+
+    if (dist >= radius) {
+      theSize = new IsoMeshSize (MeshParametersManagerSgl::instance().getBigLength());
+    }
+    else {
+      if ( isotropic ) {
+        theSize = new IsoMeshSize( sizeN_d );
+      }
+      else {
+        double nor[3];
+        if ( !dFct.getGradient(pv,nor) ) {
+          MAdMsgSgl::instance().error(__LINE__,__FILE__,"Gradient not available for vertex %p",pv);
+        }
+
+        if ( fabs(nor[0]) <= MAdTOL && fabs(nor[1]) <= MAdTOL && fabs(nor[2]) <= MAdTOL ) {
+          theSize = new IsoMeshSize( sizeN_d );
+        }
+        else {
+          if ( limit )
+            {
+              double curvR;
+              if ( !dFct.getCurvature(pv,&curvR) ) {
+                MAdMsgSgl::instance().error(__LINE__,__FILE__,"Curvature not available for vertex %p",pv);
+              }
+              if ( curvR > MAdTOL ) {
+                curvR = std::min(curvR,maxCurv);
+                curvR = 1. / curvR;
+                // limit the tangent size regarding the curvature radius of the wall
+                sizeT_d = std::min(sizeT_d, tgSizeLimitCoef * curvR);
+                sizeT_d = std::max(sizeT_d,sizeN_d);
+              }
+            }
+
+          theSize = new AnisoMeshSize( nor, sizeN_d, sizeT_d );
+        }
+      }
+    }
+    return theSize;
+  }
+
+  // -------------------------------------------------------------------
+  pMSize LocalSizeField::getSizeOnEntity(const pEntity pe, 
+                                         const double xyz[3]) const
+  {
+    // get the distance
+    double dist = dFct.computeDistance(xyz);
+
+    double dxyz[3] = {0., 0., 0.};  dxyz[0] = dist;
+
+    // get the time
+    double time = MAdTimeManagerSgl::instance().getTime();
+
+    // get the sizes for this distance at this time
+    double sizeN_d, sizeT_d;
+    sEvalN->eval(dxyz,time,&sizeN_d);
+    if ( !isotropic ) sEvalT->eval(dxyz,time,&sizeT_d);
+
+    pMSize theSize;
+
+    if (dist > radius) {
+      theSize = new IsoMeshSize (MeshParametersManagerSgl::instance().getBigLength());
+    }
+    else {
+      if ( isotropic ) {
+        theSize = new IsoMeshSize( sizeN_d );
+      }
+      else {
+        double nor[3];
+        if ( !dFct.getGradientOnEntity(pe,xyz,nor) ) {
+          MAdMsgSgl::instance().error(__LINE__,__FILE__,"Gradient not available for entity %p",pe);
+        }
+
+        if ( fabs(nor[0]) <= MAdTOL && fabs(nor[1]) <= MAdTOL && fabs(nor[2]) <= MAdTOL ) {
+          theSize = new IsoMeshSize( sizeN_d );
+        }
+        else {
+          if ( limit )
+            {
+              double curvR;
+              if ( !dFct.getCurvatureOnEntity(pe,xyz,&curvR) ) {
+                MAdMsgSgl::instance().error(__LINE__,__FILE__,"Curvature not available for entity %p",pe);
+              }
+              if ( curvR > MAdTOL ) {
+                curvR = std::min(curvR,maxCurv);
+                curvR = 1. / curvR;
+                // limit the tangent size regarding the curvature radius of the wall
+                sizeT_d = std::min(sizeT_d, tgSizeLimitCoef * curvR);
+                sizeT_d = std::max(sizeT_d,sizeN_d);
+              }
+            }
+
+          theSize = new AnisoMeshSize( nor, sizeN_d, sizeT_d );
+        }
+      }
+    }
+    return theSize;
+  }
+
+  // -------------------------------------------------------------------
+  // Length squared computation
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  double LocalSizeField::SF_VV_lengthSq(const pVertex pV0, const pVertex pV1) const
+  {
+    double xyz[2][3];
+    V_coord(pV0,xyz[0]);
+    V_coord(pV1,xyz[1]);
+
+    pMSize pS[2];
+    pS[0] = getSize(pV0);
+    pS[1] = getSize(pV1);
+
+    double lSq = SF_XYZ_lengthSq(xyz[0],xyz[1],pS[0],pS[1]);
+  
+    if ( pS[0] ) delete pS[0];
+    if ( pS[1] ) delete pS[1];
+
+    return lSq;
+  }
+
+  // -------------------------------------------------------------------
+  double LocalSizeField::SF_XYZ_lengthSq(const double xyz0[3], 
+                                         const double xyz1[3], 
+                                         const pMSize pS0, 
+                                         const pMSize pS1) const
+  {
+    if( pS0 )
+      {
+        double e[3];
+        diffVec(xyz0,xyz1,e);
+        double lenSq0 = pS0->normSq(e);
+        if ( pS1 )
+          {
+            double lenSq1 = pS1->normSq(e);
+            return sqrt(lenSq0*lenSq1);
+          }
+        else return lenSq0;
+      }
+    else {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"No size defined");
+    }
+    return 0.;
+  }
+
+  // -------------------------------------------------------------------
+  // Area squared computation
+  // -------------------------------------------------------------------
+
+  double LocalSizeField::SF_F_areaSq(const pFace face) const
+  {
+    double area = 0.;
+
+    double xyz[3][3];
+    F_coordP1(face,xyz);
+  
+    void * temp = 0;
+    pPList fVerts = F_vertices(face,1);
+    while( pVertex pV = (pVertex)PList_next(fVerts,&temp) )
+      {
+        pMSize pS = getSize(pV);
+        area += SF_XYZ_areaSq(xyz,pS,0);
+        if (pS) delete pS;
+      }
+    PList_delete(fVerts);
+  
+    area /= F_numVertices(face);
+
+    return area;
+  }
+
+  // -------------------------------------------------------------------
+  double LocalSizeField::SF_XYZ_areaSq(const double fxyz[3][3], 
+                                       const pMSize pS, 
+                                       const double norDir[3]) const
+  {
+    if( !pS ) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"No size defined");
+    }
+
+    // get the two first edges
+    double e01[3],e02[3];
+    diffVec(fxyz[1],fxyz[0],e01);
+    diffVec(fxyz[2],fxyz[0],e02);
+    
+    double nor[3];
+    crossProd(e01,e02,nor);
+
+    double l1SqInv = 1. / pS->lengthSqInDir(e01);
+    double l2SqInv = 1. / pS->lengthSqInDir(e02);
+
+    if( norDir && dotProd(norDir,nor) < MAdTOL ) return 0.;
+
+    double areaSq = 0.25 * dotProd(nor,nor) * l1SqInv * l2SqInv;
+    if( areaSq < MAdTOL ) return 0.;
+
+    return areaSq;
+  }
+
+  // -------------------------------------------------------------------
+  // Volume computation
+  // -------------------------------------------------------------------
+
+  double LocalSizeField::SF_R_volume(const pRegion region) const
+  {
+    double vol = 0.;
+
+    double xyz[4][3];
+    R_coordP1(region,xyz);
+
+    pPList rVerts = R_vertices(region);
+    void * temp = 0;
+    while( pVertex pV = (pVertex)PList_next(rVerts,&temp) )
+      {
+        pMSize pS = getSize(pV);
+        vol += SF_XYZ_volume(xyz,pS);
+        if (pS) delete pS;
+      }
+    PList_delete(rVerts);
+
+    vol /= R_numVertices(region);
+
+    return vol;
+  }
+
+  // -------------------------------------------------------------------
+  double LocalSizeField::SF_XYZ_volume(const double xyz[4][3], const pMSize pS) const
+  {
+    if( !pS ) {
+      printf("Error in LocalSizeField::volume: no size given\n");
+      throw;
+    }
+
+    double physVol = R_XYZ_volume(xyz);
+  
+    return ( physVol / (pS->size(0)*pS->size(1)*pS->size(2)) );
+  }
+
+  // -------------------------------------------------------------------
+  // Center of edge computation
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  double LocalSizeField::SF_E_center(const pEdge edge, double center[3], 
+                                     double * reducSq, pMSize * cSize) const
+  {
+    return SF_VV_center(E_vertex(edge,0),E_vertex(edge,1),center,reducSq,cSize);
+  }
+
+  // -------------------------------------------------------------------
+  double LocalSizeField::SF_VV_center(const pVertex v0, const pVertex v1,
+                                      double center[3], double * reducSq, 
+                                      pMSize * cSize) const
+  {
+    double xyz[2][3];
+    V_coord(v0,xyz[0]);
+    V_coord(v1,xyz[1]);
+
+    pMSize pS[2];
+    pS[0] = getSize(v0);
+    pS[1] = getSize(v1);
+
+    double cParam = SF_XYZ_center(xyz,pS,center,reducSq,cSize);
+
+    if ( pS[0] ) delete pS[0];
+    if ( pS[1] ) delete pS[1];
+
+    return cParam;
+  }
+
+  // -------------------------------------------------------------------
+  bool LocalSizeField::getCurvature(const pVertex pv, double *c) const
+  {
+    return dFct.getCurvature(pv,c);
+  }
+
+  // ----------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  void LocalSizeField::scale(double fact)
+  {
+    printf("Not implemented (LocalSizeField::scale)\n");
+    throw;  
+  }
+
+  // ----------------------------------------------------------------------
+  // ----------------------------------------------------------------------
+  void LocalSizeField::updateTree()
+  {
+    MAdResourceManager& tm = MAdResourceManagerSgl::instance();
+    double t0 = tm.getTime();
+
+    set<pVertex> vertices;
+    set<pEntity> entities;
+    collectEntities(&vertices, &entities);
+    dFct.computeTree(vertices,entities);
+
+    printf("Computed tree in %f sec\n",tm.getTime()-t0);
+
+    if ( !isotropic )
+      {
+        // curvatures are not implemented in 2D
+        if ( M_dim(mesh) < 3 ) dFct.computeGradientAtVertices();
+        else {
+          
+          double t1 = tm.getTime();
+          dFct.computeAllDistAndGrad();
+          printf("Computed dist and grad in %f sec\n",tm.getTime()-t1);
+
+          double t2 = tm.getTime();
+
+          // gather all regions with a vertex in the scope of the size field
+          set<pRegion> allR;
+          pPList vRegs; void *temp=NULL;
+          VIter vit = M_vertexIter(mesh);
+          while (pVertex pv = VIter_next(vit)) {
+            if ( dFct.getDistance(pv) <= radius ) {
+              vRegs = V_regions(pv);
+              for (int i=0; i< PList_size(vRegs); i++) allR.insert((pRegion)PList_item(vRegs,i));
+              PList_delete(vRegs);
+            }
+          }
+          VIter_delete(vit);
+
+          //dFct.computeGradientAndCurvature(allR);
+          if ( limit ) {
+            dFct.computeCurvature(allR);
+            dFct.smoothCurvature(1);
+          }
+          printf("Computed curvatures in %f sec\n",tm.getTime()-t2);
+
+// #warning "debug: output curvatures in volume"
+//           double t3 = tm.getTime();
+//           dFct.outputDistance("dist.pos");
+//           if ( limit ) dFct.outputCurvature("curv.pos");
+//           dFct.outputGradAtVertices("grad.pos");
+//           printf("Outputs in %f sec\n",tm.getTime()-t3);
+//           exit(0);
+        }
+      }
+
+    printf("Updated tree in %f sec\n",tm.getTime()-t0);
+  }
+
+  // ----------------------------------------------------------------------
+  void LocalSizeField::collectEntities(set<pVertex> * verts, 
+                                       set<pEntity> * ents) const
+  {
+    verts->clear();
+    ents->clear();
+
+    set<pGEntity>::const_iterator it    = geomEntities.begin();
+    set<pGEntity>::const_iterator itEnd = geomEntities.end();
+    for (; it != itEnd; it++) 
+      {
+        switch ( GEN_type(*it) ) {
+        case 0:
+          {
+            VIter vit = M_vertexIter(mesh);
+            while (pVertex pv = VIter_next(vit))
+              {
+                if ( EN_whatIn((pEntity)pv) == *it ) {
+                  ents->insert(pv);
+                  verts->insert(pv);
+                }
+              }
+            VIter_delete(vit);
+            break;
+          }
+        case 1:
+          {
+            EIter eit = M_edgeIter(mesh);
+            while (pEdge pe = EIter_next(eit))
+              {
+                if ( EN_whatIn((pEntity)pe) == *it )
+                  {
+                    ents->insert(pe);
+                    verts->insert(E_vertex (pe,0));
+                    verts->insert(E_vertex (pe,1));
+                  }
+              }
+            EIter_delete(eit);
+          }
+        case 2:
+          {
+            FIter fit = M_faceIter(mesh);
+            while (pFace pf = FIter_next(fit))
+              {
+                if ( EN_whatIn((pEntity)pf) == *it )
+                  {
+                    ents->insert(pf);
+                    verts->insert(F_vertex (pf,0));
+                    verts->insert(F_vertex (pf,1));
+                    verts->insert(F_vertex (pf,2));
+                  }
+              }
+            FIter_delete(fit);
+          }
+        case 3:
+          {
+            RIter rit = M_regionIter(mesh);
+            while (pRegion pr = RIter_next(rit))
+              {
+                if ( EN_whatIn((pEntity)pr) == *it )
+                  {
+                    ents->insert(pr);
+                    verts->insert(R_vertex (pr,0));
+                    verts->insert(R_vertex (pr,1));
+                    verts->insert(R_vertex (pr,2));
+                    verts->insert(R_vertex (pr,3));
+                  }
+              }
+            RIter_delete(rit);
+          }
+        }
+      }
+  }
+
+  // ----------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/LocalSizeField.h b/Adapt/sizeField/LocalSizeField.h
new file mode 100644
index 0000000..a6f3162
--- /dev/null
+++ b/Adapt/sizeField/LocalSizeField.h
@@ -0,0 +1,121 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_LOCALSIZEFIELD
+#define _H_LOCALSIZEFIELD
+
+#include "SizeFieldBase.h"
+#include "DistanceFunction.h"
+#include "MAdStringFieldEvaluator.h"
+
+#include <set>
+#include <utility>
+#include <string>
+
+// -------------------------------------------------------------------
+/*
+  This class stores a size field around an object. 
+  * The object is defined by a set of geometrical entities.
+  * The size field is defined by a radius and strings giving the 
+    size in function of the distance to the object.
+  * Returns:
+    - If the distance is superior to the radius, the class 
+      returns a huge size.
+    - Otherwise, it can return one of these sizes:
+      - an isotropic size (evaluated from 'sizeN')
+      - an anisotropic size with a main axis in the normal 
+        direction to the object and a corresponding value ('sizeN'), 
+        and two axis in the tangent directions with another value 
+        ('sizeT').
+*/
+// -------------------------------------------------------------------
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class LocalSizeField : public SizeFieldBase {
+
+  public:
+
+    LocalSizeField(pMesh m, std::string name="", bool _distToFaces=false);
+    LocalSizeField(const LocalSizeField& _lsf);
+    ~LocalSizeField();
+
+    sFieldType getType() const { return LOCALSFIELD; }
+
+    void scale(double);
+
+    void addGeometricEntity(int type, int tag);
+    void updateTree();
+
+    void setIsoSize(double _radius, std::string _sizeN);
+    void setAnisoSize(double _radius, std::string _sizeN, std::string _sizeT);
+    void setCurvatureLimiter(double onTgSize, double _maxCurv=MAdBIG);
+
+    // get the size at a location (allocate space!)
+    pMSize getSize(const pVertex) const;
+    pMSize getSizeOnEntity(const pEntity, const double[3]) const;
+
+    // edge length (squared)
+    double SF_VV_lengthSq(const pVertex, const pVertex) const;
+    double SF_XYZ_lengthSq(const double[3], const double[3],
+                           const pMSize, const pMSize=NULL) const;
+
+    // face area (squared)
+    double SF_F_areaSq(const pFace) const;
+    double SF_XYZ_areaSq(const double[3][3], const pMSize,
+                         const double[3]) const;
+
+    // region volume
+    double SF_R_volume(const pRegion) const;
+    double SF_XYZ_volume(const double[4][3], const pMSize) const;
+
+    // center and its associated size
+    double SF_E_center(const pEdge, double[3], double * reducSq, pMSize *) const;
+    double SF_VV_center(const pVertex, const pVertex,
+                        double[3], double * reducSq, pMSize *) const;
+
+    // divergence of the curvature
+    bool getCurvature(const pVertex pv, double *c) const;
+    
+  private:
+
+    void collectEntities(std::set<pVertex> * verts, 
+                         std::set<pEntity> * ents) const;
+
+  private:
+
+    pMesh mesh;
+
+    std::set<pGEntity> geomEntities;
+    int geoDim;
+
+    bool isotropic;
+    double radius;
+    std::string sizeN, sizeT;
+    MAdStringFieldEvaluator * sEvalN, * sEvalT;
+
+    bool distToFaces; // true:  distance computed to the faces of the wall (exact)
+                      // false: distance computed to the vertices of the wall
+    distanceFunction dFct; // tool to compute distance and its derivatives
+
+    // limiters based on curvature
+    bool limit;
+    double tgSizeLimitCoef;
+    double maxCurv;
+  };
+
+}
+
+// -------------------------------------------------------------------
+#endif
diff --git a/Adapt/sizeField/MeshSizeBase.cc b/Adapt/sizeField/MeshSizeBase.cc
new file mode 100644
index 0000000..904dec9
--- /dev/null
+++ b/Adapt/sizeField/MeshSizeBase.cc
@@ -0,0 +1,104 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MeshSizeBase.h"
+#include "IsoMeshSize.h"
+#include "AnisoMeshSize.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  pMSize MS_copy(const pMSize pMS)
+  {
+    MeshSizeType type = pMS->getType();
+    switch (type) {
+    case ISOTROPIC:
+      return new IsoMeshSize((IsoMeshSize&)(*pMS));
+      break;
+    case ANISOTROPIC:
+      return new AnisoMeshSize((AnisoMeshSize&)(*pMS));
+      break;
+    default:
+      throw;
+    }
+  }
+
+  // -------------------------------------------------------------------
+  pMSize MS_intersect(const pMSize pMS0, const pMSize pMS1)
+  {
+    pMSize newS;
+    if ( pMS0->getType() == ISOTROPIC && 
+         pMS1->getType() == ISOTROPIC    ) {
+      newS = new IsoMeshSize();
+    }
+    else {
+      newS = new AnisoMeshSize();
+    }
+    newS->intersect(pMS0,pMS1);
+
+    return newS;
+  }
+
+  // -------------------------------------------------------------------
+  pMSize MS_interpolate(const pMSize pMS0, const pMSize pMS1, double param)
+  {
+    pMSize newS;
+    if ( pMS0->getType() == ISOTROPIC && 
+         pMS1->getType() == ISOTROPIC    ) {
+      newS = new IsoMeshSize();
+    }
+    else {
+      newS = new AnisoMeshSize();
+    }
+    newS->interpolate(pMS0,pMS1,param);
+    return newS;
+  }
+
+  // -------------------------------------------------------------------
+  pMSize MS_interpolate(const pMSize pMS0, const pMSize pMS1, 
+                        const pMSize pMS2, double u, double v)
+  {
+    pMSize newS;
+    if ( pMS0->getType() == ISOTROPIC &&
+         pMS1->getType() == ISOTROPIC &&
+         pMS2->getType() == ISOTROPIC    ) {
+      newS = new IsoMeshSize();
+    }
+    else {
+      newS = new AnisoMeshSize();
+    }
+    newS->interpolate(pMS0,pMS1,pMS2,u,v);
+    return newS;
+  }
+
+  // -------------------------------------------------------------------
+  pMSize MS_interpolate(const pMSize pMS0, const pMSize pMS1, 
+                        const pMSize pMS2, const pMSize pMS3,
+                        double u, double v, double w)
+  {
+    pMSize newS;
+    if ( pMS0->getType() == ISOTROPIC &&
+         pMS1->getType() == ISOTROPIC &&
+         pMS2->getType() == ISOTROPIC &&
+         pMS3->getType() == ISOTROPIC    ) {
+      newS = new IsoMeshSize();
+    }
+    else {
+      newS = new AnisoMeshSize();
+    }
+    newS->interpolate(pMS0,pMS1,pMS2,pMS3,u,v,w);
+    return newS;
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/MeshSizeBase.h b/Adapt/sizeField/MeshSizeBase.h
new file mode 100644
index 0000000..a6d3c68
--- /dev/null
+++ b/Adapt/sizeField/MeshSizeBase.h
@@ -0,0 +1,105 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MESHSIZEBASE
+#define _H_MESHSIZEBASE
+
+#include "MAdMetric.h"
+
+#include <string>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  enum MeshSizeType {
+    ISOTROPIC,
+    ANISOTROPIC
+  };
+
+  // -------------------------------------------------------------------
+  typedef class MeshSizeBase * pMSize;
+
+  // -------------------------------------------------------------------
+  pMSize MS_copy(const pMSize pMS);
+  pMSize MS_intersect(const pMSize pMS0, const pMSize pMS1);
+  // interpolate on an edge
+  pMSize MS_interpolate(const pMSize, const pMSize, double);
+  // interpolate on a triangle
+  pMSize MS_interpolate(const pMSize, const pMSize, const pMSize, 
+                        double, double);
+  // interpolate on a tetrahedron
+  pMSize MS_interpolate(const pMSize, const pMSize, const pMSize, const pMSize, 
+                        double, double, double);
+
+  // -------------------------------------------------------------------
+  // This class stores a mesh size (prescribed edge length)
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  class MeshSizeBase
+  {
+  public:
+  
+    MeshSizeBase() {};
+    virtual ~MeshSizeBase() {};
+
+  public:
+
+    virtual MeshSizeType getType() const = 0;
+    virtual MAdMetric getMetric() const = 0;
+
+    // this becomes the minimum size between two sizes
+    virtual void   intersect(const pMSize pMS0, const pMSize pMS1) = 0;
+
+    // this becomes the interpolation between two sizes
+    virtual void   interpolate(const pMSize, const pMSize, double) = 0;
+    // this becomes the interpolation between three sizes
+    virtual void   interpolate(const pMSize, const pMSize, const pMSize, 
+                               double, double) = 0;
+    // this becomes the interpolation between four sizes
+    virtual void   interpolate(const pMSize, const pMSize, const pMSize, const pMSize, 
+                               double, double, double) = 0;
+
+    // get a principle direction (eigenvectors of the metric)
+    virtual double direction(int i, double dir[3]) const = 0;
+
+    // get the desired size in a principle direction (eigenvalues)
+    virtual double size(int i=0) const = 0;
+
+    // get the desired size in the 3 directions (eigenvalues)
+    virtual void   sizes(double _h[3]) const = 0;
+
+    // get the square norm of the vector in the metric
+    virtual double normSq(const double vec[3]) const = 0;
+
+    // get the desired size in the given direction
+    virtual double lengthSqInDir(const double dir[3]) const = 0;
+
+    // get the mean, min, max sizes
+    virtual double getMeanLength() const = 0;
+    virtual double getMinLength()  const = 0;
+    virtual double getMaxLength()  const = 0;
+
+    // scale the size
+    virtual void   scale(double) = 0;
+
+    // print info
+    virtual void   print(std::string name="") const = 0;
+
+  };
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/sizeField/NullSField.cc b/Adapt/sizeField/NullSField.cc
new file mode 100644
index 0000000..3bd1d8b
--- /dev/null
+++ b/Adapt/sizeField/NullSField.cc
@@ -0,0 +1,107 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "NullSField.h"
+#include "MathUtils.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  // Length squared computation
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  double NullSField::SF_VV_lengthSq(const pVertex v0, const pVertex v1) const
+  {
+    double xyz[2][3];
+    V_coord(v0,xyz[0]);
+    V_coord(v1,xyz[1]);
+
+    return SF_XYZ_lengthSq(xyz[0],xyz[1],NULL,NULL);
+  }
+
+  // -------------------------------------------------------------------
+  double NullSField::SF_XYZ_lengthSq(const double xyz0[3], const double xyz1[3], 
+                                     const pMSize, const pMSize) const
+  {
+    double vec[3];
+    diffVec(xyz0,xyz1,vec);
+
+    return dotProd(vec,vec); 
+  }
+
+  // -------------------------------------------------------------------
+  // Area squared computation
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  double NullSField::SF_F_areaSq(const pFace face) const
+  { 
+    double xyz[3][3];
+    F_coordP1(face,xyz);
+
+    return SF_XYZ_areaSq(xyz,NULL,NULL);
+  }
+
+  // -------------------------------------------------------------------
+  double NullSField::SF_XYZ_areaSq(const double xyz[3][3], const pMSize, 
+                                   const double norDir[3]) const
+  {
+    return XYZ_F_areaSq(xyz,norDir);
+  }
+
+  // -------------------------------------------------------------------
+  // Volume computation
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  double NullSField::SF_R_volume(const pRegion r) const
+  {
+    return R_volume(r);
+  }
+
+  // -------------------------------------------------------------------
+  double NullSField::SF_XYZ_volume(const double xyz[4][3], 
+                                   const pMSize) const
+  {
+    return R_XYZ_volume(xyz);
+  }
+
+  // -------------------------------------------------------------------
+  // Center of edge computation
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  double NullSField::SF_E_center(const pEdge edge, 
+                                 double center[3], double * reducSq, 
+                                 pMSize *) const
+  {
+    return SF_VV_center(E_vertex(edge,0),E_vertex(edge,1),center,reducSq,NULL);
+  }
+
+  // -------------------------------------------------------------------
+  double NullSField::SF_VV_center(const pVertex v0, const pVertex v1, 
+                                  double center[3], double * reducSq, 
+                                  pMSize *) const
+  {
+    double xyz[2][3];
+    V_coord(v0,xyz[0]);
+    V_coord(v1,xyz[1]);
+
+    for(int i=0; i<3; i++) center[i] = 0.5*(xyz[0][i]+xyz[1][i]);
+    *reducSq = 0.5;
+    return 0.5;
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/NullSField.h b/Adapt/sizeField/NullSField.h
new file mode 100644
index 0000000..ff1e9b3
--- /dev/null
+++ b/Adapt/sizeField/NullSField.h
@@ -0,0 +1,66 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_NULLSFIELD
+#define _H_NULLSFIELD
+
+#include "SizeFieldBase.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class NullSField : public SizeFieldBase
+  {
+  public:
+
+    NullSField(): SizeFieldBase() {}
+    ~NullSField() {}
+
+    sFieldType getType() const { return NULLSFIELD; }
+
+    // edge length (squared)
+    double SF_VV_lengthSq(const pVertex, const pVertex) const;
+    double SF_XYZ_lengthSq(const double[3], const double[3],
+                           const pMSize, const pMSize=NULL) const;
+
+    // face area (squared)
+    double SF_F_areaSq(const pFace) const;
+    double SF_XYZ_areaSq(const double[3][3], const pMSize,
+                         const double[3]) const;
+
+    // region volume
+    double SF_R_volume(const pRegion) const;
+    double SF_XYZ_volume(const double[4][3], const pMSize) const;
+
+    // center and its associated size
+    double SF_E_center(const pEdge, double[3], double * reducSq, pMSize *) const;
+    double SF_VV_center(const pVertex, const pVertex,
+                        double[3], double * reducSq, pMSize *) const;
+
+  public: // functions that have no sense here...
+
+    void scale(double) {return;}
+
+    void setSize(pEntity, pMSize) {return;}
+    void setSize(pEntity, double) {return;}
+    void deleteSize(pEntity) {return;}
+
+    pMSize getSize(const pVertex) const {return NULL;}
+    pMSize getSizeOnEntity(const pEntity, const double[3]) const {return NULL;};
+  };
+
+}
+
+// -------------------------------------------------------------------
+
+#endif
diff --git a/Adapt/sizeField/PWLinearSField.cc b/Adapt/sizeField/PWLinearSField.cc
new file mode 100644
index 0000000..ecce2fd
--- /dev/null
+++ b/Adapt/sizeField/PWLinearSField.cc
@@ -0,0 +1,590 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "PWLinearSField.h"
+#include "CallBackManager.h"
+#include "IsoMeshSize.h"
+#include "AnisoMeshSize.h"
+#include "MathUtils.h"
+#include "MAdMessage.h"
+#include "MeshParametersManager.h"
+
+#include <stdio.h>
+#include <math.h>
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+#include <queue>
+
+using namespace MAd;
+
+// -------------------------------------------------------------------
+void PWLinearSFCBFunction (pPList before, pPList after, void * data,
+                           operationType type , pEntity ppp) 
+{
+  PWLSField * pwl = (PWLSField *)(data);
+
+  switch (type) {
+  case MAd_ESPLIT: {
+
+    double xyz[3];
+    V_coord((pVertex)ppp,xyz);
+
+    // find the old edge
+    void *tmp=0;
+    pEntity pE = PList_next(before,&tmp);
+
+    // interpolate size at new location
+    pMSize newSize = pwl->getSizeOnEntity(pE,xyz);
+
+    pwl->setSize(ppp,newSize);    
+    break;
+  } 
+  case MAd_ECOLLAPSE: {
+    pwl->deleteSize(ppp);
+    break;
+  }
+  case MAd_FSWAP:
+  case MAd_ESWAP: {
+    break;
+  }
+  case MAd_RREMOVE: {
+    void * temp = NULL;
+    while ( pEntity pE = PList_next(before,&temp) ) {
+      if ( EN_type(pE) == 0 ) {
+        pwl->deleteSize( (pVertex)pE );
+      }
+    }
+    break;
+  }
+  default: {
+    MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                "Not implemented for mesh modification %d",
+                                type);
+  }
+  }
+}
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  PWLSField::PWLSField(pMesh m, std::string name): DiscreteSF(m, name)
+  {
+    CallBackManagerSgl::instance().registerCallBack(PWLinearSFCBFunction,this);
+  }
+ 
+  // -------------------------------------------------------------------
+  PWLSField::~PWLSField()
+  {
+    cleanUp();
+    CallBackManagerSgl::instance().unregisterCallBack(PWLinearSFCBFunction,this);
+  }
+
+  // -------------------------------------------------------------------
+  void PWLSField::cleanUp() 
+  {
+    VIter iter = M_vertexIter(mesh);
+    while( pVertex pV = VIter_next(iter) ) deleteSize((pEntity)pV);
+    VIter_delete(iter);
+  }
+
+  // -------------------------------------------------------------------
+  void PWLSField::intersect(const pSField extField) 
+  {
+    VIter iter = M_vertexIter(mesh);
+    while( pVertex pV = VIter_next(iter) )
+      {
+        // get the size for the extern size field
+        pMSize extS = extField->getSize(pV);
+        if (!extS) continue;
+
+        // get the size for this size field
+        pMSize intS = this->findSize(pV);
+        if (!intS) {
+          setSize((pEntity)pV,extS);
+        }
+        else {
+          pMSize newS = MS_intersect(intS,extS);
+          delete extS;
+          setSize(pV,newS);
+        }
+      }
+    VIter_delete(iter);
+  }
+
+  // -------------------------------------------------------------------
+  // Smooth the size field by limiting the size gradient along an edge 
+  // to maxGrad
+  void PWLSField::smooth(double maxGrad)
+  {
+    // edges still to be checked
+    std::queue<pEdge> toCheck;
+
+    // check every edge at least once
+    EIter eIt = M_edgeIter(mesh);
+    while( pEdge edge = EIter_next(eIt) ) toCheck.push(edge);
+    EIter_delete(eIt);
+  
+    while ( !toCheck.empty() ) {
+
+      std::set<pEdge> toAdd;
+
+      // check the content of toCheck
+      while ( !toCheck.empty() ) {
+        smoothOnEdge(toCheck.front(),maxGrad,&toAdd);
+        toCheck.pop();
+      }
+
+      // move content of toAdd to toCheck
+      std::set<pEdge>::const_iterator eIter = toAdd.begin();
+      for (; eIter != toAdd.end(); eIter++ ) toCheck.push(*eIter);
+      toAdd.clear();
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void PWLSField::smoothOnEdge(const pEdge edge, double maxGrad, 
+                               std::set<pEdge>* toAdd)
+  {
+    pVertex pV[2];
+    pMSize pMS[2];
+    double h[2];
+    for (int iV=0; iV<2; iV++) {
+      pV[iV] = E_vertex(edge,iV);
+      pMS[iV] = findSize(pV[iV]);
+      if ( pMS[iV]->getType() != ISOTROPIC ) {
+        printf("Error: PWLSField::smoothOnEdge not implemented for anisotropic sizes\n");
+        exit(1);
+      }
+      h[iV] = ( (IsoMeshSize*)(pMS[iV]) )->size();
+    }
+  
+    double physLength = E_length(edge);
+
+    double grad = fabs( h[1] - h[0] ) / physLength;
+    if ( grad > maxGrad ) {
+    
+      int toScale = 1;
+      if ( h[0] > h[1] ) toScale = 0;
+    
+      double maxSize = maxGrad * physLength + h[1-toScale];
+      ( (IsoMeshSize*)(pMS[toScale]) )->setSize(maxSize-MAdTOL);
+
+      for( int iE=0; iE<V_numEdges(pV[toScale]); iE++ ) {
+        pEdge newEdge = V_edge(pV[toScale],iE);
+        if ( newEdge == edge ) continue;
+        toAdd->insert(newEdge);
+      }
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void PWLSField::setCurrentSize() 
+  {
+    VIter vi = M_vertexIter(mesh);
+    while ( pVertex vert = VIter_next(vi) ) {
+      double lenSq = V_meanEdgeLenSq(vert);
+      pMSize pSV = new IsoMeshSize(sqrt(lenSq));
+      setSize((pEntity)vert,pSV);
+    }
+    VIter_delete(vi);
+  }
+
+  // -------------------------------------------------------------------
+  void PWLSField::setCurvatureSize(bool aniso, double alpha, double hMin) 
+  {
+    if ( !(mesh->isParametric()) ) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Curvature not available without a geometry (mesh is not parametric");
+    }
+
+#ifdef _HAVE_GMSH_
+    double bigLen = MeshParametersManagerSgl::instance().getBigLength();
+    double curvMaxBound = 10. / hMin;
+    pVertex vert;
+    VIter vi = M_vertexIter(mesh);
+    while ( ( vert = VIter_next(vi) ) )
+      {
+        pGEntity pge = V_whatIn(vert);
+        int gdim = GEN_type(pge);
+        pMSize pSV;
+        if ( aniso && gdim==2 )
+          {
+            double u[2];
+            V_params(vert,&(u[0]),&(u[1]));
+            double dir[3][3], curv[3];
+            GF_curvatures((pGFace)pge, u, dir[0], dir[1], &(curv[0]), &(curv[1]), curvMaxBound);
+            crossProd(dir[0],dir[1],dir[2]);
+            curv[2] = -1.;
+            
+            double h[3] = { -1., -1., -1. };
+            for (int iD=0; iD<3; iD++) {
+              if ( curv[iD] <= MAdTOL ) h[iD] = bigLen;
+              else {
+                h[iD] = 1. / ( curv[iD] * alpha );
+                h[iD] = std::min(std::max(h[iD],hMin),bigLen);
+              }
+            }
+
+            pSV = new AnisoMeshSize(dir,h);
+          }
+        else 
+          {
+            double curv = -1.;
+            switch(gdim) {
+            case 3: break;
+            case 2: {
+              double u[2];
+              V_params(vert,&(u[0]),&(u[1]));
+              curv = GF_curvatureDiv((pGFace)pge, u, curvMaxBound);
+              break;
+            }
+            case 1: {
+              double u, tmp;
+              V_params(vert,&u,&tmp);
+              curv = GE_curvature((pGEdge)pge, u, curvMaxBound);
+              break;
+            }
+            case 0: {
+              curv = -1.;
+              std::list<pGEdge> gEdges = GV_edges((pGVertex)pge);
+              std::list<pGEdge>::const_iterator eIter = gEdges.begin();
+              for (; eIter != gEdges.end(); eIter++) {
+                pGEdge pGEd = *eIter;
+                double u;
+                GV_reparamOnEdge((pGVertex)pge, pGEd, &u);
+                double tmpcurv = GE_curvature(pGEd, u, curvMaxBound);
+                if ( tmpcurv > curv ) curv = tmpcurv;
+              }
+              break;
+            }
+            }
+        
+            double h = -1.;
+            if ( curv <= MAdTOL ) h = bigLen;
+            else {
+              h = 1. / ( curv * alpha );
+              h = std::min(std::max(h,hMin),bigLen);
+            }
+            pSV = new IsoMeshSize(h);
+          }
+        setSize((pEntity)vert,pSV);
+      }
+    VIter_delete(vi);
+#else
+    MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                "Curvature not available without Gmsh");
+#endif
+  }
+
+  // -------------------------------------------------------------------
+  void PWLSField::setAllVSizes(pMSize pS)
+  {
+    VIter vi = M_vertexIter(mesh);
+    while ( pVertex vert = VIter_next(vi) ) {
+      pMSize pSCopy = MS_copy(pS);
+      setSize((pEntity)vert,pSCopy);
+    }
+    VIter_delete(vi);
+  }
+
+  // -------------------------------------------------------------------
+  void PWLSField::setAllVSizes(double dirs[3][3], // three unit vectors
+                               double h[3])
+  {
+    pMSize pS = new AnisoMeshSize(dirs,h);
+    setAllVSizes(pS);
+  }
+
+  // -------------------------------------------------------------------
+  void PWLSField::setAllVSizes(double h)
+  {
+    pMSize pS = new IsoMeshSize(h);
+    setAllVSizes(pS);
+  }
+
+  // -------------------------------------------------------------------
+  void PWLSField::scale(double fact)
+  {
+    VIter vIter = M_vertexIter(mesh);
+    while( pVertex pV = VIter_next(vIter) )
+      {
+        pMSize pS = findSize(pV);
+        pS->scale(fact);
+      }
+    VIter_delete(vIter);
+  }
+
+  // -------------------------------------------------------------------
+  // Length squared computation
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  double PWLSField::SF_VV_lengthSq(const pVertex v0, const pVertex v1) const
+  {
+    double xyz[2][3];
+    V_coord(v0,xyz[0]);
+    V_coord(v1,xyz[1]);
+
+    pMSize pS[2];
+    pS[0] = findSize(v0);
+    pS[1] = findSize(v1);
+
+    return SF_XYZ_lengthSq(xyz[0],xyz[1],pS[0],pS[1]);
+  }
+
+  // -------------------------------------------------------------------
+  double PWLSField::SF_XYZ_lengthSq(const double xyz0[3], const double xyz1[3], 
+                                    const pMSize pS0, const pMSize pS1) const
+  {
+    if( pS0 )
+      {
+        double e[3];
+        diffVec(xyz0,xyz1,e);
+        double lenSq0 = pS0->normSq(e);
+        if ( pS1 )
+          {
+            double lenSq1 = pS1->normSq(e);
+            return sqrt(lenSq0*lenSq1);
+          }
+        else return lenSq0;
+      }
+    else {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"No size defined");
+    }
+    return 0.;
+  }
+
+  // -------------------------------------------------------------------
+  // Area squared computation
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  double PWLSField::SF_F_areaSq(const pFace face) const
+  {
+    double area = 0.;
+
+    double xyz[3][3];
+    F_coordP1(face,xyz);
+  
+    void * temp = 0;
+    pPList fVerts = F_vertices(face,1);
+    while( pVertex pV = (pVertex)PList_next(fVerts,&temp) )
+      {
+        pMSize pS = findSize(pV);
+        area += SF_XYZ_areaSq(xyz,pS,0);
+      }
+    PList_delete(fVerts);
+  
+    area /= F_numVertices(face);
+
+    return area;
+  }
+
+  // -------------------------------------------------------------------
+  double PWLSField::SF_XYZ_areaSq(const double fxyz[3][3], const pMSize pS, 
+                                  const double norDir[3]) const
+  {
+    if( !pS ) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"No size defined");
+    }
+
+    // get the two first edges
+    double e01[3],e02[3];
+    diffVec(fxyz[1],fxyz[0],e01);
+    diffVec(fxyz[2],fxyz[0],e02);
+    
+    double nor[3];
+    crossProd(e01,e02,nor);
+
+    double l1SqInv = 1. / pS->lengthSqInDir(e01);
+    double l2SqInv = 1. / pS->lengthSqInDir(e02);
+
+    if( norDir && dotProd(norDir,nor) < MAdTOL ) return 0.;
+
+    double areaSq = 0.25 * dotProd(nor,nor) * l1SqInv * l2SqInv;
+    if( areaSq < MAdTOL ) return 0.;
+
+    return areaSq;
+  }
+
+  // -------------------------------------------------------------------
+  // Volume computation
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  double PWLSField::SF_R_volume(const pRegion region) const
+  {
+    double vol = 0.;
+
+    double xyz[4][3];
+    R_coordP1(region,xyz);
+
+    pPList rVerts = R_vertices(region);
+    void * temp = 0;
+    while( pVertex pV = (pVertex)PList_next(rVerts,&temp) )
+      {
+        pMSize pS = findSize(pV);
+        vol += SF_XYZ_volume(xyz,pS);
+      }
+    PList_delete(rVerts);
+
+    vol /= R_numVertices(region);
+
+    return vol;
+  }
+
+  // -------------------------------------------------------------------
+  double PWLSField::SF_XYZ_volume(const double xyz[4][3], const pMSize pS) const
+  {
+    if( !pS ) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"No size defined");
+    }
+
+    double physVol = R_XYZ_volume(xyz);
+    double h[3];
+    pS->sizes(h);
+    return ( physVol / ( h[0] * h[1] * h[2]) );
+  }
+
+  // -------------------------------------------------------------------
+  // Center of edge computation
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  double PWLSField::SF_E_center(const pEdge edge, double center[3], 
+                                double * reducSq, pMSize * cSize) const
+  {
+    return SF_VV_center(E_vertex(edge,0),E_vertex(edge,1),center,reducSq,cSize);
+  }
+
+  // -------------------------------------------------------------------
+  double PWLSField::SF_VV_center(const pVertex v0, const pVertex v1,
+                                 double center[3], double * reducSq, 
+                                 pMSize * cSize) const
+  {
+    double xyz[2][3];
+    V_coord(v0,xyz[0]);
+    V_coord(v1,xyz[1]);
+
+    pMSize pS[2];
+    pS[0] = findSize(v0);
+    pS[1] = findSize(v1);
+    
+    return SF_XYZ_center(xyz,pS,center,reducSq,cSize);
+  }
+
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  const pMSize PWLSField::findSize(const pVertex pV) const
+  {
+    void * size;
+    if( EN_getDataPtr( (pEntity)pV, pMSizeFieldId, &size) ) return (pMSize)size;
+    return NULL;
+  }
+
+  // -------------------------------------------------------------------
+  pMSize PWLSField::findSize(const pVertex pV)
+  {
+    void * size;
+    if( EN_getDataPtr( (pEntity)pV, pMSizeFieldId, &size) ) return (pMSize)size;
+    return NULL;
+  }
+
+  // -------------------------------------------------------------------
+  pMSize PWLSField::getSize(const pVertex pV) const
+  {
+    void * temp;
+    if( EN_getDataPtr((pEntity)pV,pMSizeFieldId,&temp) ) {
+      return MS_copy((pMSize)temp);
+    }
+    return NULL;
+  }
+
+  // -------------------------------------------------------------------
+  pMSize PWLSField::getSizeOnEntity(const pEntity entity, 
+                                    const double xyz[3]) const
+  {
+    int type = EN_type(entity);
+    switch(type) {
+    case 0: return getSize((pVertex)entity);
+    case 1: return getSizeOnEdge((pEdge)entity,xyz);
+    case 2: return getSizeOnFace((pFace)entity,xyz);
+    case 3: return getSizeOnRegion((pRegion)entity,xyz);
+    }
+    return NULL;
+  }
+
+  // -------------------------------------------------------------------
+  pMSize PWLSField::getSizeOnEdge(const pEdge edge, 
+                                  const double xyz[3]) const
+  {
+    double u = E_linearParams(edge,xyz);
+    return getSizeOnEdgeParam(edge,u);
+  }
+
+  // -------------------------------------------------------------------
+  pMSize PWLSField::getSizeOnEdgeParam(const pEdge pE, 
+                                       const double u) const
+  {
+    pMSize pS0 = findSize( E_vertex(pE,0) );
+    pMSize pS1 = findSize( E_vertex(pE,1) );
+  
+    return MS_interpolate( pS0, pS1, u );
+  }
+
+  // -------------------------------------------------------------------
+  pMSize PWLSField::getSizeOnFace(const pFace face, 
+                                  const double xyz[3]) const
+  {
+    double u[2];
+    F_linearParams(face,xyz,u);
+    return getSizeOnFaceParam(face,u);
+  }
+
+  // -------------------------------------------------------------------
+  pMSize PWLSField::getSizeOnFaceParam(const pFace face, 
+                                       const double u[2]) const
+  {
+    pMSize pS0 = findSize( F_vertex(face,0) );
+    pMSize pS1 = findSize( F_vertex(face,1) );
+    pMSize pS2 = findSize( F_vertex(face,2) );
+
+    return MS_interpolate( pS0, pS1, pS2, u[0], u[1] );
+  }
+
+  // -------------------------------------------------------------------
+  pMSize PWLSField::getSizeOnRegion(const pRegion region, 
+                                    const double xyz[3]) const
+  {
+    double u[3];
+    R_linearParams(region, xyz, u);
+    return getSizeOnRegionParam(region, u);
+  }
+
+  // -------------------------------------------------------------------
+  pMSize PWLSField::getSizeOnRegionParam(const pRegion region, 
+                                         const double u[3]) const
+  {
+    pMSize pS0 = findSize( R_vertex(region,0) );
+    pMSize pS1 = findSize( R_vertex(region,1) );
+    pMSize pS2 = findSize( R_vertex(region,2) );
+    pMSize pS3 = findSize( R_vertex(region,3) );
+
+    return MS_interpolate( pS0, pS1, pS2, pS3, u[0], u[1], u[2] );
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/PWLinearSField.h b/Adapt/sizeField/PWLinearSField.h
new file mode 100644
index 0000000..d254cc1
--- /dev/null
+++ b/Adapt/sizeField/PWLinearSField.h
@@ -0,0 +1,96 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_PWLINEARSFIELD
+#define _H_PWLINEARSFIELD
+
+#include "DiscreteSF.h"
+
+#include <set>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class PWLSField : public DiscreteSF
+  {
+  public:
+
+    PWLSField(pMesh, std::string name="");
+    ~PWLSField();
+
+    DiscreteSFType discretization() const { return VERTEX_P1_DSFTYPE; }
+
+    // delete sizes
+    void cleanUp();
+
+    // Intersect with another size field
+    void intersect(const pSField);
+
+    // smooth the size field
+    void smooth(double);
+
+    // set a size at all vertices 
+    void setCurrentSize();
+    void setCurvatureSize(bool aniso, 
+                          double alpha=2., // prescribe 2*PI*alpha edges around a circle
+                          double hMin=1.e-4); // minimal size
+    void setAllVSizes(pMSize);
+    void setAllVSizes(double[3][3], double[3]);
+    void setAllVSizes(double);
+    void scale(double);
+
+    // get the size at a location (allocate space!)
+    pMSize getSize(const pVertex) const;
+    pMSize getSizeOnEntity(const pEntity, const double[3]) const;
+
+    // get the size at a vertex (do not allocate space)
+    const pMSize findSize(const pVertex) const;
+    pMSize findSize(const pVertex);
+
+    // edge length (squared)
+    double SF_VV_lengthSq(const pVertex, const pVertex) const;
+    double SF_XYZ_lengthSq(const double[3], const double[3],
+                           const pMSize, const pMSize=NULL) const;
+
+    // face area (squared)
+    double SF_F_areaSq(const pFace) const;
+    double SF_XYZ_areaSq(const double[3][3], const pMSize,
+                         const double[3]) const;
+
+    // region volume
+    double SF_R_volume(const pRegion) const;
+    double SF_XYZ_volume(const double[4][3], const pMSize) const;
+
+    // center and its associated size
+    double SF_E_center(const pEdge, double[3], double * reducSq, pMSize *) const;
+    double SF_VV_center(const pVertex, const pVertex,
+                        double[3], double * reducSq, pMSize *) const;
+
+  protected:
+
+    pMSize getSizeOnEdge(const pEdge, const double[3]) const;
+    pMSize getSizeOnEdgeParam(const pEdge, const double) const;
+    pMSize getSizeOnFace(const pFace, const double[3]) const;
+    pMSize getSizeOnFaceParam(const pFace, const double[2]) const;
+    pMSize getSizeOnRegion(const pRegion, const double[3]) const;
+    pMSize getSizeOnRegionParam(const pRegion, const double[3]) const;
+
+    void smoothOnEdge(const pEdge, double, std::set<pEdge>*);
+
+  };
+
+}
+
+// -------------------------------------------------------------------
+
+#endif
diff --git a/Adapt/sizeField/SizeFieldBase.cc b/Adapt/sizeField/SizeFieldBase.cc
new file mode 100644
index 0000000..b8b7dc8
--- /dev/null
+++ b/Adapt/sizeField/SizeFieldBase.cc
@@ -0,0 +1,90 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "SizeFieldBase.h"
+#include "MAdOutput.h"
+#include "MathUtils.h"
+
+using std::string;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  // Length squared computation
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  double SizeFieldBase::SF_E_lengthSq(const pEdge edge) const
+  {
+    return SF_VV_lengthSq(E_vertex(edge,0),E_vertex(edge,1));
+  }
+
+  // -------------------------------------------------------------------
+  // Center of edge computation
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  double SizeFieldBase::SF_XYZ_center(const double xyz[2][3], const pMSize pS[2],
+                                      double center[3], double * reducSq, 
+                                      pMSize * cSize) const
+  {
+    if( !pS[0] || !pS[1] ) {
+      printf("Error in SizeFieldBase::SF_XYZ_center: one of the sizes is NULL\n");
+      throw;
+    }
+
+    double vec[3];
+    diffVec(xyz[1],xyz[0],vec);
+
+    double lenSq[2];
+    lenSq[0] = pS[0]->lengthSqInDir(vec);
+    lenSq[1] = pS[1]->lengthSqInDir(vec);
+    double lenRatSqrt = pow(lenSq[1]/lenSq[0],0.25);
+
+    double cParam = 1. / ( 1. + lenRatSqrt );
+    *reducSq = 1. / ( 1./lenRatSqrt + lenRatSqrt + 2 );
+
+//     double len[2];
+//     len[0] = sqrt(pS[0]->lengthSqInDir(vec));
+//     len[1] = sqrt(pS[1]->lengthSqInDir(vec));
+
+//     double cParam = len[0] / ( len[0] + len[1] );
+
+    for (int i=0; i<3; i++) {
+      center[i] = cParam * xyz[1][i] + (1-cParam) * xyz[0][i];
+    }
+
+    *cSize = MS_interpolate(pS[0],pS[1],cParam);
+
+    return cParam;
+  }
+
+  // -------------------------------------------------------------------
+  void SizeFieldBase::printPosIsotropic(const pMesh mesh, const string name)
+  {
+    MAdGmshOutput(mesh, this, name.c_str(), OD_SIZEFIELD_MEAN);
+  }
+
+  // -------------------------------------------------------------------
+  void SizeFieldBase::printPosAnisotropic(const pMesh mesh, const string baseName)
+  {
+    string name0 = baseName + "0.pos";
+    MAdGmshOutput(mesh, this, name0.c_str(), OD_ANISO_SF_AXIS0);
+    string name1 = baseName + "1.pos";
+    MAdGmshOutput(mesh, this, name1.c_str(), OD_ANISO_SF_AXIS1);
+    string name2 = baseName + "2.pos";
+    MAdGmshOutput(mesh, this, name2.c_str(), OD_ANISO_SF_AXIS2);
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/SizeFieldBase.h b/Adapt/sizeField/SizeFieldBase.h
new file mode 100644
index 0000000..74aab5f
--- /dev/null
+++ b/Adapt/sizeField/SizeFieldBase.h
@@ -0,0 +1,101 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_SIZEFIELDBASE
+#define _H_SIZEFIELDBASE
+
+#include "MeshSizeBase.h"
+#include "MSops.h"
+#include "MAdDefines.h"
+
+#include <string>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  enum sFieldType {
+    UNKNOWNSFIELDTYPE,
+    NULLSFIELD,
+    DISCRETESFIELD,
+    ANALYTICALSFIELD,
+    LOCALSFIELD
+  };
+
+  // -------------------------------------------------------------------
+  typedef class SizeFieldBase * pSField;
+
+  // -------------------------------------------------------------------
+  class SizeFieldBase 
+  {
+  public:
+  
+    SizeFieldBase(std::string _name=""): name(_name) {};
+    virtual ~SizeFieldBase() {};
+  
+  public:
+  
+    virtual sFieldType getType() const = 0 ;
+    std::string getName() const { return name; }
+  
+    virtual void scale(double) = 0;
+  
+  public:
+
+    // edge length (squared)
+    virtual double SF_E_lengthSq(const pEdge) const;
+    virtual double SF_VV_lengthSq(const pVertex,const pVertex) const = 0;
+    virtual double SF_XYZ_lengthSq(const double[3], const double[3],
+                                   const pMSize, const pMSize=NULL) const = 0;
+
+    // face area (squared)
+    virtual double SF_F_areaSq(const pFace) const = 0;
+    virtual double SF_XYZ_areaSq(const double[3][3], const pMSize,
+                                 const double[3]) const = 0;
+
+    // region volume
+    virtual double SF_R_volume(const pRegion) const = 0;
+    virtual double SF_XYZ_volume(const double[4][3], const pMSize) const = 0;
+
+    // center and its associated size
+    virtual double SF_E_center(const pEdge, double[3], double * reducSq, pMSize *) const = 0;
+    virtual double SF_VV_center(const pVertex, const pVertex,
+                                double[3], double * reducSq, pMSize *) const = 0;
+    virtual double SF_XYZ_center(const double[2][3], const pMSize[2],
+                                 double[3], double * reducSq, pMSize *) const;
+
+  public:
+
+    // get the size at a location
+    // --- Memory is allocated ! ---
+    virtual pMSize getSize(const pVertex) const = 0;
+    virtual pMSize getSizeOnEntity(const pEntity, 
+                                   const double[3]) const = 0;
+
+  public:
+
+    // visualisation of the isotropic size in a .pos file
+    void printPosIsotropic  (const pMesh mesh, const std::string name);
+    // visualisation of the anisotropic size in a .pos file
+    void printPosAnisotropic(const pMesh mesh, const std::string baseName);
+
+  private:
+
+    std::string name;
+
+  };
+
+}
+
+// -------------------------------------------------------------------
+
+#endif
diff --git a/Adapt/sizeField/SizeFieldManager.cc b/Adapt/sizeField/SizeFieldManager.cc
new file mode 100644
index 0000000..d69a5c9
--- /dev/null
+++ b/Adapt/sizeField/SizeFieldManager.cc
@@ -0,0 +1,175 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "SizeFieldManager.h"
+#include "NullSField.h"
+#include "MAdTimeManager.h"
+#include "MeshQualityManager.h"
+#include "MAdMessage.h"
+
+#include <iostream>
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::set;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  SizeFieldManager::SizeFieldManager(pMesh m, pSField psf): 
+    localTime(-1.),smooth(false),maxGradient(1.)
+  {
+    if (!m) return;
+    mesh = m;
+
+    mainSF = new PWLSField(mesh,"Main size field");
+
+    localTime = MAdTimeManagerSgl::instance().getTime();
+
+    if (!psf) MAdMsgSgl::instance().warning(__LINE__,__FILE__,"No size field registered");
+
+    else {
+    
+      mainSF->intersect(psf);
+  
+      sFieldType type = psf->getType();
+      switch (type) {
+      case NULLSFIELD: {
+        break;
+      }
+      case DISCRETESFIELD: {
+        assert ( ((DiscreteSF*)psf)->discretization() == VERTEX_P1_DSFTYPE );
+        PWLSField* linsf = static_cast<PWLSField*>(psf);
+        addPWLinearSF( linsf );
+        break;
+      }
+      case ANALYTICALSFIELD: {
+        AnalyticalSField* asf = static_cast<AnalyticalSField*>(psf);
+        addAnalyticalSF( asf );
+        break;
+      }
+      case LOCALSFIELD: {
+        LocalSizeField* locsf = static_cast<LocalSizeField*>(psf);
+        addLocalSF( locsf );
+        break;
+      }
+      default: {
+        cerr <<"Error: unknown size field type "<<type<<"\n"; throw;
+      }
+      }
+    }  
+  }
+
+  // -------------------------------------------------------------------
+  SizeFieldManager::~SizeFieldManager() {
+
+    if (mainSF) delete mainSF;
+    linears.clear();
+    analyticals.clear();
+    locals.clear();
+  }
+
+  // -------------------------------------------------------------------
+  void SizeFieldManager::setMesh(pMesh m)
+  {
+    mesh = m;
+    mainSF = new PWLSField(mesh);
+    MAdMsgSgl::instance().warning(__LINE__,__FILE__,"No size field registered");
+  }
+
+  // -------------------------------------------------------------------
+  void SizeFieldManager::intersect(const pSField sf) {
+    mainSF->intersect(sf);
+  }
+
+  // -------------------------------------------------------------------
+  void SizeFieldManager::addSizeField(pSField sf) {
+
+    mainSF->intersect(sf);
+  
+    sFieldType type = sf->getType();
+    switch (type) {
+    case NULLSFIELD: {
+      break;
+    }
+    case DISCRETESFIELD: {
+      assert ( ((DiscreteSF*)sf)->discretization() == VERTEX_P1_DSFTYPE );
+      PWLSField* linsf = static_cast<PWLSField*>(sf);
+      addPWLinearSF( linsf );
+      break;
+    }
+    case ANALYTICALSFIELD: {
+      AnalyticalSField* asf = static_cast<AnalyticalSField*>(sf);
+      addAnalyticalSF( asf );
+      break;
+    }
+    case LOCALSFIELD: {
+      LocalSizeField* locsf = static_cast<LocalSizeField*>(sf);
+      addLocalSF( locsf );
+      break;
+    }
+    default: {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Unknown size field type %d",type);
+    }
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void SizeFieldManager::addPWLinearSF(PWLSField* sf) {
+    linears.insert(sf);
+  }
+
+  // -------------------------------------------------------------------
+  void SizeFieldManager::addAnalyticalSF(AnalyticalSField* sf) {
+    analyticals.insert(sf);
+  }
+
+  // -------------------------------------------------------------------
+  void SizeFieldManager::addLocalSF(LocalSizeField* sf) {
+    locals.insert(sf);
+  }
+
+  // -------------------------------------------------------------------
+  void SizeFieldManager::update()
+  {
+    MeshQualityManagerSgl::instance().clearAllShapes(); // not useful in isotropic case (be careful about the hypothesis)
+
+    mainSF->cleanUp();
+
+    set<PWLSField*>::const_iterator linIter = linears.begin();
+    set<PWLSField*>::const_iterator linLast = linears.end();
+    for (; linIter != linLast; linIter++) {
+      mainSF->intersect(*linIter);
+    }
+
+    set<AnalyticalSField*>::const_iterator aIter = analyticals.begin();
+    set<AnalyticalSField*>::const_iterator aLast = analyticals.end();
+    for (; aIter != aLast; aIter++) {
+      mainSF->intersect(*aIter);
+    }
+
+    set<LocalSizeField*>::iterator locIter = locals.begin();
+    set<LocalSizeField*>::iterator locLast = locals.end();
+    for (; locIter != locLast; locIter++) {
+      (*locIter)->updateTree();
+      mainSF->intersect(*locIter);
+    }
+
+    if ( smooth ) mainSF->smooth(maxGradient);
+
+    localTime = MAdTimeManagerSgl::instance().getTime();
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/sizeField/SizeFieldManager.h b/Adapt/sizeField/SizeFieldManager.h
new file mode 100644
index 0000000..99207fc
--- /dev/null
+++ b/Adapt/sizeField/SizeFieldManager.h
@@ -0,0 +1,85 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_SIZEFIELDMANAGER
+#define _H_SIZEFIELDMANAGER
+
+#include "SizeFieldBase.h"
+#include "PWLinearSField.h"
+#include "LocalSizeField.h"
+#include "AnalyticalSField.h"
+
+#include <set>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  // This class lists, intersects and updates all size fields
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+
+  class SizeFieldManager {
+
+  public:
+
+    SizeFieldManager(pMesh m, pSField psf=NULL);
+    ~SizeFieldManager();
+
+  public:
+
+    void setMesh(pMesh m);
+    void setSmoothing(bool enable, double maxGrad) 
+    {
+      smooth = enable;
+      maxGradient = maxGrad;
+    }
+
+    void intersect(const pSField sf);
+
+    void addSizeField(pSField sf);
+
+    void update();
+
+    DiscreteSF* getSizeField()             { return mainSF; }
+    const DiscreteSF* getSizeField() const { return mainSF; }
+
+    std::set<LocalSizeField *> getLocalSizeFields() const { return locals; }
+
+  private:
+
+    void addPWLinearSF(PWLSField * sf);
+    void addAnalyticalSF(AnalyticalSField * sf);
+    void addLocalSF(LocalSizeField * sf);
+
+  private:
+
+    DiscreteSF* mainSF;
+
+    std::set<PWLSField *>        linears;
+    std::set<AnalyticalSField *> analyticals;
+    std::set<LocalSizeField *>   locals;
+
+    pMesh mesh;
+
+    double localTime;
+
+    bool smooth;
+    double maxGradient;
+  };
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/utils/CallBackManager.cc b/Adapt/utils/CallBackManager.cc
new file mode 100644
index 0000000..e69b8da
--- /dev/null
+++ b/Adapt/utils/CallBackManager.cc
@@ -0,0 +1,100 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "CallBackManager.h"
+
+using std::list;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  void CallBackManager::initialize()
+  {
+  }
+
+  // -------------------------------------------------------------------
+  void CallBackManager::finalize()
+  {
+    CB.clear();
+    CBMove.clear();
+  }
+
+  // -------------------------------------------------------------------
+  void CallBackManager::registerCallBack(CBFunction CBFct, 
+                                         void* userData)
+  {
+    CBStructure cb;
+    cb.function = CBFct;
+    cb.data = userData;
+    CB.push_back(cb);
+  }
+
+  // -------------------------------------------------------------------
+  void CallBackManager::registerCallBackMove(CBFunc_move CB_move, 
+                                             void* userData_move)
+  {
+    CBStructureMove cbm;
+    cbm.function = CB_move;
+    cbm.data = userData_move;
+    CBMove.push_back(cbm);
+  }
+
+  // -------------------------------------------------------------------
+  void CallBackManager::unregisterCallBack(CBFunction CBFct, 
+                                           void* userData)
+  {
+    CBStructure cb;
+    cb.function = CBFct;
+    cb.data = userData;
+    CB.remove(cb);
+  }
+
+  // -------------------------------------------------------------------
+  void CallBackManager::unregisterCallBackMove(CBFunc_move CB_move, 
+                                               void* userData_move)
+  {
+    CBStructureMove cbm;
+    cbm.function = CB_move;
+    cbm.data = userData_move;
+    CBMove.remove(cbm);
+  }
+
+  // -------------------------------------------------------------------
+  void CallBackManager::callCallBacks(pPList before, pPList after,
+                                      operationType type , pEntity ppp)
+  {
+    list<CBStructure>::const_iterator cbIter = CB.begin();
+    list<CBStructure>::const_iterator cbLast = CB.end();
+
+    for (; cbIter != cbLast; cbIter++) {
+      CBFunction f = (*cbIter).function;
+      void * userData = (*cbIter).data;
+      f(before,after,userData,type,ppp);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void CallBackManager::callCallBackMoves(pVertex pv, double * xyz)
+  {
+    list<CBStructureMove>::const_iterator cbIterM = CBMove.begin();
+    list<CBStructureMove>::const_iterator cbLastM = CBMove.end();
+
+    for (; cbIterM != cbLastM; cbIterM++) {
+      CBFunc_move fM = (*cbIterM).function;
+      void * userDataM = (*cbIterM).data;
+      fM(pv,xyz,userDataM);
+    }
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/utils/CallBackManager.h b/Adapt/utils/CallBackManager.h
new file mode 100644
index 0000000..2adb42a
--- /dev/null
+++ b/Adapt/utils/CallBackManager.h
@@ -0,0 +1,89 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_CALLBACKMANAGER
+#define _H_CALLBACKMANAGER
+
+#include "MAdOperatorBase.h"
+
+#include "MAdSingleton.h"
+
+#include "MSops.h"
+#include <list>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  // callback functions
+  typedef void (*CBFunction)(pPList, pPList, 
+                             void *, operationType, pEntity);
+  typedef void (*CBFunc_move)(pVertex, double *, void *);
+
+  // -------------------------------------------------------------------
+  struct CBStructure {
+
+    CBFunction function;
+    void* data;
+
+    bool operator== (CBStructure cb) const {
+      if ( function==cb.function && data==cb.data) return true;
+      return false;
+    }
+  };
+
+  // -------------------------------------------------------------------
+  struct CBStructureMove {
+    CBFunc_move function;
+    void* data;
+
+    bool operator== (CBStructureMove cbm) const {
+      if ( function==cbm.function && data==cbm.data) return true;
+      return false;
+    }
+  };
+
+  // -------------------------------------------------------------------
+  class CallBackManager {
+
+  public:
+  
+    CallBackManager() {};
+    ~CallBackManager() {};
+  
+    void initialize();
+    void finalize();
+
+    void registerCallBack(CBFunction CB, void* userData);
+    void registerCallBackMove(CBFunc_move CB_move, void* userData_move);
+
+    void unregisterCallBack(CBFunction CB, void* userData);
+    void unregisterCallBackMove(CBFunc_move CB_move, void* userData_move);
+
+    void callCallBacks(pPList before, pPList after,
+                       operationType type , pEntity ppp);
+    void callCallBackMoves(pVertex, double *);
+  
+  private:
+
+    std::list<CBStructure> CB;
+    std::list<CBStructureMove> CBMove;
+
+  };
+
+  // -------------------------------------------------------------------
+
+  typedef MAdSingleton<CallBackManager> CallBackManagerSgl;
+
+}
+
+#endif
diff --git a/Adapt/utils/DistanceFunction.cc b/Adapt/utils/DistanceFunction.cc
new file mode 100644
index 0000000..16b5f65
--- /dev/null
+++ b/Adapt/utils/DistanceFunction.cc
@@ -0,0 +1,1193 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "DistanceFunction.h"
+#include "MAdOutput.h"
+#include "CallBackManager.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  void DistFct_CBMoveFct(pVertex pv, double * target, void * data)
+  {
+    // When a vertex is moved, the distance is cleared because it
+    // can be recalculated on-the-fly when needed.
+    // The gradients and curvatures are not cleared because they 
+    // can be needed elsewhere and cannot be recalculated on-the-fly.
+
+    distanceFunction * dFct = (distanceFunction *) data;
+    dFct->clearDistance(pv);
+  }
+
+  // -------------------------------------------------------------------
+  void DistFct_CBFct(pPList before, pPList after, void * data,
+                     operationType type , pEntity ppp)
+  {
+    distanceFunction * dFct = (distanceFunction *) data;
+    
+    switch (type) {
+    case MAd_ESPLIT: {
+      // In the edge split case, we have to interpolate the data at the new node
+
+      double grads[2][3], curv[2];
+          
+      // find the old edge
+      void * tmp = 0;
+      pEdge pe = (pEdge)PList_next(before,&tmp);
+      double t = E_linearParams(pe,(pVertex)ppp);
+
+      // interpolate distance gradient
+      if ( dFct->getGradient( E_vertex((pEdge)pe, 0), grads[0] ) &&
+           dFct->getGradient( E_vertex((pEdge)pe, 1), grads[1] )   )
+        {
+          double * newGrad = new double[3];
+          for (int i=0; i<3; i++) newGrad[i] = (1.-t) * grads[0][i] + t * grads[1][i];
+
+          // attach it
+          dFct->attachGradient((pVertex)ppp, newGrad);
+        }
+
+      // interpolate curvature
+      if ( dFct->getCurvature( E_vertex((pEdge)pe, 0), &(curv[0]) ) &&
+           dFct->getCurvature( E_vertex((pEdge)pe, 1), &(curv[1]) )    )
+        {
+          double newCurv = (1.-t) * curv[0] + t * curv[1];
+          dFct->attachCurvature((pVertex)ppp, newCurv);
+        }
+
+      break;
+    } 
+    case MAd_ECOLLAPSE: {
+      // In the edge collapse case, we have to delete the datas attached to the deleted node
+      dFct->clearVertexData((pVertex)ppp);
+      break;
+    }
+    case MAd_ESWAP:
+    case MAd_FSWAP: {
+      // nothing to be done (no modification at nodes)
+      break;
+    }
+    case MAd_RREMOVE: {
+      void * temp = NULL;
+      while ( pEntity pE = PList_next(before,&temp) ) {
+        if ( EN_type(pE) == 0 ) {
+          dFct->clearVertexData((pVertex)pE);
+        }
+      }
+      break;
+    }
+    case MAd_UNKNOWNOPERATION:
+    case MAd_VERTEXMOVE:
+    case MAd_FCOLLAPSE:
+    case MAd_DESPLTCLPS:
+    default: {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Not implemented for mesh modification %d", type);
+    }
+    }
+  }
+
+  // -------------------------------------------------------------------
+  distanceFunction::distanceFunction(pMesh m, bool _distToEntities): 
+    mesh(m), distToEntities(_distToEntities), nVert(0), nEnt(0), 
+    nVE(-1), xyzV(NULL), entToV(NULL)
+  {
+    distId = MD_newMeshDataId();
+    vGradId = MD_newMeshDataId();
+    rGradId = MD_newMeshDataId();
+    vCurvId = MD_newMeshDataId();
+
+    kdSearch = new SearchTool();
+
+    CallBackManagerSgl::instance().registerCallBackMove(DistFct_CBMoveFct,this);
+    CallBackManagerSgl::instance().registerCallBack(DistFct_CBFct,this);
+  }
+
+  // -------------------------------------------------------------------
+  distanceFunction::~distanceFunction()
+  {
+    clearDistances();
+    MD_deleteMeshDataId(distId);
+
+    clearGradientAtVertices();
+    MD_deleteMeshDataId(vGradId);
+
+    clearGradientInElements();
+    MD_deleteMeshDataId(rGradId);
+
+    clearCurvature();
+    MD_deleteMeshDataId(vCurvId);
+
+    if (xyzV) delete [] xyzV;
+    if (entToV) delete [] entToV;
+    if (kdSearch) delete kdSearch;
+
+    CallBackManagerSgl::instance().unregisterCallBackMove(DistFct_CBMoveFct,this);
+    CallBackManagerSgl::instance().unregisterCallBack(DistFct_CBFct,this);
+  }
+  
+  // -------------------------------------------------------------------
+  void distanceFunction::computeTree(const std::set<pVertex>& verts, 
+                                     const std::set<pEntity>& ents)
+  {
+    // Build search tree and vertices coordinates
+
+    kdSearch->reset();
+
+    nVert = verts.size();
+    kdSearch->allocatePoints(nVert);
+
+    if ( xyzV ) delete [] xyzV;
+    xyzV = new double[3*nVert];
+
+    pvToSearchId.clear();
+    vToEnt.clear();
+
+    std::set<pVertex> :: const_iterator itV    = verts.begin();
+    std::set<pVertex> :: const_iterator itVEnd = verts.end();
+    int k = 0;
+    for ( ; itV != itVEnd ; ++itV)
+      {
+        double coord[3]; V_coord(*itV,coord);
+        kdSearch->addPoint(k,coord);
+
+        pvToSearchId[*itV] = k;
+        for (int i=0; i<3; i++) xyzV[k*3+i] = coord[i];
+
+        k++;
+      }
+
+    kdSearch->allocateTree(nVert);
+
+    // Build wall entities topology
+
+    if ( distToEntities ) {
+      nEnt = ents.size();
+      if ( nEnt > 0 )
+        {
+          // allocate entities
+          nVE = EN_numVertices(*(ents.begin()));
+          if ( nVE > 3 ) {
+            MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                        "Distance to entities with more than 3 vertices not implemented");
+          }
+          if (entToV) delete [] entToV;
+          entToV = new int[nVE*nEnt];
+
+          // fill it
+          int m = 0;
+          std::set<pEntity>::const_iterator itE = ents.begin();
+          for (; itE != ents.end(); itE++) {
+            pPList eVerts = EN_vertices(*itE);
+            for (int i=0; i<nVE; i++) {
+              int vId = pvToSearchId[(pVertex)PList_item(eVerts,i)];
+              entToV[nVE*m+i] = vId;
+              vToEnt.insert(std::make_pair(vId,m));
+            }
+            PList_delete(eVerts);
+
+            // ensure faces normals are outgoing
+            if ( EN_type(*itE) == 2 && M_dim(mesh) == 3 ) {
+              if ( F_numRegions((pFace)*itE) != 1 ) {
+                MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+                                              "Faces with %d region(s), normals will not be outgoing",
+                                              F_numRegions((pFace)*itE));
+              }
+              else {
+                pRegion pr = F_region((pFace)*itE,0);
+                if ( R_dirUsingFace(pr,(pFace)*itE) != 1 ) {
+                  int tmp = entToV[nVE*m+1];
+                  entToV[nVE*m+1] = entToV[nVE*m+2];
+                  entToV[nVE*m+2] = tmp;
+                }
+              }
+            }
+
+            m++;
+          }
+        }
+      else {
+        if (entToV) delete [] entToV;
+        entToV = NULL;
+      }
+    }
+
+    // Clear everything else
+
+    clearDistances();
+    clearGradientAtVertices();
+    clearGradientInElements();
+    clearCurvature();
+  }
+  
+  // -------------------------------------------------------------------
+  void distanceFunction::computeAllDistances() const
+  {
+    pVertex pv;
+    VIter vit = M_vertexIter(mesh);
+    while ( ( pv = VIter_next(vit) ) )
+      {
+        computeDistance(pv);
+      }
+    VIter_delete(vit);
+  }
+
+  // -------------------------------------------------------------------
+  double distanceFunction::getDistance(const pVertex pv) const
+  {
+    double dist;
+    if ( EN_getDataDbl((pEntity)pv,distId,&dist) ) return dist;
+    return computeDistance(pv);
+  }
+
+  // -------------------------------------------------------------------
+  double distanceFunction::computeDistance(const pVertex pv) const
+  {
+    double xyz[3]; V_coord(pv,xyz);
+    double dist = computeDistance(xyz);
+    EN_attachDataDbl((pEntity)pv,distId,dist);
+    return dist;
+  }
+
+  // -------------------------------------------------------------------
+  double distanceFunction::computeDistance(const double xyz[3]) const
+  {
+    return sqrt(computeDistSq(xyz));
+  }
+
+  // -------------------------------------------------------------------
+  double distanceFunction::computeDistSq(const double xyz[3]) const
+  {
+    if ( !distToEntities || nEnt == 0 ) return kdSearch->computeDistanceSq(xyz);
+
+    double minD = MAdBIG;
+
+    // --- compute distance to every entity and take minimum ---
+
+    double xyzE[3][3]; // 1 line = coordinates of 1 vertex
+    double vec[3];
+
+    //GC note: could be improved
+
+    // --- compute distance to entities neighboring closest point and take minimum ---
+    int closestId;
+    kdSearch->computeDistanceSq(xyz, &closestId);
+    std::multimap<int,int>::const_iterator bfIt = vToEnt.find(closestId);
+    assert ( bfIt != vToEnt.end() );
+    while ( bfIt != vToEnt.end() && bfIt->first == closestId )
+      {
+        int iE = (*bfIt).second;
+//     for (int iE=0; iE<nEnt; iE++)
+//       {
+        double dist;
+
+        for(int iV=0; iV<nVE; iV++) {
+          for(int iC=0; iC<3; iC++) xyzE[iV][iC] = xyzV[entToV[iE*nVE+iV]*3+iC];
+        }
+
+        if ( nVE == 3 ) {
+          dist = distToTriangleSq(xyzE,xyz,vec);
+        }
+        else {
+          MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                      "Distance to a set of edge not implemented yet");
+        }
+
+        minD = std::min(minD,dist);
+
+        bfIt++;
+      }
+        
+    return minD;
+  }
+
+  // -------------------------------------------------------------------
+  void distanceFunction::computeAllDistAndGrad() const
+  {
+    double testVec[3];
+    double xyzE[3][3]; // 1 line = coordinates of 1 vertex
+    pVertex pv;
+    VIter vit = M_vertexIter(mesh);
+    while ( ( pv = VIter_next(vit) ) )
+      {
+        double dist;
+        double * grad = new double[3];
+
+        double xyz[3];
+        V_coord(pv,xyz);
+
+        if ( !distToEntities || nEnt == 0 )
+          {
+            int closestId;
+            kdSearch->computeDistanceSq(xyz, &closestId);
+            double xyzW[3];
+            for (int iC=0; iC<3; iC++) xyzW[iC] = xyzV[3*closestId+iC];
+            diffVec(xyz,xyzW,grad);
+            dist = sqrt( dotProd(grad,grad) );
+            if ( dist <= MAdTOL ) {
+              MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+                                            "Zero vector found for a distance gradient");
+            }
+            else {
+              normalizeVec(grad,grad);
+            }
+          }
+        else
+          {
+            double minD = MAdBIG;
+
+            //GC note: could be improved
+
+            // --- compute distance to entities neighboring closest point and take minimum ---
+            int closestId;
+            kdSearch->computeDistanceSq(xyz, &closestId);
+            std::multimap<int,int>::const_iterator bfIt = vToEnt.find(closestId);
+            assert ( bfIt != vToEnt.end() );
+            while ( bfIt != vToEnt.end() && bfIt->first == closestId )
+              {
+                int iE = (*bfIt).second;
+                //             // --- compute distance to every entity and take minimum ---
+                //         for (int iE=0; iE<nEnt; iE++)
+                //           {
+                double distSq;
+
+                for(int iV=0; iV<nVE; iV++) {
+                  for(int iC=0; iC<3; iC++) xyzE[iV][iC] = xyzV[entToV[iE*nVE+iV]*3+iC];
+                }
+            
+                if ( nVE == 3 ) {
+                  distSq = distToTriangleSq(xyzE,xyz,testVec);
+                }
+                else {
+                  MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                              "Distance to a set of edge not implemented yet");
+                }
+            
+                if ( distSq < minD ) {
+                  minD = distSq;
+                  for (int i=0; i<3; i++) grad[i] = testVec[i];
+                }
+                minD = std::min(minD,distSq);
+
+                bfIt++;
+              }
+
+            dist = sqrt(minD);
+
+            // if the point is lying on the iso-zero, take the mean of the 
+            // normals of the neighboring elements. The normals are supposed 
+            // to be outgoing.
+            if ( minD < MAdTOL ) 
+              { 
+                if (nVE != 3) throw;
+                grad[0] = 0.; grad[1] = 0.; grad[2] = 0.;
+                int locId = pvToSearchId.find(pv)->second;
+                std::multimap<int,int>::const_iterator bfIt = vToEnt.find(locId);
+                assert ( bfIt != vToEnt.end() );
+                while ( bfIt != vToEnt.end() && bfIt->first == locId )
+                  {
+                    int entId = bfIt->second;
+                    for(int iV=0; iV<nVE; iV++) {
+                      for(int iC=0; iC<3; iC++) xyzE[iV][iC] = xyzV[entToV[entId*nVE+iV]*3+iC];
+                    }
+                
+                    double nor[3];
+                    XYZ_F_normal(xyzE,nor);
+                    normalizeVec(nor,nor);
+                
+                    // give more weight to the closest information
+                    double cen[3], xyzToC[3];
+                    meanRow33(xyzE,cen);
+                    diffVec(cen,xyz,xyzToC);
+                    double invDistToCenSq = 1. / dotProd(xyzToC,xyzToC);
+                
+                    for (int i=0; i<3; i++) grad[i] -= nor[i] * invDistToCenSq;
+                
+                    bfIt++;
+                  }
+            
+                normalizeVec(grad,grad);
+              }
+            else
+              {
+                double invD = 1./dist;
+                for (int i=0; i<3; i++) grad[i] *= invD;
+              }
+          }
+// #warning "hacked gradients"
+//         for (int i=0; i<3; i++) grad[i] = xyz[i];
+//         normalizeVec(grad,grad);
+
+        EN_attachDataDbl((pEntity)pv,distId,dist);
+        void * del;
+        if ( EN_getDataPtr((pEntity)pv,vGradId,&del) && del ) delete [] (double*)del;
+        EN_attachDataPtr((pEntity)pv,vGradId,grad);
+      }
+    VIter_delete(vit);
+  }
+
+  // -------------------------------------------------------------------
+  void distanceFunction::clearDistance(const pVertex pv) const
+  {
+    EN_deleteData((pEntity)pv,distId);
+  }
+
+  // -------------------------------------------------------------------
+  void distanceFunction::clearDistances() const
+  {
+    pVertex pv;
+    VIter vit = M_vertexIter(mesh);
+    while ( ( pv = VIter_next(vit) ) )
+      {
+        EN_deleteData((pEntity)pv,distId);
+      }
+    VIter_delete(vit);
+  }
+
+  // -------------------------------------------------------------------
+  void distanceFunction::computeGradientInElements() const
+  {
+    double gsf[4][3] = {
+      {-1., -1., -1.}, 
+      { 1.,  0.,  0.}, 
+      { 0.,  1.,  0.}, 
+      { 0.,  0.,  1.}, 
+    };
+
+    pRegion pr;
+    RIter rit = M_regionIter(mesh);
+    while ( ( pr = RIter_next(rit) ) )
+      {
+        pPList rVerts = R_vertices(pr);
+        double dist[4];
+        void * temp = NULL;
+        pVertex pv;
+        int i = 0;
+        while ( ( pv = (pVertex)PList_next(rVerts,&temp) ) )
+          {
+            dist[i] = getDistance(pv);
+            i++;
+          }
+        PList_delete(rVerts);
+
+        double ijac[3][3], detj;
+        detj = R_invJacobian(pr,ijac);
+
+        void * del;
+        if ( EN_getDataPtr((pEntity)pr,rGradId,&del) && del ) delete [] (double*)del;
+        double * grad = new double[3];
+        for ( int iC=0; iC<3; iC++)
+          {
+            grad[iC] = 0.;
+            for (int iSF=0; iSF<4; iSF++) {
+              grad[iC] += dist[iSF] * ( gsf[iSF][0] * ijac[0][iC] +
+                                        gsf[iSF][1] * ijac[1][iC] +
+                                        gsf[iSF][2] * ijac[2][iC]   );
+            }
+          }
+
+        EN_attachDataPtr((pEntity)pr,rGradId,grad);
+      }
+    RIter_delete(rit);
+  }
+
+  // -------------------------------------------------------------------
+  void distanceFunction::clearGradientInElements() const
+  {
+    pRegion pr;
+    RIter rit = M_regionIter(mesh);
+    while ( ( pr = RIter_next(rit) ) )
+      {
+        EN_deleteData((pEntity)pr,rGradId);
+      }
+    RIter_delete(rit);
+  }
+
+  // -------------------------------------------------------------------
+  void distanceFunction::computeGradientAtVertices()
+  {
+    computeGradientInElements();
+
+    pVertex pv;
+    VIter vit = M_vertexIter(mesh);
+    while ( ( pv = VIter_next(vit) ) )
+      {
+        void * del;
+        if ( EN_getDataPtr((pEntity)pv,vGradId,&del) && del ) delete [] (double*)del;
+        double * grad = new double[3];
+        for (int i=0; i<3; i++) grad[i] = 0.;
+
+        pPList vRegs = V_regions(pv);
+        void * temp = NULL;
+        void * rGrad = NULL;
+        pRegion pr;
+        while ( pr = (pRegion)PList_next(vRegs,&temp) )
+          {
+            if ( !EN_getDataPtr((pEntity)pr,rGradId,&rGrad) ) throw;
+            grad[0] += ((double*)rGrad)[0];
+            grad[1] += ((double*)rGrad)[1];
+            grad[2] += ((double*)rGrad)[2];
+          }
+
+        int nRegs = PList_size(vRegs);
+        PList_delete(vRegs);
+        double invNRegs = 1. / (double)nRegs;
+        for (int i=0; i<3; i++) grad[i] *= invNRegs;
+        
+        EN_attachDataPtr((pEntity)pv,vGradId,grad);
+      }
+    VIter_delete(vit);
+
+    clearGradientInElements();
+  }
+
+  // -------------------------------------------------------------------
+  void distanceFunction::clearGradientAtVertices()
+  {
+    pVertex pv;
+    void *tmp;
+    VIter vit = M_vertexIter(mesh);
+    while ( ( pv = VIter_next(vit) ) )
+      {
+        if ( EN_getDataPtr((pEntity)pv,vGradId, &tmp) ) {
+          EN_deleteData((pEntity)pv,vGradId);
+        }
+      }
+    VIter_delete(vit);
+  }
+
+  // -------------------------------------------------------------------
+  bool distanceFunction::getGradient(const pVertex pv, double grad[3]) const
+  {
+    void * tmp;
+    if ( !EN_getDataPtr((pEntity)pv,vGradId,&tmp) ) return false;
+    for (int i=0; i<3; i++) grad[i] = ((double*) tmp)[i];
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool distanceFunction::getCurvatureOnEntity(const pEntity entity, 
+                                              const double xyz[3],
+                                              double *curv) const
+  {
+    int type = EN_type(entity);
+    switch(type) {
+    case 0: return getCurvature((pVertex)entity,curv);
+    case 1: {
+      double u = E_linearParams((pEdge)entity,xyz);
+      double c[2];
+      if ( !getCurvature(E_vertex((pEdge)entity,0), &(c[0])) ||
+           !getCurvature(E_vertex((pEdge)entity,1), &(c[1])) ) return false;
+      *curv = (1.-u) * c[0] + u * c[1];
+      return true;
+    }
+    case 2: {
+      double u[2];
+      F_linearParams((pFace)entity,xyz,u);
+      double c[3];
+      if ( !getCurvature(F_vertex((pFace)entity,0), &(c[0])) ||
+           !getCurvature(F_vertex((pFace)entity,1), &(c[1])) ||
+           !getCurvature(F_vertex((pFace)entity,2), &(c[2])) ) return false;
+  
+      *curv = (1.-u[0]-u[1]) * c[0] + u[0] * c[1] + u[1] * c[2];
+      return true;
+    }
+    case 3: {
+      double u[3];
+      R_linearParams((pRegion)entity, xyz, u);
+      double c[4];
+      if ( !getCurvature(R_vertex((pRegion)entity,0), &(c[0])) ||
+           !getCurvature(R_vertex((pRegion)entity,1), &(c[1])) ||
+           !getCurvature(R_vertex((pRegion)entity,2), &(c[2])) ||
+           !getCurvature(R_vertex((pRegion)entity,3), &(c[3])) ) return false;
+  
+      *curv = (1.-u[0]-u[1]-u[2]) * c[0] + u[0] * c[1] + u[1] * c[2] + u[2] * c[3];
+      return true;
+    }
+    default: throw;
+    }
+  }
+
+  // -------------------------------------------------------------------
+  bool distanceFunction::getGradientOnEntity(const pEntity entity, 
+                                             const double xyz[3],
+                                             double grad[3]) const
+  {
+    int type = EN_type(entity);
+    switch(type) {
+    case 0: return getGradient((pVertex)entity,grad);
+    case 1: return getGradientOnEdge((pEdge)entity,xyz,grad);
+    case 2: return getGradientOnFace((pFace)entity,xyz,grad);
+    case 3: return getGradientOnRegion((pRegion)entity,xyz,grad);
+    default: throw;
+    }
+  }
+
+  // -------------------------------------------------------------------
+  bool distanceFunction::getGradientOnEdge(const pEdge edge, 
+                                           const double xyz[3],
+                                           double grad[3]) const
+  {
+    double u = E_linearParams(edge,xyz);
+    return getGradientOnEdgeParam(edge,u,grad);
+  }
+
+  // -------------------------------------------------------------------
+  bool distanceFunction::getGradientOnEdgeParam(const pEdge pE, 
+                                                const double u,
+                                                double grad[3]) const
+  {
+    double g0[3], g1[3];
+    if ( !getGradient(E_vertex(pE,0), g0) ||
+         !getGradient(E_vertex(pE,1), g1) ) return false;
+  
+    for (int i=0; i<3; i++) grad[i] = (1.-u) * g0[i] + u * g1[i];
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool distanceFunction::getGradientOnFace(const pFace face, 
+                                           const double xyz[3],
+                                           double grad[3]) const
+  {
+    double u[2];
+    F_linearParams(face,xyz,u);
+    return getGradientOnFaceParam(face,u,grad);
+  }
+
+  // -------------------------------------------------------------------
+  bool distanceFunction::getGradientOnFaceParam(const pFace face, 
+                                                const double u[2],
+                                                double grad[3]) const
+  {
+    double g0[3], g1[3], g2[3];
+    if ( !getGradient(F_vertex(face,0), g0) ||
+         !getGradient(F_vertex(face,1), g1) ||
+         !getGradient(F_vertex(face,2), g2) ) return false;
+  
+    for (int i=0; i<3; i++) grad[i] = (1.-u[0]-u[1]) * g0[i] + u[0] * g1[i] + u[1] * g2[i];
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  bool distanceFunction::getGradientOnRegion(const pRegion region, 
+                                             const double xyz[3],
+                                             double grad[3]) const
+  {
+    double u[3];
+    R_linearParams(region, xyz, u);
+    return getGradientOnRegionParam(region, u, grad);
+  }
+
+  // -------------------------------------------------------------------
+  bool distanceFunction::getGradientOnRegionParam(const pRegion region, 
+                                                  const double u[3],
+                                                  double grad[3]) const
+  {
+    double g0[3], g1[3], g2[3], g3[3];
+    if ( !getGradient(R_vertex(region,0), g0) ||
+         !getGradient(R_vertex(region,1), g1) ||
+         !getGradient(R_vertex(region,2), g2) ||
+         !getGradient(R_vertex(region,3), g3) ) return false;
+  
+    for (int i=0; i<3; i++) {
+      grad[i] = (1.-u[0]-u[1]-u[2]) * g0[i] + u[0] * g1[i] + u[1] * g2[i] + u[2] * g3[i];
+    }
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  void distanceFunction::attachGradient(pVertex pv, double grad[3]) const
+  {
+    EN_attachDataPtr((pEntity)pv,vGradId,grad);
+  }
+
+  // -------------------------------------------------------------------
+  void distanceFunction::outputDistance(const char * fn) const
+  {
+    MAdAttachedNodalDataOutput(mesh, fn, distId);
+  }
+
+  // -------------------------------------------------------------------
+  void distanceFunction::outputGradAtVertices(const char * fn) const
+  {
+    MAdAttachedNodalDataVecOutput(mesh, fn, vGradId);
+  }
+
+  // -------------------------------------------------------------------
+  void distanceFunction::clearVertexData(pVertex pv) const
+  {
+    EN_deleteData((pEntity)pv, vGradId);
+    EN_deleteData((pEntity)pv, distId);
+    EN_deleteData((pEntity)pv, vCurvId);
+  }
+
+  // -------------------------------------------------------------------
+  void distanceFunction::computeCurvature(const std::set<pRegion>& regs)
+  {
+    int nR = regs.size();      // number of regions involved
+    int r2v[nR*4];             // regions vertices
+    std::map<pFace,pRegion> bFaces;  // boundary faces (to 'regs') and 
+    //                                  the corresponding region
+    std::map<pVertex,int> v2i; // vertex pointers to local ids
+
+    // --- fill v2i and r2v ---
+
+    pVertex pv;
+    pRegion pr;
+    pFace pf;
+    std::map<pVertex,int>::iterator v2iIt;
+    int vId=0, rId=0;
+    std::set<pRegion>::const_iterator rIt = regs.begin();
+    for (; rIt != regs.end(); rIt++) {
+      // vertices
+      for (int i=0; i<4; i++) {
+        pv = R_vertex(*rIt,i);
+        v2iIt = v2i.find(pv);
+        if ( v2iIt == v2i.end() ) {
+          v2i[pv] = vId;
+          r2v[rId*4+i] = vId;
+          vId++;
+        }
+        else {
+          r2v[rId*4+i] = (*v2iIt).second;
+        }
+      }
+      // boundary faces
+      for (int i=0; i<4; i++) {
+        pf = R_face(*rIt,i);
+        pr = F_otherRegion(pf,*rIt);
+        if ( !pr || regs.find( pr ) == regs.end() ) {
+          bFaces[pf] = *rIt;
+        }
+      }
+      rId++;
+    }
+
+    // --- make the reverse mapping of v2i: i2v ---
+
+    int nV = v2i.size();   // number of vertices involved
+    pVertex i2v[nV];       // local ids to vertex pointers
+
+    std::map<pVertex,int>::const_iterator v2iIter = v2i.begin();
+    for(; v2iIter != v2i.end(); v2iIter++) i2v[v2iIter->second] = v2iIter->first;
+    
+    // --- compute right hand side and mass matrix ---
+    
+    double dPhidXi[4][3] = {
+      {-1., -1., -1.}, {1., 0., 0.}, {0., 1., 0.}, {0., 0., 1.}
+    };
+
+    double over12 = 1./12.;
+    double over24 = 1./24.;
+
+    double rhs[nV], MLump[nV];
+    for (int i=0; i<nV; i++) {
+      rhs[i] = 0.;
+      MLump[i] = 0.;
+    }
+
+    void * tmpP;
+    double vGrad[4][3];
+    double ijac[3][3], detJ, dPhiDx[4][3];
+    int iR = 0;
+    for ( rIt = regs.begin(); rIt != regs.end(); rIt++ )
+      {
+        // get inverse Jacobian and determinant
+        detJ = R_invJacobian(*rIt,ijac);
+
+        // --- shape functions gradients and distance gradients ---
+        for (int iSF=0; iSF<4; iSF++)
+          {
+            int iId = r2v[iR*4+iSF];
+            assert ( EN_getDataPtr( (pEntity) ( i2v[iId] ), vGradId, &tmpP) );
+            for ( int iC=0; iC<3; iC++) {
+              dPhiDx[iSF][iC] = ( dPhidXi[iSF][0] * ijac[0][iC] +
+                                  dPhidXi[iSF][1] * ijac[1][iC] +
+                                  dPhidXi[iSF][2] * ijac[2][iC]   );
+              vGrad[iSF][iC] = ((double*)tmpP)[iC];
+            }
+          }
+
+        // --- rhs and mass matrix ---
+        int iId, jSF;
+        for (int iSF=0; iSF<4; iSF++) {
+          iId = r2v[iR*4+iSF];
+          for (jSF=0; jSF<4; jSF++) {
+            rhs[iId] -= over24 * detJ * dotProd( dPhiDx[iSF], vGrad[jSF] );
+          }
+          MLump[iId] += over24 * detJ;
+        }
+
+        // --- boundary term ---
+        
+        double nor[3], term, detJ;
+        pPList fVerts;
+        for (int iF=0; iF<4; iF++ )
+          {
+            pf = R_face(*rIt, iF);
+            if ( bFaces.find(pf) != bFaces.end() )
+              {
+                // we will need the outgoing normal...
+                //  ... and the ordered vertices ...
+                F_normal(pf,nor);
+                normalizeVec(nor,nor);
+                if ( R_dirUsingFace(*rIt,pf) ) fVerts = F_vertices(pf, 1);
+                else {
+                  fVerts = F_vertices(pf, 0);
+                  for(int i=0; i<3; i++) nor[i] = -1.*nor[i];
+                }
+                
+                // ... the jacobian of the face ...
+                detJ = 2. * F_area(pf);
+                
+                // ... the gradient of distance at vertices.
+                for (int iVF=0; iVF<3; iVF++) {
+                  pv = (pVertex)PList_item(fVerts,iVF);
+                  EN_getDataPtr( (pEntity)pv, vGradId, &tmpP);
+                  for(int i=0; i<3; i++) vGrad[iVF][i] = ((double*)tmpP)[i];
+                }
+
+                // compute the term
+                for (int iVF=0; iVF<3; iVF++) {
+                  pv = (pVertex)PList_item(fVerts,iVF);
+                  int iId = v2i.find(pv)->second;
+                  for (int jVF=0; jVF<3; jVF++) {
+                    if ( iVF == jVF ) {
+                      rhs[iId] += over12 * detJ * dotProd( nor, vGrad[jVF] );
+                    }
+                    else {
+                      rhs[iId] += over24 * detJ * dotProd( nor, vGrad[jVF] );
+                    }
+                  }
+                }
+                PList_delete(fVerts);
+              }
+          }
+
+        iR++;
+      }
+    
+
+    // --- solve the system to find curvatures ---
+    for (int iV=0; iV<nV; iV++)
+      {
+        EN_attachDataDbl((pEntity)(i2v[iV]),vCurvId, fabs( rhs[iV] / MLump[iV] ));
+      }
+  }
+
+  // -------------------------------------------------------------------
+  void distanceFunction::computeGradientAndCurvature(const std::set<pRegion>& regs)
+  {
+    int nR = regs.size();      // number of regions involved
+    int r2v[nR*4];             // regions vertices
+    std::map<pFace,pRegion> bFaces;  // boundary faces (to 'regs') and 
+    //                                  the corresponding region
+    std::map<pVertex,int> v2i; // vertex pointers to local ids
+
+    // --- fill v2i and r2v ---
+
+    pVertex pv;
+    pRegion pr;
+    pFace pf;
+    std::map<pVertex,int>::iterator v2iIt;
+    int vId=0, rId=0;
+    std::set<pRegion>::const_iterator rIt = regs.begin();
+    for (; rIt != regs.end(); rIt++) {
+      // vertices
+      for (int i=0; i<4; i++) {
+        pv = R_vertex(*rIt,i);
+        v2iIt = v2i.find(pv);
+        if ( v2iIt == v2i.end() ) {
+          v2i[pv] = vId;
+          r2v[rId*4+i] = vId;
+          vId++;
+        }
+        else {
+          r2v[rId*4+i] = (*v2iIt).second;
+        }
+      }
+      // boundary faces
+      for (int i=0; i<4; i++) {
+        pf = R_face(*rIt,i);
+        pr = F_otherRegion(pf,*rIt);
+        if ( !pr || regs.find( pr ) == regs.end() ) {
+          bFaces[pf] = *rIt;
+        }
+      }
+      rId++;
+    }
+
+    // --- make the reverse mapping of v2i: i2v ---
+
+    int nV = v2i.size();   // number of vertices involved
+    pVertex i2v[nV];       // local ids to vertex pointers
+
+    std::map<pVertex,int>::const_iterator v2iIter = v2i.begin();
+    for(; v2iIter != v2i.end(); v2iIter++) i2v[v2iIter->second] = v2iIter->first;
+    
+    // --- compute right hand side and mass matrix ---
+    
+    double dPhidXi[4][3] = {
+      {-1., -1., -1.}, {1., 0., 0.}, {0., 1., 0.}, {0., 0., 1.}
+    };
+
+    double sixth      = 1./6.;
+    double oneOver60  = 1./60.;
+    double oneOver120 = 1./120.;
+
+    double rhs[nV], MLump[nV];
+    double vGrad[nV*3];  // distance gradients computed on the vertices
+    int v_nR[nV];        // number of involved regions around vertices
+    for (int i=0; i<nV; i++) {
+      rhs[i] = 0.;
+      MLump[i] = 0.;
+      v_nR[i] = 0;
+      for (int j=0; j<3; j++) vGrad[3*i+j] = 0.;
+    }
+
+
+    double dist[4], ijac[3][3], detJ, dPhiDx[4][3];
+    double rGrad[3];
+    int iR = 0;
+    for ( rIt = regs.begin(); rIt != regs.end(); rIt++ )
+      {
+        // get distances
+        for (int iV = 0; iV<4; iV++) dist[iV] = getDistance(R_vertex(*rIt,iV));
+        
+        // get inverse Jacobian and determinant
+        detJ = R_invJacobian(*rIt,ijac);
+
+        // --- gradients ---
+        rGrad[0] = 0.; rGrad[1] = 0.; rGrad[2] = 0.;
+        for (int iSF=0; iSF<4; iSF++)
+          {
+            for ( int iC=0; iC<3; iC++) {
+              dPhiDx[iSF][iC] = ( dPhidXi[iSF][0] * ijac[0][iC] +
+                                  dPhidXi[iSF][1] * ijac[1][iC] +
+                                  dPhidXi[iSF][2] * ijac[2][iC]   );
+              rGrad[iC] += dist[iSF] * dPhiDx[iSF][iC];
+            }
+          }
+        normalizeVec(rGrad,rGrad);
+        for (int iSF=0; iSF<4; iSF++)
+          {
+            for ( int iC=0; iC<3; iC++) {
+              vGrad[( r2v[iR*4+iSF] )*3+iC] += rGrad[iC];
+            }
+            v_nR[ r2v[iR*4+iSF] ] ++;
+          }
+
+        // --- rhs and mass matrix ---
+        int iId, jId;
+        double detjO60  = detJ * oneOver60;
+        double detjO120 = detJ * oneOver120;
+        for (int iSF=0; iSF<4; iSF++) {
+          iId = r2v[iR*4+iSF];
+          rhs[iId] -= sixth * detJ * (dPhiDx[iSF][0] * rGrad[0] +
+                                      dPhiDx[iSF][1] * rGrad[1] +
+                                      dPhiDx[iSF][2] * rGrad[2]   );
+          
+          for (int j=0; j<4; j++) {
+            if ( iSF == j ) {
+              MLump[ iId ]  += detjO60;
+            }
+            else {
+              MLump[ iId ]  += detjO120;
+            }
+          }
+        }
+
+        // --- boundary term ---
+        
+        double nor[3], term;
+        for (int iF=0; iF<4; iF++ )
+          {
+            pf = R_face(*rIt, iF);
+            if ( bFaces.find(pf) != bFaces.end() )
+              {
+                // we will need the outgoing normal...
+                //  ... and the ordered vertices ...
+                F_normal(pf,nor);
+                normalizeVec(nor,nor);
+                pPList fVerts;
+                if ( R_dirUsingFace(*rIt,pf) ) fVerts = F_vertices(pf, 1);
+                else {
+                  fVerts = F_vertices(pf, 0);
+                  for(int i=0; i<3; i++) nor[i] = -1.*nor[i];
+                }
+                
+                // ... the jacobian of the face ...
+                double detJ = 2. * F_area(pf);
+
+                // compute the term
+// #warning "debug: analytical grad"
+//                 if ( nor[0] > 0.5 ) {
+//                   printVec(rGrad,"rGrad");
+//                   rGrad[0]=2;
+//                   rGrad[1]=0.; rGrad[2]=0.;
+//                 }
+//                 if ( nor[0] < -0.5 ) {
+//                   rGrad[0]=0;
+//                   rGrad[1]=0.; rGrad[2]=0.;
+//                 }
+//                 else {
+//                   rGrad[1]=0.; rGrad[2]=0.;
+//                 }
+
+                term = sixth * dotProd( nor, rGrad ) * detJ;
+                for (int iVF=0; iVF<3; iVF++) {
+                  rhs  [ v2i[(pVertex)PList_item(fVerts,iVF)] ] += term;
+                }
+              }
+          }
+
+        iR++;
+      }
+    
+//     fprintf (frg,"};\n");
+//     fclose (frg);
+// #warning "debug output rhs"
+//     FILE *f = fopen ("testrhs.pos", "w");
+//     fprintf (f,"View\" mesh \" {\n");
+//     iR = 0;
+//     for ( rIt = regs.begin(); rIt != regs.end(); rIt++ )
+//       {
+//         // get the coordinates
+//         double xyz[4][3];
+//         R_coordP1(*rIt, xyz);
+        
+//         // get the data at nodes
+//         double data[4];
+//         pPList verts = R_vertices(pr);
+//         void* tmp = 0;
+//         int i = 0;
+//         while ( pEntity pent = PList_next(verts,&tmp) ) {
+//           //          data[i] = rhs2(v2i[(pVertex)pent]);
+//           data[i] = rhs[r2v[iR*4+i]];
+//           i++;
+//         }
+//         PList_delete(verts);
+
+//         // write an element
+//         fprintf (f,"SS(%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g,%g};\n",
+//                  xyz[0][0],xyz[0][1],xyz[0][2],
+//                  xyz[1][0],xyz[1][1],xyz[1][2],
+//                  xyz[2][0],xyz[2][1],xyz[2][2],
+//                  xyz[3][0],xyz[3][1],xyz[3][2],
+//                  data[0],data[1],data[2],data[3]);
+
+//         iR++;
+//       }
+//     fprintf (f,"};\n");
+//     fclose (f);
+    
+
+    // --- solve the system to find curvatures ---
+    for (int iV=0; iV<nV; iV++)
+      {
+        EN_attachDataDbl((pEntity)(i2v[iV]),vCurvId, fabs( rhs[iV] / MLump[iV] ));
+      }
+
+    // --- compute gradients at vertices ---
+    int nbRV;
+    void * del;
+    for ( int iV=0; iV<nV; iV++ )
+      {
+        pv = i2v[iV];
+        if ( EN_getDataPtr((pEntity)pv,vGradId,&del) && del ) delete [] (double*)del;
+
+        double * grad = new double[3];
+        for (int iC=0; iC<3; iC++) grad[iC] = vGrad[iV*3+iC] / (double)(v_nR[iV]);
+        
+        EN_attachDataPtr((pEntity)pv,vGradId,grad);
+      }
+  }
+
+  // -------------------------------------------------------------------
+  // GC: to be improved
+  void distanceFunction::smoothCurvature(int nbSmoothings) const
+  {
+    pVertex pv, pv2;
+    double curv, weights, locCurv;
+    pPList vEdges;
+    pEdge edge;
+
+    for (int iS=0; iS < nbSmoothings; iS++)
+      {
+        VIter vit = M_vertexIter(mesh);
+        while ( ( pv = VIter_next(vit) ) )
+          {
+            if ( EN_getDataDbl((pEntity)pv,vCurvId,&locCurv ) ) 
+              {
+                weights = 0.;
+                curv = 0.;
+                vEdges = V_edges(pv);
+                void * tmp = NULL;
+                while ( ( edge = (pEdge)PList_next(vEdges,&tmp) ) ) {
+                  double tmpCurv;
+                  pv2 = E_otherVertex(edge,pv);
+                  if ( EN_getDataDbl((pEntity)pv2,vCurvId,&tmpCurv ) )
+                    {
+                      double invDistSq = 1. / E_length(edge);
+                      curv += tmpCurv * invDistSq;
+                      weights += invDistSq;
+                    }
+                }
+                
+                if ( weights < MAdTOL ) curv = locCurv;
+                else {
+                  curv /= weights;
+                  curv = 0.5 * ( curv + locCurv );
+                }
+                
+                EN_attachDataDbl((pEntity)pv,vCurvId, curv);
+              }
+          }
+        VIter_delete(vit);
+      }
+  }
+
+  // -------------------------------------------------------------------
+  bool distanceFunction::getCurvature(const pVertex pv, double *c) const
+  {
+    if ( EN_getDataDbl((pEntity)pv, vCurvId, c) ) return true;
+    return false;
+  }
+
+  // -------------------------------------------------------------------
+  void distanceFunction::attachCurvature(pVertex pv, double curv) const
+  {
+    EN_attachDataDbl((pEntity)pv,vCurvId,curv);
+  }
+
+  // -------------------------------------------------------------------
+  void distanceFunction::clearCurvature() const
+  {
+    pVertex pv;
+    VIter vit = M_vertexIter(mesh);
+    while ( ( pv = VIter_next(vit) ) )
+      {
+        EN_deleteData((pEntity)pv,vCurvId);
+      }
+    VIter_delete(vit);
+  }
+
+  // -------------------------------------------------------------------
+  void distanceFunction::outputCurvature(const char * fn) const
+  {
+    MAdAttachedNodalDataOutput(mesh, fn, vCurvId);
+  }
+
+  // -------------------------------------------------------------------
+}
diff --git a/Adapt/utils/DistanceFunction.h b/Adapt/utils/DistanceFunction.h
new file mode 100644
index 0000000..1e8b074
--- /dev/null
+++ b/Adapt/utils/DistanceFunction.h
@@ -0,0 +1,134 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_DISTANCEFUNCTION
+#define _H_DISTANCEFUNCTION
+
+#include "MeshDataBaseInterface.h"
+#include "DistanceToPoints.h"
+#include <set>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  // This class computes and stores:
+  //   - the distance to a set of vertices, edges or faces 
+  //     (as attached double),
+  //   - the gradient of the distance (as attached pointer),
+  //   - the Laplacian of the distance (as attached double).
+  //
+  // There are two ways to compute the distance: 
+  //   - to a set of vertices (inacurate to represent a wall)
+  //   - to a set of edges(2D)/faces(3D) (more accurate, more expensive)
+  // The choice is governed by the variable 'distToEntities'
+  // -------------------------------------------------------------------
+  class distanceFunction {
+
+  public:
+
+    distanceFunction(pMesh m, bool _distToEntities);
+    ~distanceFunction();
+
+    void computeTree(const std::set<pVertex>&, const std::set<pEntity>&);
+
+    void clearVertexData(pVertex pv) const;
+
+    // Distance
+
+    void   computeAllDistances() const;
+    double getDistance(const pVertex pv) const;
+    void   clearDistance(const pVertex pv) const;
+    void   clearDistances() const;
+
+    double computeDistance(const double xyz[3]) const;
+    double computeDistSq  (const double xyz[3]) const;
+
+    void outputDistance(const char * fn) const;
+
+    // Gradient of the distance
+
+    void computeAllDistAndGrad() const; // the most accurate for gradients
+
+    void computeGradientAtVertices(); // not accurate
+    void clearGradientAtVertices();
+    bool getGradient(const pVertex pv, double grad[3]) const;
+    bool getGradientOnEntity(const pEntity entity, 
+                             const double xyz[3],
+                             double grad[3]) const;
+    void attachGradient(pVertex pv, double grad[3]) const;
+
+    void outputGradAtVertices(const char * fn) const;
+
+    // Curvature ( Laplacian of the distance )
+
+    void computeGradientAndCurvature(const std::set<pRegion>& regs); // not accurate...
+
+    void computeCurvature(const std::set<pRegion>& regs);
+    void smoothCurvature(int nbSmoothings=1) const;
+    bool getCurvature(const pVertex pv, double *c) const;
+    bool getCurvatureOnEntity(const pEntity entity, 
+                              const double xyz[3],
+                              double *curv) const;
+    void clearCurvature() const;
+    void attachCurvature(pVertex pv, double curv) const;
+
+    void outputCurvature(const char * fn) const;
+
+  private:
+
+    double computeDistance(const pVertex pv) const;
+    void computeGradientInElements() const;
+    void clearGradientInElements() const;
+
+    bool getGradientOnEdge(const pEdge edge, 
+                           const double xyz[3],
+                           double grad[3]) const;
+    bool getGradientOnEdgeParam(const pEdge pE, 
+                                const double u,
+                                double grad[3]) const;
+    bool getGradientOnFace(const pFace face, 
+                           const double xyz[3],
+                           double grad[3]) const;
+    bool getGradientOnFaceParam(const pFace face, 
+                                const double u[2],
+                                double grad[3]) const;
+    bool getGradientOnRegion(const pRegion region, 
+                             const double xyz[3],
+                             double grad[3]) const;
+    bool getGradientOnRegionParam(const pRegion region, 
+                                  const double u[3],
+                                  double grad[3]) const;
+
+  private:
+
+    pMesh mesh;
+    pMeshDataId distId, vGradId, rGradId, vCurvId;
+
+    // true:  distance computed to a set of edges (2D) or faces (3D)
+    // false: distance computed to a set of vertices
+    bool distToEntities;
+
+    int nVert, nEnt;
+    int nVE; // number of vertices in a wall entity
+    double * xyzV; // coordinates of the vertices sorted by local ids with contiguous xyz
+    int * entToV;  // entities vertices (by local id)
+    std::multimap<int,int> vToEnt; // vertices entities
+    SearchTool * kdSearch;
+    std::map<pVertex,int> pvToSearchId;
+    
+  };
+
+  // -------------------------------------------------------------------
+}
+
+#endif
diff --git a/Adapt/utils/DistanceToPoints.h b/Adapt/utils/DistanceToPoints.h
new file mode 100644
index 0000000..149be91
--- /dev/null
+++ b/Adapt/utils/DistanceToPoints.h
@@ -0,0 +1,148 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_DISTANCETOPOINTS
+#define _H_DISTANCETOPOINTS
+
+#ifdef _HAVE_ANN_
+#include <ANN/ANN.h>
+#endif
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class MAd_searchTool {
+
+  public:
+    MAd_searchTool() {
+      printf("Error: no search tool implemented: flag _HAVE_ANN_ not set\n");
+      throw;
+    }
+    void reset() { throw; }
+    void allocatePoints(int n) { throw; }
+    void addPoint(int index, double xyz[3]) { throw; }
+    void allocateTree(int n) { throw; }
+    double computeDistanceSq(const double xyz[3], int * id=NULL) const { throw; }
+  };
+
+  // -------------------------------------------------------------------
+#ifdef _HAVE_ANN_
+  class ANN_searchTool {
+
+  public:
+
+    ANN_searchTool()
+    {
+      kdTree = NULL;
+      points = NULL;
+    }
+
+    ~ANN_searchTool()
+    {
+      if (kdTree) { delete kdTree; kdTree = NULL; }
+      if (points) { annDeallocPts(points); points = NULL; }
+      annClose();
+    }
+
+    void reset()
+    {
+      if (kdTree) { delete kdTree; kdTree = NULL; }
+      if (points) { annDeallocPts(points); points = NULL; }
+    }
+
+    void allocatePoints(int n)
+    {
+      if (points) annDeallocPts(points);
+      points = annAllocPts(n,3);
+    }
+
+    void addPoint(int index, double xyz[3])
+    {
+      for (int i=0; i<3; i++) points[index][i] = xyz[i];
+    }
+
+    void allocateTree(int n)
+    {
+      if (kdTree) delete kdTree;
+      kdTree = new ANNkd_tree(points, n, 3);
+    }
+
+    double computeDistanceSq(const double xyz[3], int * id=NULL) const
+    {
+      if (!kdTree) {
+        printf("Error: no research tree built\n");
+        throw;
+      }
+
+      double xyz_copy[3]; // because the first argument of annkSearch is not const
+      for (int i=0; i<3; i++) xyz_copy[i] = xyz[i];
+      int maxpts = 1;
+      // the use of allocation is done due to ms visual c++ compiler 
+      // that do not support c99 standard (it uses the c95 et c++98 standards)
+      ANNidx*  index= new ANNidx[maxpts];
+      ANNdist* distSq= new ANNdist[maxpts];
+      kdTree->annkSearch(xyz_copy, maxpts, index, distSq);
+      double theDistSq = distSq[0];
+      if ( id ) *id = index[0];
+      delete [] index;
+      delete [] distSq;
+      return theDistSq;
+    }
+
+    // Compute gradient of the square distance to the cloud of points 
+    // by non-centered differences. Central differences would lead to 
+    // zero gradients for points located on the walls (distance is not signed).
+    double gradDistanceSq(const double xyz[3], double grad[3]) const
+    {
+      double dSq = computeDistanceSq(xyz);
+      double eps = 1.e-3;
+      double dEps[2];
+
+      int maxpts = 1;
+      ANNidx*  index= new ANNidx[maxpts];
+      ANNdist* distSq= new ANNdist[maxpts];
+      double tmp[3];
+      tmp[0] = xyz[0]; tmp[1] = xyz[1]; tmp[2] = xyz[2];
+      for (int i=0; i<3; i++) {
+        tmp[i] += eps;
+        kdTree->annkSearch(tmp, maxpts, index, distSq);
+        dEps[0] = distSq[0];
+        tmp[i] -= 2*eps;
+        kdTree->annkSearch(tmp, maxpts, index, distSq);
+        dEps[1] = distSq[1];
+        tmp[i] += eps;
+        grad[i] = 1000. * ( dEps[1] - dEps[0] );
+      }
+    }
+
+    private:
+
+      ANNkd_tree * kdTree;
+      ANNpoint * points;
+  };
+
+  typedef ANN_searchTool SearchTool;
+
+  // -------------------------------------------------------------------
+#else
+
+  typedef MAd_searchTool SearchTool;
+
+  // -------------------------------------------------------------------
+#endif
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Adapt/utils/History.cc b/Adapt/utils/History.cc
new file mode 100644
index 0000000..a783c30
--- /dev/null
+++ b/Adapt/utils/History.cc
@@ -0,0 +1,144 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "History.h"
+
+#include <stdarg.h>
+#include <fstream>
+#include <iostream>
+#include <stdlib.h>
+using std::ostream;
+
+namespace MAd {
+
+  static int actionIntParameters[UNKNOWN_ACTION] = {1,1,1,1,1};
+
+  // -------------------------------------------------------------------
+  void History::initialize()
+  {
+    open = false;
+    refCount = -1;
+  }
+
+  // -------------------------------------------------------------------
+  void History::finalize()
+  {
+    journal.clear();
+    refJournal.clear();
+  }
+
+  // -------------------------------------------------------------------
+  void History::add(int ot, actionType at, ...)
+  {
+    if ( !open ) return;
+
+    va_list ap;
+    va_start(ap, at);
+
+    std::vector<int> intParams;
+    for (int iInt=0; iInt < actionIntParameters[at]; iInt++) {
+      intParams.push_back(va_arg(ap, int));
+    }
+
+    va_end(ap);
+
+    action act;
+    act.opType    = ot;
+    act.actType   = at;
+    act.intParams = intParams;
+
+    add(act);
+  }
+
+  // -------------------------------------------------------------------
+  void History::add(action act)
+  {
+    if ( !open ) return;
+
+    journal.push_back(act);
+  
+    if ( !compare() ) {
+      std::cerr << "Error in History: operations are not the same as in the reference journal\n";
+      flushJournal("journal_for_diff");
+      exit(1);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  bool History::compare()
+  {
+    if ( !open ) return false;
+
+    if ( refJournal.empty() || refCount >= (int) refJournal.size() ) return true;
+  
+    for (; refCount < (int) journal.size(); refCount++) {
+      if ( journal[refCount] != refJournal[refCount] ) return false;
+    }
+
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  void History::loadJournal(std::string name)
+  {
+    FILE * f = fopen(name.c_str(),"r");
+    if ( !f ) {
+      std::cerr << "Error: could not open file " << name << std::endl; throw;
+    }
+
+    int opType;
+    int actType;
+    while ( fscanf(f,"%d %d",&opType,&actType) != EOF ) {
+
+      std::vector<int> intParams;
+      int par;
+      for (int iPar=0; iPar<actionIntParameters[actType]; iPar++) {
+        fscanf(f,"%d",&par);
+        intParams.push_back(par);
+      }
+
+      action act;
+      act.opType    = opType;
+      act.actType   = (actionType)    actType;
+      act.intParams = intParams;
+
+      refJournal.push_back(act);
+    }
+
+    fclose(f);
+
+    refCount = 0;
+  }
+
+  // -------------------------------------------------------------------
+  void History::flushJournal(ostream& out) const
+  {
+    for (int iAct=0; iAct < (int) journal.size(); iAct++) {
+      action act = journal[iAct];
+      out << act.opType << "\t" << act.actType;
+      for (int iP=0; iP<actionIntParameters[act.actType]; iP++) {
+        out << "\t"<< act.intParams[iP];
+      }
+      out << "\n";
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void History::flushJournal(std::string name) const
+  {
+    std::ofstream fileOut(name.c_str());
+    flushJournal(fileOut);
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/utils/History.h b/Adapt/utils/History.h
new file mode 100644
index 0000000..435c743
--- /dev/null
+++ b/Adapt/utils/History.h
@@ -0,0 +1,91 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_HISTORY
+#define _H_HISTORY
+
+#include "MAdSingleton.h"
+
+#include <vector>
+#include <ostream>
+#include <string>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  enum actionType {
+    OP_CHECKCONSTRAINTS = 0,
+    OP_CHECKGEOMETRY    = 1,
+    OP_CHECKSHAPES      = 2,
+    OPERATOR_APPLY      = 3,
+    OPERATOR_UNAPPLY    = 4,
+    UNKNOWN_ACTION      = 5
+  };
+
+  struct action {
+    int opType;
+    actionType actType;
+    std::vector<int> intParams;
+
+    bool operator!=(const action& other) {
+      if ( opType  != other.opType  ) return true;
+      if ( actType != other.actType ) return true;
+      if ( intParams.size() != other.intParams.size() ) return true;
+      for (unsigned int i=0; i<intParams.size(); i++) {
+        if ( intParams[i] != other.intParams[i] ) return true;
+      }
+      return false;
+    }
+  };
+
+  // -------------------------------------------------------------------
+  class History {
+
+  public:
+  
+    History()  {};
+    ~History() {};
+  
+    void initialize();
+    void finalize();
+  
+    void openJournal()  { open = true;  };
+    void closeJournal() { open = false; };
+
+    void add(int, actionType,...);
+    void add(action);
+
+    bool compare();
+
+    void flushJournal(std::ostream& out) const;
+    void flushJournal(std::string name) const;
+
+    void loadJournal(std::string name);
+  
+  private:
+  
+    bool open; // indicates if the journal is in use
+
+    std::vector<action> journal;      // list of actions
+
+    std::vector<action> refJournal;  // journal to compare with
+    int refCount;                    // position of the next action to compare
+  };
+
+  // -------------------------------------------------------------------
+
+  typedef MAdSingleton<History> HistorySgl;
+
+}
+
+#endif
diff --git a/Adapt/utils/MAdLinearSystem.h b/Adapt/utils/MAdLinearSystem.h
new file mode 100644
index 0000000..7e6e58e
--- /dev/null
+++ b/Adapt/utils/MAdLinearSystem.h
@@ -0,0 +1,126 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_LINEARSYSTEM_MAD
+#define _H_LINEARSYSTEM_MAD
+
+namespace MAd {
+
+  // A class that encapsulates a linear system solver interface :
+  // building a sparse matrix, solving a linear system
+
+  // -------------------------------------------------------------------
+  enum SolverType { GMRES, CG };
+
+  // -------------------------------------------------------------------
+  class MAdLinearSystem {
+
+  public:
+
+    MAdLinearSystem (): sType(GMRES),fill(0),eps(1.e-12) {}
+    virtual ~MAdLinearSystem () {}
+
+  public:
+
+    virtual bool isAllocated () const = 0;
+    virtual void allocate (int nbRows) = 0;
+    virtual void  addToMatrix    (int _row, int _col, double val) = 0;
+    virtual double getFromMatrix (int _row, int _col) const = 0;
+    virtual void  addToRightHandSide    (int _row, double val) = 0;
+    virtual double getFromRightHandSide (int _row) const = 0;
+    virtual double getFromSolution (int _row) const = 0;
+    virtual void zeroMatrix () = 0;
+    virtual void zeroRightHandSide () = 0;
+    virtual void reorder() = 0;
+    virtual int systemSolve () = 0;
+		virtual void set_nnz(int row,int nz){}
+		virtual void allocate_matrix(){}
+
+    virtual void setSolver(SolverType _type) {sType = _type;}
+    void setFillIn(int _k) {fill=_k;}
+    void setEps(double _eps) {eps=_eps;}
+    virtual void setPrec(double){}
+    virtual void setNoisy(int){}
+
+  protected:
+
+    SolverType sType;
+    int fill;
+    double eps;
+
+  };
+
+  // -------------------------------------------------------------------
+  class MAdLinearSystemNull : public MAdLinearSystem {
+
+  public:
+  
+    MAdLinearSystemNull ()
+    {
+      printf("Error: no linear systems solver available\n");
+      throw;
+    }
+
+  public:
+
+    bool isAllocated () const { return false; }
+    void allocate (int nbRows) {}
+    void  addToMatrix    (int _row, int _col, double val) {}
+    double getFromMatrix (int _row, int _col) const { return 0.; }
+    void  addToRightHandSide    (int _row, double val) {}
+    double getFromRightHandSide (int _row) const { return 0.; }
+    double getFromSolution (int _row) const { return 0.; }
+    void zeroMatrix () {}
+    void zeroRightHandSide () {}
+    void reorder() {}
+    int systemSolve () { return 0; }
+  };
+
+  // -------------------------------------------------------------------
+
+}
+
+// -------------------------------------------------------------------
+
+#ifdef _HAVE_PETSC_
+#include "MAdLinearSystemPETSc.h"
+namespace MAd {
+  typedef MAdLinearSystemPETSc MAdLinearSystemDef;
+}
+#else
+
+#ifdef _HAVE_SPARSKIT_
+#include "MAdLinearSystemSparskit.h"
+namespace MAd {
+  typedef MAdLinearSystemSparskit MAdLinearSystemDef;
+}
+#else
+
+#ifdef _HAVE_GMM_
+#include "MAdLinearSystemGmm.h"
+namespace MAd {
+  typedef MAdLinearSystemGmm MAdLinearSystemDef;
+}
+#else
+namespace MAd {
+  typedef MAdLinearSystemNull MAdLinearSystemDef;
+}
+#endif // end gmm
+#endif // end sparskit
+#endif // end PETSc
+
+// -------------------------------------------------------------------
+
+#endif
+
+
diff --git a/Adapt/utils/MAdLinearSystemGmm.h b/Adapt/utils/MAdLinearSystemGmm.h
new file mode 100644
index 0000000..c2d986b
--- /dev/null
+++ b/Adapt/utils/MAdLinearSystemGmm.h
@@ -0,0 +1,111 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_LINEARSYSTEMGMM_MAD
+#define _H_LINEARSYSTEMGMM_MAD
+
+#ifdef _HAVE_GMM_
+
+// Interface to GMM++
+
+#include "MAdLinearSystem.h"
+
+#include <gmm.h>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class MAdLinearSystemGmm : public MAdLinearSystem {
+
+  public :
+
+    MAdLinearSystemGmm () : MAdLinearSystem(), _a(0), _b(0), _x(0), _prec(1.e-8), _noisy(0) {}
+    ~MAdLinearSystemGmm ()
+    {
+      delete _a;
+      delete _b;
+      delete _x;
+    }
+
+  public:
+
+    bool isAllocated () const {return _a != 0;}
+    void allocate (int _nbRows)
+    {
+      if (_a) delete _a;
+      if (_x) delete _x;
+      if (_b) delete _b;
+      _a = new  gmm::row_matrix< gmm::wsvector<double> >(_nbRows,_nbRows);
+      _b = new  std::vector<double>(_nbRows);
+      _x = new  std::vector<double>(_nbRows);    
+    }
+    void  addToMatrix    (int _row, int _col, double _val) 
+    {
+      if (_val != 0.0) (*_a)(_row, _col) += _val;
+    }
+    double getFromMatrix (int _row, int _col) const
+    {
+      return (*_a)(_row, _col);
+    }
+    void  addToRightHandSide    (int _row, double _val) 
+    {
+      if (_val != 0.0) (*_b)[_row]+=_val;
+    }
+    double getFromRightHandSide (int _row) const 
+    {
+      return (*_b)[_row];
+    }
+    double getFromSolution (int _row) const 
+    {
+      return (*_x)[_row];
+    }
+    void zeroMatrix () 
+    {
+      gmm::clear(*_a);
+    }
+    void zeroRightHandSide () 
+    {
+      for (unsigned int i = 0; i < _b->size(); i++) (*_b)[i] = 0;
+    }
+    void reorder () {
+    
+    }
+    void setPrec(double p){_prec=p;}
+    void setNoisy(int n){_noisy=n;}
+    int systemSolve () 
+    {
+      //gmm::ilut_precond< gmm::row_matrix< gmm::wsvector<double> > > P(*_a, fill, _prec);
+      gmm::ildltt_precond< gmm::row_matrix< gmm::wsvector<double> > > P(*_a, fill, _prec);
+      gmm::iteration iter(eps);
+      iter.set_noisy(_noisy);
+      //     gmm::sequential_additive_schwarz(*_a, *_x, *_b, P, vB, iter, local_solver, global_solver)
+      if (sType==GMRES)gmm::gmres(*_a, *_x, *_b, P, 100, iter);  // execute the GMRES algorithm
+      else gmm::cg(*_a, *_x, *_b, P, iter);  // execute the CG algorithm
+      return 1;
+    }
+
+  private:
+
+    gmm::row_matrix<gmm::wsvector<double> > *_a;
+    std::vector<double> *_b, *_x;
+    double _prec;
+    int _noisy;
+  };
+
+  // -------------------------------------------------------------------
+
+#endif
+
+}
+
+#endif
diff --git a/Adapt/utils/MAdLinearSystemPETSc.h b/Adapt/utils/MAdLinearSystemPETSc.h
new file mode 100644
index 0000000..f5a68e0
--- /dev/null
+++ b/Adapt/utils/MAdLinearSystemPETSc.h
@@ -0,0 +1,215 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Richard Comblen, Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_LINEARSYSTEMPETSC_MAD
+#define _H_LINEARSYSTEMPETSC_MAD
+
+// -------------------------------------------------------------------
+//  Interface to PETSc
+// -------------------------------------------------------------------
+
+#ifdef _HAVE_PETSC_
+
+#include "MAdLinearSystem.h"
+#include "petsc.h"
+#include "petscksp.h"
+#include "petscmat.h"
+#include "petscvec.h"
+#include <iostream>
+
+namespace MAd {
+  class MAdLinearMatrixPETSc {
+  private:
+    int * nnz;
+    int local_size, global_size;
+    bool allocated, assembled;
+  public:
+    Mat mat;
+    MAdLinearMatrixPETSc(int _local_size, int _global_size) {
+      local_size  = _local_size;
+      global_size = _global_size;
+      nnz = new int[local_size];
+      mat = NULL;
+      allocated = false;
+      assembled = false;
+    }
+    ~MAdLinearMatrixPETSc() {
+      if(mat) MatDestroy(mat);
+      delete [] nnz;
+    }
+    void set_nnz(int row, int nz){
+      nnz[row] = nz;
+    }
+    // You must call set_nnz before!
+    void allocate(){
+      if(!allocated){
+        MatCreate(PETSC_COMM_WORLD, &mat);
+        MatSetSizes(mat,local_size,local_size,global_size,global_size);
+        MatSetFromOptions(mat);
+        //    MatMPIAIJSetPreallocationCSR(mat,sparsity->rowstart,sparsity->colind,NULL);
+        MatSeqAIJSetPreallocation(mat,0,nnz);
+        allocated=true;
+      }
+    }
+    void add(int row, int col, double val){ 
+      MatSetValue(mat, row, col, val, ADD_VALUES);
+      assembled = false;
+    }
+    void assemble()
+    {
+      if(assembled) return;
+      MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY);
+      MatAssemblyEnd  (mat, MAT_FINAL_ASSEMBLY);
+#if PETSC_VERSION_MAJOR==3
+      MatSetOption(mat, MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);
+      MatSetOption(mat, MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE);
+#else
+      MatSetOption(mat, MAT_NO_NEW_NONZERO_LOCATIONS);
+#endif 
+      assembled = true;
+    }
+    void zero(){
+      //assemble();
+      MatZeroEntries(mat);
+    }
+  };
+  class MAdLinearVectorPETSc {
+  private:
+    int local_size, global_size, nghosts;
+    double * entries;
+  public:
+    Vec vec;
+    MAdLinearVectorPETSc(int _local_size, int _global_size){
+      global_size = _global_size;
+      local_size  = _local_size;
+      nghosts = 0;
+      entries = new double[local_size+nghosts];
+      VecCreateMPIWithArray(MPI_COMM_WORLD,local_size,global_size,entries,&vec);
+      VecAssemblyBegin(vec);
+      VecAssemblyEnd(vec);
+      VecSet(vec, 0);
+      get_array();
+    }
+    ~MAdLinearVectorPETSc(){
+      VecDestroy(vec);
+      delete []entries;// Check whether Petsc does destroy it or not...
+    }
+    inline double& operator()(int row){
+      return entries[row];
+    }
+    void zero(){
+      for(int i=0;i<local_size+nghosts;i++){
+        entries[i]=0;
+      }
+    }
+    void gather(){
+      // To be implemented - see slim_vector.cc
+    }
+    void scatter(){
+      // To be implemented - see slim_vector.cc
+    }
+    void get_array(){
+      VecGetArray(vec,&entries);
+    }
+    void restore_array(){
+      VecRestoreArray(vec,&entries);
+    }
+  };
+
+  // -------------------------------------------------------------------
+  class MAdLinearSystemPETSc : public MAdLinearSystem {
+
+  private:
+    MAdLinearMatrixPETSc * matrix;
+    MAdLinearVectorPETSc * rhs;
+    MAdLinearVectorPETSc * X;
+    KSP ksp;
+
+  public:
+
+    MAdLinearSystemPETSc():
+      MAdLinearSystem()
+    {
+      PetscInitialize(0,NULL, NULL, NULL);
+      KSPCreate(PETSC_COMM_WORLD, &ksp);
+    }
+    ~MAdLinearSystemPETSc ()
+    {
+      KSPDestroy(ksp);
+      delete matrix;
+      delete rhs;
+      delete X;
+    }
+    bool isAllocated () const {throw;}
+    void allocate (int nbRows){
+      int local_size, global_size;
+      local_size = global_size = nbRows;
+      matrix = new MAdLinearMatrixPETSc(local_size, global_size);
+      rhs    = new MAdLinearVectorPETSc(local_size, global_size);
+      X      = new MAdLinearVectorPETSc(local_size, global_size);
+    }
+    void addToMatrix (int row, int col, double val) {
+      matrix->add(row,col,val);
+    }
+    double getFromMatrix (int _row, int _col) const {
+      throw;
+    }
+    void addToRightHandSide (int row, double val) {
+      (*rhs)(row) += val;
+    }
+    double getFromRightHandSide (int row) const {
+      return (*rhs)(row);
+    }
+    double getFromSolution (int row) const {
+      return (*X)(row);
+    }
+    void zeroMatrix () {
+      matrix->zero();
+    }
+    void zeroRightHandSide () {
+      rhs->zero();
+    }
+    void reorder () {
+    }
+    void set_nnz(int row,int nz){
+      matrix->set_nnz(row,nz);
+    }
+    void allocate_matrix(){
+      matrix->allocate();
+    }
+    void setSolver(SolverType _type) {
+    }
+    int systemSolve () {
+      rhs->restore_array();
+      X->restore_array();
+      matrix->assemble();
+      std::string options;
+      options="-pc_type bjacobi -sub_pc_type icc -ksp_type cg -ksp_rtol 1e-6";
+//      options="-pc_type hypre -pc_hypre_type boomeramg -pc_hypre_boomeramg_print_statistics -ksp_type gmres -ksp_rtol 1e-7 -ksp_monitor";
+      PetscOptionsInsertString(options.c_str());
+      KSPSetFromOptions(ksp);
+      KSPSetOperators (ksp, matrix->mat, matrix->mat, DIFFERENT_NONZERO_PATTERN);
+      KSPSolve(ksp, rhs->vec, X->vec);
+      
+      X->get_array();
+      rhs->get_array();
+      KSPConvergedReason reason;
+      return KSPGetConvergedReason(ksp,&reason);
+    }
+
+  };
+}
+
+#endif
+
+#endif
diff --git a/Adapt/utils/MAdLinearSystemSparskit.h b/Adapt/utils/MAdLinearSystemSparskit.h
new file mode 100644
index 0000000..a578c1e
--- /dev/null
+++ b/Adapt/utils/MAdLinearSystemSparskit.h
@@ -0,0 +1,106 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_LINEARSYSTEMSPARSKIT_MAD
+#define _H_LINEARSYSTEMSPARSKIT_MAD
+
+// -------------------------------------------------------------------
+//  Interface to Y Saad's sparskit lib
+// -------------------------------------------------------------------
+
+#ifdef _HAVE_SPARSKIT_
+
+#include "MAdLinearSystem.h"
+#include "MAdMessage.h"
+
+#include "CSR_Matrix.h"
+#include "CSR_Vector.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class MAdLinearSystemSparskit : public MAdLinearSystem {
+
+  public:
+
+    MAdLinearSystemSparskit ():
+      MAdLinearSystem(),_a(0),_b(0),_x(0)
+    {
+    }
+    ~MAdLinearSystemSparskit ()
+    {
+      delete _a;
+      delete _b;
+      delete _x;
+    }
+    bool isAllocated () const {return _a != 0;}
+    void allocate (int _nbRows)
+    {
+      if (_a) delete _a;
+      if (_b) delete _b;
+      if (_x) delete _x;
+      _a = new CSR_Matrix (_nbRows);
+      _b = new CSR_Vector (_nbRows);
+      _x = new CSR_Vector (_nbRows);
+    }
+    void addToMatrix (int _row, int _col, double _val) {
+      if (_val != 0.0) _a->AddMatrix (_row+1, _col+1, _val);
+    }
+    double getFromMatrix (int _row, int _col) const {
+      return _a->GetMatrix (_row+1,_col+1);
+    }
+    void addToRightHandSide (int _row, double _val) {
+      if (_val != 0.0) _b->AddVal(_row+1, _val);
+    }
+    double getFromRightHandSide (int _row) const {
+      return _b->GetVal (_row+1);
+    }
+    double getFromSolution (int _row) const {
+      return _x->GetVal (_row+1);
+    }
+    void zeroMatrix () {
+      _a->ZeroMatrix();
+    }
+    void zeroRightHandSide () {
+      _b->ZeroArray();
+    }
+    void reorder () {
+    
+    }
+    void setSolver(SolverType _type) {
+      MAdMsgSgl::instance().warning(__LINE__,__FILE__,"CG not available in Sparskit, GMRES will be used\n");
+      sType = GMRES;
+    }
+    int systemSolve () {
+      _a->EndOfAssembly();
+      std::string solver = "gmres";
+      //    if (sType == CG) solver = "cg";
+      SPARSKIT_LINEAR_SOLVER_ ( "rcmk","ilut",solver,fill,eps,*_a,*_b,*_x);
+      return 1;
+    }
+
+  private:
+  
+    CSR_Matrix *_a;
+    CSR_Vector *_b;
+    CSR_Vector *_x;
+  
+  };
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
+
+#endif
diff --git a/Adapt/utils/MAdStatistics.cc b/Adapt/utils/MAdStatistics.cc
new file mode 100644
index 0000000..5269899
--- /dev/null
+++ b/Adapt/utils/MAdStatistics.cc
@@ -0,0 +1,60 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MAdStatistics.h"
+
+using std::ostream;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  void MAdStatistics::initialize()
+  {
+    t_eSplits    = 0.;
+    t_eCollapses = 0.;
+    t_eSwaps     = 0.;
+    t_rSlivers   = 0.;
+    t_fSlivers   = 0.;
+
+    num_eSplits    = 0;
+    num_eCollapses = 0;
+    num_eSwaps     = 0;
+
+    numInfLoops = 0;
+  }
+
+  // -------------------------------------------------------------------
+  void MAdStatistics::finalize()
+  {
+  }
+
+  // -------------------------------------------------------------------
+  void MAdStatistics::print(ostream& out) const
+  {
+    out << "\n*** Statistics about local mesh modifications *** \n\n";
+
+    out << "Time spent in the different operators:\n";
+    double t_Total = t_eSplits + t_eCollapses + t_eSwaps + t_rSlivers + t_fSlivers;
+    out << "Edge splits\tEdge collapses\tEdge swaps\tSlivers\tTotal\n"
+        << t_eSplits <<"\t"<< t_eCollapses <<"\t"<< t_eSwaps <<"\t"
+        << t_rSlivers+t_fSlivers <<"\t"<< t_Total <<"\n\n";
+
+    out << "Number of elementary operations (excluding sliver handling):\n";
+    out << "Edge splits\tEdge collapses\tEdge swaps\n"
+        << num_eSplits <<"\t"<< num_eCollapses <<"\t"<< num_eSwaps << "\n\n";
+
+    out << "Number of infinite loops:\t" << numInfLoops << "\n\n";
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/utils/MAdStatistics.h b/Adapt/utils/MAdStatistics.h
new file mode 100644
index 0000000..df95304
--- /dev/null
+++ b/Adapt/utils/MAdStatistics.h
@@ -0,0 +1,94 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MADSTATISTICS
+#define _H_MADSTATISTICS
+
+#include "MAdSingleton.h"
+
+#include <iostream>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class MAdStatistics {
+
+  public:
+  
+    MAdStatistics()  {};
+    ~MAdStatistics() {};
+  
+    void initialize();
+    void finalize();
+
+    void print(std::ostream& out) const;
+
+    // -----------------------
+    // CPU time
+    // -----------------------
+
+  private:
+
+    double t_eSplits, t_eCollapses, t_eSwaps, t_rSlivers, t_fSlivers;
+
+  public:
+  
+    void addCPUESplits    (double dt) { t_eSplits    += dt; }
+    void addCPUECollapses (double dt) { t_eCollapses += dt; }
+    void addCPUESwaps     (double dt) { t_eSwaps     += dt; }
+    void addCPURSlivers   (double dt) { t_rSlivers   += dt; }
+    void addCPUFSlivers   (double dt) { t_fSlivers   += dt; }
+
+    double getCPUESplits    () const { return t_eSplits;    }
+    double getCPUECollapses () const { return t_eCollapses; }
+    double getCPUESwaps     () const { return t_eSwaps;     }
+    double getCPURSlivers   () const { return t_rSlivers;   }
+    double getCPUFSlivers   () const { return t_fSlivers;   }
+
+
+    // -----------------------------
+    // Elementary operations count
+    // -----------------------------
+
+  private:
+
+    int num_eSplits, num_eCollapses, num_eSwaps;
+
+  public:
+
+    void addNumESplits    (int num) { num_eSplits    += num; }
+    void addNumECollapses (int num) { num_eCollapses += num; }
+    void addNumESwaps     (int num) { num_eSwaps     += num; }
+
+
+    // -----------------------------
+    // Others
+    // -----------------------------
+
+  private:
+
+    int numInfLoops;
+
+  public:
+
+    void addInfiniteLoops(int num) { numInfLoops += num; }
+
+  };
+
+  // -------------------------------------------------------------------
+
+  typedef MAdSingleton<MAdStatistics> MAdStatisticsSgl;
+
+}
+
+#endif
diff --git a/Adapt/utils/MAdTimeManager.cc b/Adapt/utils/MAdTimeManager.cc
new file mode 100644
index 0000000..ea341e7
--- /dev/null
+++ b/Adapt/utils/MAdTimeManager.cc
@@ -0,0 +1,48 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MAdTimeManager.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  void MAdTimeManager::initialize()
+  {
+    time = 0.;
+  }
+
+  // -------------------------------------------------------------------
+  void MAdTimeManager::finalize()
+  {
+  }
+
+  // -------------------------------------------------------------------
+  void MAdTimeManager::setTime(double _t)
+  {
+    time = _t;
+  }
+
+  // -------------------------------------------------------------------
+  void MAdTimeManager::incrementTime(double dt)
+  {
+    time += dt;
+  }
+
+  // -------------------------------------------------------------------
+  double MAdTimeManager::getTime() const
+  {
+    return time;
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/utils/MAdTimeManager.h b/Adapt/utils/MAdTimeManager.h
new file mode 100644
index 0000000..c745d90
--- /dev/null
+++ b/Adapt/utils/MAdTimeManager.h
@@ -0,0 +1,49 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MADTIMEMANAGER
+#define _H_MADTIMEMANAGER
+
+#include "MAdSingleton.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class MAdTimeManager {
+
+  public:
+  
+    MAdTimeManager() {};
+    ~MAdTimeManager() {};
+  
+    void   initialize();
+    void   finalize();
+
+    void   setTime(double);
+    void   incrementTime(double);
+
+    double getTime() const;
+  
+  private:
+
+    double time;
+
+  };
+
+  // -------------------------------------------------------------------
+
+  typedef MAdSingleton<MAdTimeManager> MAdTimeManagerSgl;
+
+}
+
+#endif
diff --git a/Adapt/utils/NodalDataManager.cc b/Adapt/utils/NodalDataManager.cc
new file mode 100644
index 0000000..cad2d15
--- /dev/null
+++ b/Adapt/utils/NodalDataManager.cc
@@ -0,0 +1,614 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "NodalDataManager.h"
+#include "CallBackManager.h"
+#include "MAdOutput.h"
+
+#include "MSops.h"
+
+#include <iostream>
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::vector;
+using std::set;
+using std::ostream;
+using std::string;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  void P1CBFunction (pPList before, pPList after, void *dataNames,
+                     operationType type , pEntity ppp) {
+  
+    set<string>* knownDataNames = static_cast<set<string>*>(dataNames);
+
+    switch (type) {
+    case MAd_ESPLIT: {
+      // In the edge split case, we have to interpolate the data at the new node
+
+      set<string>::const_iterator tIter = (*knownDataNames).begin();
+      set<string>::const_iterator tLast = (*knownDataNames).end();
+      for (; tIter != tLast; tIter++ ) {
+
+        pMeshDataId dataId = MD_lookupMeshDataId((*tIter).c_str());
+    
+        // find the old edge
+        void *tmp=0;
+        pEntity pE = PList_next(before,&tmp);
+        double t = E_linearParams((pEdge)pE,(pVertex)ppp);
+     
+        // get datas at old nodes
+        double data0 = 0.;
+        pVertex pV0 = E_vertex((pEdge)pE, 0); 
+        int gotit0 = EN_getDataDbl((pEntity)pV0, dataId,  &data0);
+      
+        double data1 = 0.;
+        pVertex pV1 = E_vertex((pEdge)pE, 1); 
+        int gotit1 = EN_getDataDbl((pEntity)pV1, dataId,  &data1);
+      
+        if (!gotit0 || !gotit1) {
+          printf("Error: one of the nodes has no data attached to with name %s",
+                 (*tIter).c_str());
+          throw;
+        }
+
+        // Interpolate the data at the new node. 
+        double newData = (1.-t) * data0 + t * data1;
+      
+        // attach it
+        EN_attachDataDbl(ppp, dataId, newData);
+      }
+
+      break;
+    } 
+    case MAd_ECOLLAPSE: {
+      // In the edge collapse case, we have to delete the datas attached to the deleted node
+    
+      set<string>::const_iterator tIter = (*knownDataNames).begin();
+      set<string>::const_iterator tLast = (*knownDataNames).end();
+      for (; tIter != tLast; tIter++ ) {
+
+        pMeshDataId dataId = MD_lookupMeshDataId((*tIter).c_str());
+        EN_deleteData(ppp, dataId);
+      }
+  
+      break;
+    }
+    case MAd_ESWAP:
+    case MAd_FSWAP: {
+      // nothing to be done (no modification at nodes)
+      break;
+    }
+    case MAd_RREMOVE: {
+      void * temp = NULL;
+      while ( pEntity pE = PList_next(before,&temp) ) {
+        if ( EN_type(pE) == 0 ) {
+          set<string>::const_iterator tIter = (*knownDataNames).begin();
+          set<string>::const_iterator tLast = (*knownDataNames).end();
+          for (; tIter != tLast; tIter++ ) {
+            pMeshDataId dataId = MD_lookupMeshDataId((*tIter).c_str());
+            EN_deleteData( (pVertex)pE, dataId);
+          }
+        }
+      }
+      break;
+    }
+    case MAd_UNKNOWNOPERATION:
+    case MAd_VERTEXMOVE:
+    case MAd_FCOLLAPSE:
+    case MAd_DESPLTCLPS:
+    default: {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Not implemented for mesh modification %d",
+                                  type);
+    }
+    }
+  
+  }
+
+  // -------------------------------------------------------------------
+  void P1VecCBFunction (pPList before, pPList after, void *dataNames,
+                        operationType type , pEntity ppp) {
+  
+    set<string>* knownDataNames = static_cast<set<string>*>(dataNames);
+
+    switch (type) {
+    case MAd_ESPLIT: {
+      // In the edge split case, we have to interpolate the data at the new node
+
+      set<string>::const_iterator tIter = (*knownDataNames).begin();
+      set<string>::const_iterator tLast = (*knownDataNames).end();
+      for (; tIter != tLast; tIter++ ) {
+
+        pMeshDataId dataId = MD_lookupMeshDataId((*tIter).c_str());
+    
+        // find the old edge
+        void *tmp=0;
+        pEntity pE = PList_next(before,&tmp);
+        double t = E_linearParams((pEdge)pE,(pVertex)ppp);
+     
+        // get coordinates and datas at old nodes
+        void * data0 = NULL;
+        pVertex pV0 = E_vertex((pEdge)pE, 0);
+        int gotit0 = EN_getDataPtr((pEntity)pV0, dataId,  &data0);
+        vector<double> * vec0 = (vector<double>*) data0;
+      
+        void * data1 = NULL;
+        pVertex pV1 = E_vertex((pEdge)pE, 1);
+        int gotit1 = EN_getDataPtr((pEntity)pV1, dataId,  &data1);
+        vector<double> * vec1 = (vector<double>*) data1;
+      
+        if (!gotit0 || !gotit1) {
+          printf("Error: one of the nodes has no data attached to with name %s",
+                 (*tIter).c_str());
+          throw;
+        }
+
+        // Interpolate the data at the new node. 
+        vector<double> * newData = new vector<double>;
+        for (int i=0; i<3; i++)  (*newData).push_back( (1.-t) * (*vec0)[i] + t * (*vec1)[i] );
+      
+        // attach it
+        EN_attachDataPtr(ppp, dataId, newData);
+      }
+
+      break;
+    } 
+    case MAd_ECOLLAPSE: {
+      // In the edge collapse case, we have to delete the datas attached to the deleted node
+          
+      set<string>::const_iterator tIter = (*knownDataNames).begin();
+      set<string>::const_iterator tLast = (*knownDataNames).end();
+      for (; tIter != tLast; tIter++ ) {
+
+        pMeshDataId dataId = MD_lookupMeshDataId((*tIter).c_str());
+        void * data = NULL;
+        int gotit = EN_getDataPtr((pEntity)ppp, dataId,  &data);
+        vector<double> * vec = (vector<double>*) data;
+        if (gotit && vec) delete vec;
+        EN_deleteData(ppp, dataId);
+      }
+  
+      break;
+    }
+    case MAd_ESWAP:
+    case MAd_FSWAP: {
+      // nothing to be done (no modification at nodes)
+      break;
+    }
+    case MAd_RREMOVE: {
+      void * temp = NULL;
+      while ( pEntity pE = PList_next(before,&temp) ) {
+        if ( EN_type(pE) == 0 ) {
+          set<string>::const_iterator tIter = (*knownDataNames).begin();
+          set<string>::const_iterator tLast = (*knownDataNames).end();
+          for (; tIter != tLast; tIter++ ) {
+            pMeshDataId dataId = MD_lookupMeshDataId((*tIter).c_str());
+            void * data = NULL;
+            int gotit = EN_getDataPtr((pEntity)ppp, dataId,  &data);
+            vector<double> * vec = (vector<double>*) data;
+            if (gotit && vec) delete vec;
+            EN_deleteData((pVertex)pE, dataId);
+          }
+        }
+      }
+      break;
+    }
+    case MAd_UNKNOWNOPERATION:
+    case MAd_VERTEXMOVE:
+    case MAd_FCOLLAPSE:
+    case MAd_DESPLTCLPS:
+    default: {
+      printf("Error in NodalDataManager: Callback function not implemented for mesh modification %d",
+             type);  
+      throw;
+    }
+    }
+  
+  }
+
+  // -------------------------------------------------------------------
+  void NodalDataManager::initialize(pMesh m)
+  {
+    mesh = m;
+
+    prefix    = "NodalDataManagerId_";
+    prefixVec = prefix + "Vec_";
+
+    coordNameBase = "StoredCoordinates__";
+
+    if(knownDataNames )
+      {
+        knownDataNames->clear();
+      }
+    else
+      { 
+        knownDataNames= new set<string>();
+      }
+    if ( knownDataVecNames  )
+      {
+        knownDataVecNames->clear();
+      }
+    else
+      {
+        knownDataVecNames = new set<string>();
+      }
+
+    CallBackManagerSgl::instance().registerCallBack(P1CBFunction,   knownDataNames   );
+    CallBackManagerSgl::instance().registerCallBack(P1VecCBFunction,knownDataVecNames);
+  }
+
+  // -------------------------------------------------------------------
+  void NodalDataManager::setMesh(pMesh m)
+  {
+    mesh = m;
+  }
+
+  // -------------------------------------------------------------------
+  void NodalDataManager::finalize()
+  {
+    removeAllData();
+    if (knownDataNames) 
+      {
+        delete knownDataNames;
+        knownDataNames = NULL;
+      }
+    if (knownDataVecNames)
+      {
+        delete knownDataVecNames;
+        knownDataVecNames = NULL;
+      }
+  }
+
+  // -------------------------------------------------------------------
+  void NodalDataManager::diagnostics (ostream& out) const
+  {
+    out << "\nContent of the nodal data manager:\n";
+
+    out << "\n  - Double scalar : " << knownDataNames->size() << " fields:\n";
+    set<string>::iterator iIter;
+    set<string>::iterator iLast;
+    iIter = (*knownDataNames).begin();
+    iLast = (*knownDataNames).end();
+    for (; iIter != iLast; iIter++) {
+      out << "     - "<< *iIter << "\n";
+    }
+
+    out << "\n  - Double vector : " << knownDataVecNames->size() << " vector fields:\n";
+    iIter = (*knownDataVecNames).begin();
+    iLast = (*knownDataVecNames).end();
+    for (; iIter != iLast; iIter++) {
+      out << "     - "<< *iIter << "\n";
+    }
+  
+    out << "\n" << endl;
+  }
+
+  // -------------------------------------------------------------------
+  void NodalDataManager::removeAllData()
+  {
+    set<string>::iterator iIter;
+    set<string>::iterator iLast;
+
+    iIter = (*knownDataNames).begin();
+    iLast = (*knownDataNames).end();
+    for (; iIter != iLast; iIter++)  removeData(*iIter);
+
+    iIter = (*knownDataVecNames).begin();
+    iLast = (*knownDataVecNames).end();
+    for (; iIter != iLast; iIter++)  removeVData(*iIter);
+  }
+
+  // -------------------------------------------------------------------
+  void NodalDataManager::registerData(string name, const vector<double> datas)
+  {
+    string dataName = prefix + name;
+
+    // check that this name doesn't exists yet
+    if ( nameExists(dataName,0) ) {
+      cerr << "Error: this scalar data \'"<<name<<"\' is already registered in the NodalDataManager\n";
+      throw;
+    }
+
+    // check that the number of datas is equal to the number of nodes in the mesh
+    int nbDatas = datas.size();
+    if ( nbDatas != M_numVertices(mesh) ) {
+      cerr<< "Error: wrong number of datas ("<<nbDatas<<") with "<<M_numVertices(mesh)<<" nodes\n";
+      throw;
+    }
+
+    // add this name to the list
+    (*knownDataNames).insert(dataName);
+
+    // attach the data at nodes
+    pMeshDataId id = MD_lookupMeshDataId( dataName.c_str() );
+    int i = 0;
+    VIter vit = M_vertexIter(mesh);
+    while (pVertex pv = VIter_next(vit))
+      {
+        EN_attachDataDbl((pEntity)pv,id,datas[i]);
+        i++;
+      }
+    VIter_delete(vit);
+  }
+
+  // -------------------------------------------------------------------
+  void NodalDataManager::registerVData(string name, 
+                                       const vector<vector<double> > datas)
+  {
+    string dataName = prefixVec + name;
+
+    // check that this name doesn't exists yet
+    if ( nameExists(dataName,1) ) {
+      cerr << "Error: this vectorial data \'"<<name<<"\' is already registered in the NodalDataManager\n";
+      throw;
+    }
+
+    // check that the number of datas is equal to the number of nodes in the mesh
+    int nbDatas = datas.size();
+    if ( nbDatas != M_numVertices(mesh) ) {
+      cerr<< "Error: wrong number of datas ("<<nbDatas<<") with "<<M_numVertices(mesh)<<" nodes\n";
+      throw;
+    }
+
+    // add this name to the list
+    (*knownDataVecNames).insert(dataName);
+
+    // attach the data at nodes
+    pMeshDataId id = MD_lookupMeshDataId( dataName.c_str() );
+    int i = 0;
+    VIter vit = M_vertexIter(mesh);
+    while (pVertex pv = VIter_next(vit))
+      {
+        vector<double> * copy = new vector<double>(datas[i]);
+        EN_attachDataPtr((pEntity)pv,id,copy);
+        i++;
+      }
+    VIter_delete(vit);
+  }
+
+  // -------------------------------------------------------------------
+  void NodalDataManager::getMeshData(string name, vector<double> * result) const
+  {
+    string dataName = prefix + name;
+
+    // check that this name exists
+    if ( !nameExists(dataName,0) ) {
+      cerr << "Error: this scalar data \'"<<name<<"\' is not registered in the NodalDataManager\n";
+      throw;
+    }
+
+    result->clear();
+
+    pMeshDataId id = MD_lookupMeshDataId( dataName.c_str() );
+  
+    int i = 0;
+    VIter vit = M_vertexIter(mesh);
+    while (pVertex pv = VIter_next(vit))
+      {
+        double theDbl;
+        EN_getDataDbl((pEntity)pv,id,&theDbl);
+        result->push_back(theDbl);
+        i++;
+      }
+    VIter_delete(vit);
+  }
+
+  // -------------------------------------------------------------------
+  void NodalDataManager::getMeshVData(string name, vector<vector<double> > * result) const
+  {
+    string dataName = prefixVec + name;
+
+    // check that this name exists
+    if ( !nameExists(dataName,1) ) {
+      cerr << "Error: this vectorial data \'"<<name<<"\' is not registered in the NodalDataManager\n";
+      throw;
+    }
+
+    result->clear();
+
+    pMeshDataId id = MD_lookupMeshDataId( dataName.c_str() );
+  
+    int i = 0;
+    VIter vit = M_vertexIter(mesh);
+    while (pVertex pv = VIter_next(vit))
+      {
+        void * tmp = 0;
+        EN_getDataPtr((pEntity)pv,id,&tmp);
+        vector<double> * vec = (vector<double>*) tmp;
+        result->push_back(*vec);
+        i++;
+      }
+    VIter_delete(vit);
+  }
+
+  // -------------------------------------------------------------------
+  void NodalDataManager::getData(string name, pVertex pv, double* res) const
+  {
+    string dataName = prefix + name;
+
+    // check that this name exists
+    if ( !nameExists(dataName,0) ) {
+      cerr << "Error: this scalar data \'"<<name<<"\' is not registered in the NodalDataManager\n";
+      throw;
+    }
+
+    pMeshDataId id = MD_lookupMeshDataId( dataName.c_str() );
+  
+    EN_getDataDbl((pEntity)pv,id,res);
+  }
+
+  // -------------------------------------------------------------------
+  void NodalDataManager::getVData(string name, pVertex pv, vector<double>& res) const
+  {
+    string dataName = prefixVec + name;
+
+    // check that this name exists
+    if ( !nameExists(dataName,1) ) {
+      cerr << "Error: this vectorial data \'"<<name<<"\' is not registered in the NodalDataManager\n";
+      throw;
+    }
+
+    pMeshDataId id = MD_lookupMeshDataId( dataName.c_str() );
+  
+    void * tmp = 0;
+    EN_getDataPtr((pEntity)pv,id,&tmp);
+    res.clear();
+    for (int i=0; i<3; i++) res.push_back(  (*( (vector<double>*) tmp))[i]  );
+
+  }
+
+  // -------------------------------------------------------------------
+  void NodalDataManager::removeData(string name)
+  {
+    string dataName = prefix + name;
+
+    if ( !nameExists(dataName,0) )  return;
+
+    // remove it from the list of names
+    set<string>::iterator iIter = (*knownDataNames).find(dataName);
+    (*knownDataNames).erase(iIter);
+
+    // delete the datas at nodes
+    pMeshDataId id = MD_lookupMeshDataId( (dataName).c_str() );
+    VIter vit = M_vertexIter(mesh);
+    while (pVertex pv = VIter_next(vit))
+      {
+        EN_deleteData((pEntity)pv,id);
+      }
+    VIter_delete(vit);
+  }
+
+  // -------------------------------------------------------------------
+  void NodalDataManager::removeVData(string name)
+  {
+    string dataName = prefixVec + name;
+
+    if ( !nameExists(dataName,1) )  return;
+
+    // remove it from the list of names
+    set<string>::iterator iIter = (*knownDataVecNames).find(dataName);
+    (*knownDataVecNames).erase(iIter);
+
+    // delete the datas at nodes
+    pMeshDataId id = MD_lookupMeshDataId( dataName.c_str() );
+    VIter vit = M_vertexIter(mesh);
+    while (pVertex pv = VIter_next(vit))
+      {
+        void * data = NULL;
+        int gotit = EN_getDataPtr((pEntity)pv, id,  &data);
+        vector<double> * vec = (vector<double>*) data;
+        if (gotit && vec) delete vec;
+        EN_deleteData((pEntity)pv, id);
+      }
+    VIter_delete(vit);
+  }
+
+  // -------------------------------------------------------------------
+  void NodalDataManager::writeData(string name, const char *fn)
+  {
+    string dataName = prefix + name;
+
+    // check that this name exists
+    if ( !nameExists(dataName,0) ) {
+      cerr << "Error: this data \'"<<name<<"\' is not registered in the NodalDataManager\n";
+      throw;
+    }
+
+    pMeshDataId id = MD_lookupMeshDataId( dataName.c_str() );
+  
+    MAdAttachedNodalDataOutput(mesh, fn, id);
+  }
+
+  // -------------------------------------------------------------------
+  void NodalDataManager::writeVData(string name, const char *fn)
+  {
+    string dataName = prefixVec + name;
+
+    // check that this name exists
+    if ( !nameExists(dataName,1) ) {
+      cerr << "Error: this data \'"<<name<<"\' is not registered in the NodalDataManager\n";
+      throw;
+    }
+
+    pMeshDataId id = MD_lookupMeshDataId( dataName.c_str() );
+  
+    MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+                                  "Output for vectorial attached data is not implemented");
+    // it is implemented for double arrays, not vectors. 
+    // This class should store double arrays too, to be done (GC).
+    //    MAdAttachedNodalDataVecOutput(mesh, fn, id);
+  }
+
+  // -------------------------------------------------------------------
+  void NodalDataManager::storeCoordinates()
+  {
+    removeCoordinates();
+
+    // add the coordinates name to the list
+    string coordName = prefixVec + coordNameBase;
+    (*knownDataVecNames).insert(coordName);
+
+    // attach the data at nodes
+    pMeshDataId id = MD_lookupMeshDataId( coordName.c_str() );
+    VIter vit = M_vertexIter(mesh);
+    while (pVertex pv = VIter_next(vit))
+      {
+        double xyz[3]; V_coord(pv,xyz);
+        vector<double> * vec = new vector<double>;
+        for (int j = 0; j<3; j++)  (*vec).push_back(xyz[j]);
+        EN_attachDataPtr((pEntity)pv,id,vec);
+      }
+    VIter_delete(vit);
+  }
+
+  // -------------------------------------------------------------------
+  void NodalDataManager::getStoredCoordinates(pVertex pv, vector<double>& res)
+  {
+    getVData(coordNameBase,pv,res);
+  }
+
+  // -------------------------------------------------------------------
+  void NodalDataManager::removeCoordinates()
+  {
+    removeVData(coordNameBase);
+  }
+
+  // -------------------------------------------------------------------
+  bool NodalDataManager::isCoordinates()
+  {
+    string coordName = prefixVec + coordNameBase;
+    return nameExists(coordName,1);
+  }
+
+  // -------------------------------------------------------------------
+
+  bool NodalDataManager::nameExists(string dataName, int vec) const
+  {
+    if ( vec == 0 ) {
+      set<string>::iterator iIter = (*knownDataNames).find(dataName);
+      if ( iIter == (*knownDataNames).end() ) return false;
+      else return true;
+    }
+    if ( vec == 1 ) {
+      set<string>::iterator iIter = (*knownDataVecNames).find(dataName);
+      if ( iIter == (*knownDataVecNames).end() ) return false;
+      else return true;
+    }
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Adapt/utils/NodalDataManager.h b/Adapt/utils/NodalDataManager.h
new file mode 100644
index 0000000..ad4cbd7
--- /dev/null
+++ b/Adapt/utils/NodalDataManager.h
@@ -0,0 +1,103 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_NODALDATAMANAGER
+#define _H_NODALDATAMANAGER
+
+#include "MSops.h"
+
+#include "MAdSingleton.h"
+
+#include <vector>
+#include <string>
+#include <set>
+#include <iostream>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+
+  class NodalDataManager {
+
+  public:
+  
+    NodalDataManager():mesh(NULL),
+                       knownDataNames(NULL), knownDataVecNames(NULL){};
+    ~NodalDataManager() {};
+  
+    void initialize(pMesh m);
+    void setMesh(pMesh m);
+    void finalize();
+
+    void removeAllData();
+
+    void diagnostics (std::ostream& out) const;
+
+    // will attach the datas to the nodes of the mesh
+    // order in vector is the node iterator order
+    void registerData  (std::string name, const std::vector<double>);
+    void registerVData (std::string name, const std::vector<std::vector<double> >);
+
+    // will fill the variable with the datas attached to the nodes
+    // this function does not allocate memory
+    // order in vector is the node iterator order
+    void getMeshData  (std::string name, std::vector<double> *)          const;
+    void getMeshVData (std::string name, std::vector<std::vector<double> > *) const;
+
+    // get the data at a node
+    void getData  (std::string name, pVertex pv, double* res)         const;
+    void getVData (std::string name, pVertex pv, std::vector<double>& res) const;
+
+    // will delete the data attached to the nodes
+    void removeData  (std::string name);
+    void removeVData (std::string name);
+
+    // write the data in a postprocessing file
+    void writeData  (std::string name, const char *fn);
+    void writeVData (std::string name, const char *fn);
+
+    // functions to keep track of the initial coordinates
+    void storeCoordinates();
+    void getStoredCoordinates(pVertex pv, std::vector<double>& res);
+    void removeCoordinates();
+    bool isCoordinates();
+  
+  private:
+
+    pMesh mesh;
+
+    // prefix for identification of the datas from this manager
+    // ensures there is no clash with other datas
+    std::string prefix;
+    std::string prefixVec;
+
+    // identifier for the coordinates
+    std::string coordNameBase;
+
+    // stored with the prefix
+    std::set<std::string>* knownDataNames;
+    std::set<std::string>* knownDataVecNames;
+
+  private:
+
+    bool nameExists(std::string name, int vec) const;
+
+  };
+
+  // -------------------------------------------------------------------
+
+  typedef MAdSingleton<NodalDataManager> NodalDataManagerSgl;
+
+}
+
+#endif
diff --git a/Benchmarks/meshInfo/Makefile b/Benchmarks/meshInfo/Makefile
new file mode 100644
index 0000000..d7c290d
--- /dev/null
+++ b/Benchmarks/meshInfo/Makefile
@@ -0,0 +1,59 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information. 
+# You should have received a copy of these files along with MAdLib. 
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../../variables
+
+BIN = $(MAdROOT)/bin/meshInfo
+
+INC =  ${MAdLib_INCLUDES}\
+       ${DASH}I$(MAdROOT)/Geo\
+       ${DASH}I$(MAdROOT)/Mesh\
+       ${DASH}I$(MAdROOT)/Common\
+       ${DASH}I$(MAdROOT)/Adapt\
+       ${DASH}I$(MAdROOT)/Adapt/constraint\
+       ${DASH}I$(MAdROOT)/Adapt/operator\
+       ${DASH}I$(MAdROOT)/Adapt/output\
+       ${DASH}I$(MAdROOT)/Adapt/quality\
+       ${DASH}I$(MAdROOT)/Adapt/repositioning\
+       ${DASH}I$(MAdROOT)/Adapt/sizeField\
+       ${DASH}I$(MAdROOT)/Adapt/utils
+
+ALLFLAGS = ${OPTIM} ${CXXFLAGS} ${MAdLib_DEFS} ${FLAGS} ${INC} ${SYSINCLUDE}
+
+SRC = main.cc
+
+OBJ = ${SRC:.cc=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cc
+
+${BIN}: ${OBJ}
+	${LINKER} ${OPTIM} ${DASH}o $@ $(OBJ) ${MAdLib_LIBS}
+
+cpobj: ${OBJ} 
+	cp -f ${OBJ} $(MAdROOT)/bin/
+
+.cc${OBJEXT}:
+	${CXX} ${ALLFLAGS} ${DASH}c $< ${DASH}o $@
+
+clean:
+	${RM} *.o *.obj
+
+purge:
+	${RM} *.msh *.geo *.pos
+
+depend:
+	(sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+         ${CXX} -MM ${ALLFLAGS} ${SRC} | sed 's/.o:/$${OBJEXT}:/g' \
+        ) > Makefile.new
+	cp Makefile Makefile.bak
+	cp Makefile.new Makefile
+	rm -f Makefile.new
\ No newline at end of file
diff --git a/Benchmarks/meshInfo/main.cc b/Benchmarks/meshInfo/main.cc
new file mode 100644
index 0000000..b5372dd
--- /dev/null
+++ b/Benchmarks/meshInfo/main.cc
@@ -0,0 +1,123 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MSops.h"
+#include "AdaptInterface.h"
+#include "NullSField.h"
+#include "AnalyticalSField.h"
+#include "MAdResourceManager.h"
+#include "MAdLib.h"
+
+#include <iostream>
+using std::cout;
+#include <sys/resource.h>
+#include <string>
+using std::string;
+
+using namespace MAd;
+
+#ifdef PARALLEL
+#include "mpi.h"
+#endif
+
+// ----------------------------------------------------------------------
+void displayMemoryUsage(string step="")
+{
+  MAdResourceManagerSgl::instance().printMemoryUsage(step,std::cout);
+}
+
+// ----------------------------------------------------------------------
+int main(int argc, char* argv[]) {
+
+  MAdLibInitialize(&argc, &argv);
+
+  displayMemoryUsage("initialized");
+
+  // Check input
+  // ------------
+  if ( argc != 3 && argc != 2  ) {
+    printf("Error: usage: \'executable mshFile [geoFile]\'\n");
+    exit(0);
+  }
+  string meshFile = argv[1];
+
+  // Build tools
+  // ------------
+  printf ("Analyzing mesh %s...\n\n",meshFile.c_str());
+
+  // --- Reading model ---
+  pGModel model = 0;
+  GM_create(&model,"theModel");
+  
+  if ( argc == 3 ) {
+    string geoFile  = argv[2];
+    GM_readFromGEO(model, geoFile.c_str());
+  }
+  else {
+    GM_readFromMSH(model, meshFile.c_str());
+  }
+
+  displayMemoryUsage("built model");
+
+  pMesh mesh = M_new(model);
+  M_load(mesh,meshFile.c_str());
+
+  displayMemoryUsage("built mesh");
+
+  SizeFieldBase * sizeField = new AnalyticalSField("1.");
+  
+  MeshAdapter* ma = new MeshAdapter(mesh,sizeField);
+
+  displayMemoryUsage("built adapter");
+
+  // temporary info
+//   int nbVolEdges = 0;
+//   int dim = M_dim(mesh);
+//   int numR[20];
+//   for (int i=0; i<20; i++) numR[i]=0;
+//   EIter ei = M_edgeIter(mesh);
+//   while ( pEdge edge = EIter_next(ei) ) {
+//     if ( E_whatInType(edge) == dim ) {
+//       int num = E_numRegions(edge);
+//       numR[num] = numR[num]++;
+//       nbVolEdges++;
+//     }
+//   }
+//   EIter_delete(ei);
+//   printf("Num points in edges crown:\n");
+//   printf("Edges: %d\n",nbVolEdges);
+  
+//   for (int i=0; i<20; i++) {
+//     double ratio = ( (double) (numR[i]) ) / ( (double)nbVolEdges );
+//     printf("%d\t%d\t%f\n",i,numR[i],ratio);
+//   }
+//   printf("\n");
+
+
+  // Outputs
+  // --------
+  ma->printStatistics(std::cout);
+  ma->writePos("meanRatio.pos",OD_MEANRATIO);
+
+  // Cleaning
+  // ---------
+  if (ma) delete ma;
+  if (sizeField) delete sizeField;
+  M_delete(mesh);
+  GM_delete(model);
+
+  displayMemoryUsage("cleaned");
+
+  MAdLibFinalize();
+}
+
+// ----------------------------------------------------------------------
diff --git a/Benchmarks/moveIt/Makefile b/Benchmarks/moveIt/Makefile
new file mode 100644
index 0000000..995be41
--- /dev/null
+++ b/Benchmarks/moveIt/Makefile
@@ -0,0 +1,59 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information. 
+# You should have received a copy of these files along with MAdLib. 
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../../variables
+
+BIN = $(MAdROOT)/bin/moveIt
+
+INC =  ${MAdLib_INCLUDES}\
+       ${DASH}I$(MAdROOT)/Geo\
+       ${DASH}I$(MAdROOT)/Mesh\
+       ${DASH}I$(MAdROOT)/Common\
+       ${DASH}I$(MAdROOT)/Adapt\
+       ${DASH}I$(MAdROOT)/Adapt/constraint\
+       ${DASH}I$(MAdROOT)/Adapt/operator\
+       ${DASH}I$(MAdROOT)/Adapt/output\
+       ${DASH}I$(MAdROOT)/Adapt/quality\
+       ${DASH}I$(MAdROOT)/Adapt/repositioning\
+       ${DASH}I$(MAdROOT)/Adapt/sizeField\
+       ${DASH}I$(MAdROOT)/Adapt/utils
+
+ALLFLAGS = ${OPTIM} ${CXXFLAGS} ${MAdLib_DEFS} ${FLAGS} ${INC} ${SYSINCLUDE}
+
+SRC = main.cc
+
+OBJ = ${SRC:.cc=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cc
+
+${BIN}: ${OBJ}
+	${LINKER} ${OPTIM} ${DASH}o $@ $(OBJ) ${MAdLib_LIBS}
+
+cpobj: ${OBJ} 
+	cp -f ${OBJ} $(MAdROOT)/bin/
+
+.cc${OBJEXT}:
+	${CXX} ${ALLFLAGS} ${DASH}c $< ${DASH}o $@
+
+clean:
+	${RM} *.o *.obj
+
+purge:
+	${RM} *.msh *.geo *.pos MyParams.h example/tube/result/*
+
+depend:
+	(sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+         ${CXX} -MM ${ALLFLAGS} ${SRC} | sed 's/.o:/$${OBJEXT}:/g' \
+        ) > Makefile.new
+	cp Makefile Makefile.bak
+	cp Makefile.new Makefile
+	rm -f Makefile.new
\ No newline at end of file
diff --git a/Benchmarks/moveIt/Parameters.h b/Benchmarks/moveIt/Parameters.h
new file mode 100644
index 0000000..98b29a8
--- /dev/null
+++ b/Benchmarks/moveIt/Parameters.h
@@ -0,0 +1,246 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_PARAMETERS
+#define _H_PARAMETERS
+
+#include "AdaptInterface.h"
+#include "SizeFieldBase.h"
+#include "LocalSizeField.h"
+
+#include <string.h>
+using std::string;
+#include <list>
+#include <set>
+#include <vector>
+using std::vector;
+
+// ----------------------------------------------------------------------
+enum KinematicType {
+  KT_DISPLACEMENT,
+  KT_VELOCITY
+};
+
+// ----------------------------------------------------------------------
+enum OrientationType {
+  ORT_ISOTROPIC,
+  ORT_ANISOTROPIC
+};
+
+// ----------------------------------------------------------------------
+// ----------------------------------------------------------------------
+struct LocalSFDef {
+  string name;
+  bool distToFaces;
+  bool isotropic;
+  double radius;
+  string sizeN, sizeT;
+  bool limit;
+  double limitSizeTg;
+  double maxCurv;
+};
+
+// ----------------------------------------------------------------------
+struct SizeFieldDef
+{
+  MAd::sFieldType type; // analytical or piecewise linear
+
+  // analytical size fields
+  OrientationType orientation;
+  string isoSize;
+  vector<string> anisoSize;
+  vector<string> anisoDir0, anisoDir1, anisoDir2;
+
+  // piecewise linear size fields
+  string pwlSource; // curvature or initial length
+  
+  // curvature parameters
+  bool curv_aniso;
+  double curv_alpha, curv_hMin;
+};
+
+// ----------------------------------------------------------------------
+struct ObjectDef {
+
+  string name;
+
+  // geometry
+  int geomLevel; // 0=point,1=line,2=surface,3=region
+  std::set<int> geomTags;
+
+  // kinematics
+  KinematicType kinType;
+  vector<string> kinExpression;
+
+  // size fields
+  std::list<LocalSFDef> sizes;
+};
+
+// ----------------------------------------------------------------------
+struct MoveParameters {
+  
+  // global input specifications
+  // ---------------------------
+
+  string meshFileName;
+  string geoFileName;
+  
+  // global output parameters
+  // ------------------------
+
+  int outFrequency;
+  string outType; // "Msh", "Pos" or "MshAndPos"(def)
+  string outPrefix;
+
+  // Global task parameters
+  // ----------------------
+
+  string task; // MobileObject(def),...
+
+  // debugging parmeters
+  // --------------------
+
+  int debugLevel;
+  bool openJournal;
+  string referenceJournal;
+  bool sliverReports;
+  bool testSliverOperators;
+
+  // Mesh adaptation
+  // ----------------
+
+  int maxInnerIter;
+  double lowerLength, upperLength;
+  double infLength;
+  double swapMinImproveRatio;
+  double sliverQuality;
+
+  bool splitCanMakeSlivers, collapseCanMakeSlivers;
+  double makeSliverInSplitLenSqBound, makeSliverInCollapseLenSqBound;
+
+  bool collapseOnBoundary;
+  double clpOnBdryTolerance;
+
+  bool swapOnBoundary;
+  double swapOnBdryTolerance;
+
+  bool trackGeometry;
+  bool   snap_cavityIsMesh;
+  int    snap_thickness;
+  double snap_chi;
+
+  bool SFSmoothing;
+  double SFSmoothGrad;
+
+  // Moving objects
+  // --------------
+
+  std::vector<ObjectDef> objects;
+
+  // Size Field parameters
+  // ---------------------
+
+  std::list<SizeFieldDef> sizes;
+  
+  // Node motion
+  // -----------
+
+  string nodeMotionType; // None(def), ForceBoundaries, ElasticAnalogy
+  bool   elasticIsMeshTheCavity;
+  int    elasticCavityThickness;
+  double elasticStiffnessAlteration;
+
+  // Time parameters
+  // ---------------
+
+  int maxNbTimeSteps;
+  double timeStep;
+  double finalTime;
+
+};
+
+// ----------------------------------------------------------------------
+// this function set the parameters to the values of a particular test case
+extern void setCurrentParameters(MoveParameters *);
+
+// ----------------------------------------------------------------------
+void setDefaultParameters(MoveParameters * params)
+{
+  params->meshFileName = "";
+  params->geoFileName = "";
+
+  params->outFrequency = 1;
+  params->outType = "MshAndPos";
+  params->outPrefix  = "result/";
+
+  params->task = "MobileObject";
+
+  params->debugLevel = 1;
+  params->openJournal = false;
+  params->referenceJournal = "";
+  params->sliverReports = false;
+  params->testSliverOperators = false;
+
+  params->maxInnerIter = 10;
+  params->lowerLength = 1./sqrt(3.);
+  params->upperLength = sqrt(3.);
+  params->infLength = 1.e14;
+  params->swapMinImproveRatio = 1.0;
+  params->sliverQuality = 0.02;
+
+  params->splitCanMakeSlivers = true;
+  params->makeSliverInSplitLenSqBound = 10.;
+  params->collapseCanMakeSlivers = true;
+  params->makeSliverInCollapseLenSqBound = 0.1;
+
+  params->collapseOnBoundary = true;
+  params->clpOnBdryTolerance = 1.e-6;
+
+  params->swapOnBoundary = true;
+  params->swapOnBdryTolerance = 1.e-6;
+
+  params->trackGeometry = false;
+  params->snap_cavityIsMesh = false;
+  params->snap_thickness = 3;
+  params->snap_chi = 1.;
+
+  params->SFSmoothing = false;
+  params->SFSmoothGrad = 1.;
+
+  params->objects.clear();
+
+  params->sizes.clear();
+
+  params->nodeMotionType = "None";
+  params->elasticIsMeshTheCavity = true;
+  params->elasticCavityThickness = 3;
+  params->elasticStiffnessAlteration = 1.0;
+
+  params->maxNbTimeSteps = 1000000;
+  params->timeStep = 0.1;
+  params->finalTime = -1.0;
+}
+
+// ----------------------------------------------------------------------
+MoveParameters getParameters()
+{
+  MoveParameters params;
+  setDefaultParameters(&params);
+  setCurrentParameters(&params);
+
+  return params;
+}
+
+// ----------------------------------------------------------------------
+
+#endif
diff --git a/Benchmarks/moveIt/README b/Benchmarks/moveIt/README
new file mode 100644
index 0000000..7390d7b
--- /dev/null
+++ b/Benchmarks/moveIt/README
@@ -0,0 +1,32 @@
+MAdLib - Benchmarks - moveIt
+
+Description
+------------
+
+This benchmark allows to define a motion of the domain boundaries 
+and adapt the mesh accordingly. 
+
+How to use it ?
+----------------
+
+The parameters of the computations are defined in a file called 
+'MyParams.h' which has to be located in this directory and will 
+be included during the compilation of the executable. 
+You can make a link to the .h file you defined in a subdirectory
+for instance.
+
+The 'MyParams.h' file has to be written according to the template 
+defined in 'Parameters.h'.
+
+In the 'MyParams.h' file, a target mesh file with a '.msh' 
+extension is required. In order to produce it, download Gmsh at 
+<http://www.geuz.org/gmsh> and run:
+
+gmsh -3 -optimize 'the_geo_file'
+
+where 'the_geo_file' is a file with a '.geo' extension, the 
+native CAD file format of Gmsh.
+
+Once the executable is compiled, run it without any argument. The 
+output will be produced and stored according to the parameters 
+contained in the 'MyParams.h' file at the time of the compilation.
diff --git a/Benchmarks/moveIt/examples/tube/MyParams.h b/Benchmarks/moveIt/examples/tube/MyParams.h
new file mode 100644
index 0000000..20e567b
--- /dev/null
+++ b/Benchmarks/moveIt/examples/tube/MyParams.h
@@ -0,0 +1,199 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MYPARAMS
+#define _H_MYPARAMS
+
+#include "Parameters.h"
+
+// ----------------------------------------------------------------------
+void setCurrentParameters(MoveParameters * params) {
+
+  params->meshFileName = "tube.msh";
+//   params->geoFileName="tube_fullGeo.geo";
+  
+  // global output parameters
+  // ------------------------
+
+  params->outFrequency = 10;
+  params->outType = "Msh"; // "Msh", "Pos" or "MshAndPos"
+  params->outPrefix = "result/";
+
+  // Global task parameters
+  // ----------------------
+
+  params->task = "MobileObject";
+
+  // debugging parmeters
+  // --------------------
+
+  params->debugLevel = 0;
+  params->openJournal = false;
+  params->referenceJournal = "";
+  params->sliverReports = false;
+  params->testSliverOperators = false;
+
+  // Mesh adaptation
+  // ----------------
+
+  params->maxInnerIter = 10;
+  params->lowerLength = 0.577;
+  params->upperLength = 1.732;
+  params->swapMinImproveRatio = 1.0;
+  params->sliverQuality = 0.02;
+  params->splitCanMakeSlivers = true;
+  params->makeSliverInSplitLenSqBound = 0.1;
+  params->collapseCanMakeSlivers = true;
+  params->makeSliverInCollapseLenSqBound = 10.;
+  params->collapseOnBoundary = true;
+  params->clpOnBdryTolerance = 1.e-6;
+  params->swapOnBoundary = true;
+  params->swapOnBdryTolerance = 1.e2;
+  params->trackGeometry = false;
+//   params->snap_cavityIsMesh = false;
+//   params->snap_thickness = 3;
+//   params->snap_chi = 1.;
+  
+  params->SFSmoothing = true;
+  params->SFSmoothGrad = 1.;
+
+  // Node motion
+  // -----------
+
+  params->nodeMotionType = "ElasticAnalogy";
+  params->elasticStiffnessAlteration = 1.0;
+  params->elasticIsMeshTheCavity = true;
+  params->elasticCavityThickness = 0;
+
+  // Time parameters
+  // ---------------
+
+  params->timeStep = 0.01;
+  params->finalTime = 4.0;
+//   params->maxNbTimeSteps = 1;
+
+  
+  // Moving objects
+  // --------------
+
+  // --- The cylinder ---
+
+  ObjectDef cylinder;
+  cylinder.name = "Cylinder";
+  cylinder.geomLevel = 2;
+  cylinder.geomTags.insert(8);
+  cylinder.geomTags.insert(12);
+  cylinder.geomTags.insert(16);
+  cylinder.geomTags.insert(20);
+  cylinder.geomTags.insert(22);
+  cylinder.geomTags.insert(126);
+  cylinder.kinType = KT_VELOCITY;
+  cylinder.kinExpression.push_back("0.");
+  cylinder.kinExpression.push_back("0.");
+  cylinder.kinExpression.push_back("1.*sign(sin(2.*3.14159265/8.*t+1.e-6))");
+
+  LocalSFDef localSFCyl;
+  localSFCyl.name = "CylinderSF";
+	localSFCyl.radius = 1.;
+  localSFCyl.distToFaces = false;
+  localSFCyl.isotropic = true;
+  localSFCyl.sizeN = "0.1+0.5*x";
+
+  cylinder.sizes.push_back(localSFCyl);
+
+  params->objects.push_back(cylinder);
+
+  // --- The tube ---
+
+  ObjectDef tube;
+  tube.name = "Tube";
+  tube.geomLevel = 2;
+  tube.geomTags.insert(40);
+  tube.geomTags.insert(44);
+  tube.geomTags.insert(48);
+  tube.geomTags.insert(52);
+  tube.geomTags.insert(56);
+  tube.geomTags.insert(60);
+  tube.geomTags.insert(64);
+  tube.geomTags.insert(68);
+  tube.geomTags.insert(71);
+  tube.geomTags.insert(106);
+  tube.kinType = KT_VELOCITY;
+  tube.kinExpression.push_back("0.");
+  tube.kinExpression.push_back("0.");
+  tube.kinExpression.push_back("-1.*sign(sin(2.*3.14159265/8.*t+1.e-6))");
+
+  LocalSFDef localSFTube;
+  localSFTube.name = "tubeSF";
+	localSFTube.radius = 1.;
+  localSFTube.distToFaces = false;
+  localSFTube.isotropic = true;
+  localSFTube.sizeN = "0.2+0.4*x";
+
+  tube.sizes.push_back(localSFTube);
+
+  params->objects.push_back(tube);
+
+  // --- The box ---
+
+//   ObjectDef box;
+//   box.name = "Box";
+//   box.geomLevel = 2;
+//   box.geomTags.insert(110);
+//   box.geomTags.insert(114);
+//   box.geomTags.insert(118);
+//   box.geomTags.insert(122);
+//   box.geomTags.insert(124);
+//   box.geomTags.insert(131);
+//   box.kinType = KT_DISPLACEMENT;
+//   box.kinExpression.push_back("0.");
+//   box.kinExpression.push_back("0.");
+//   box.kinExpression.push_back("0.");
+
+//   params->objects.push_back(box);
+
+  // Size Field parameters
+  // ---------------------
+
+  SizeFieldDef analSF;
+  analSF.type = MAd::ANALYTICALSFIELD;
+  analSF.orientation = ORT_ISOTROPIC;
+  analSF.isoSize = "0.6";
+//   analSF.orientation = ORT_ANISOTROPIC;
+//   vector<string> myAnisoSize;
+//   myAnisoSize.push_back("0.3");
+//   myAnisoSize.push_back("0.6");
+//   myAnisoSize.push_back("0.6");
+//   analSF.anisoSize = myAnisoSize;
+//   vector<string> anisoDir0;
+//   anisoDir0.push_back("1.");
+//   anisoDir0.push_back("0.");
+//   anisoDir0.push_back("0.");
+//   analSF.anisoDir0 = anisoDir0;
+//   vector<string> anisoDir1;
+//   anisoDir1.push_back("0.");
+//   anisoDir1.push_back("1.");
+//   anisoDir1.push_back("0.");
+//   analSF.anisoDir1 = anisoDir1;
+//   vector<string> anisoDir2;
+//   anisoDir2.push_back("0.");
+//   anisoDir2.push_back("0.");
+//   anisoDir2.push_back("1.");
+//   analSF.anisoDir2 = anisoDir2;
+
+  params->sizes.push_back(analSF);
+}
+
+// ----------------------------------------------------------------------
+
+#endif
diff --git a/Benchmarks/moveIt/examples/tube/result/quality b/Benchmarks/moveIt/examples/tube/result/quality
new file mode 100644
index 0000000..fe2a50c
--- /dev/null
+++ b/Benchmarks/moveIt/examples/tube/result/quality
@@ -0,0 +1,3 @@
+iter	mean quality	worst quality
+0	0.559586	1.71371e-06
+0	5.759428e-01	2.011903e-02
diff --git a/Benchmarks/moveIt/examples/tube/tube.geo b/Benchmarks/moveIt/examples/tube/tube.geo
new file mode 100644
index 0000000..a3c0d17
--- /dev/null
+++ b/Benchmarks/moveIt/examples/tube/tube.geo
@@ -0,0 +1,85 @@
+// -*- C++ -*-
+
+lc1 = 0.1;//0.1
+lc2 = 0.2;//0.4
+lcBox = 0.6;//0.6
+
+// cylinders parameters
+r = 0.9;
+R = 1.;
+dR = 0.2;
+L1 = 3.;
+L2 = 3.;
+dL = 1.;
+
+// external box parameters
+B1 = 2.;
+B2 = 2.;
+B3 = 3.;
+
+// first cylinder (small one)
+Point(1) = {0,0,0,lc1};
+Point(2) = {r,0,0,lc1};
+Point(3) = {0,r,0,lc1};
+Point(4) = {0,-r,0,lc1};
+Point(5) = {-r,0,0,lc1};
+Circle(1) = {2,1,3};
+Circle(2) = {3,1,5};
+Circle(3) = {5,1,4};
+Circle(4) = {4,1,2};
+Extrude {0,0,L1} {
+  Line{3,2,1,4};
+}
+Line Loop(21) = {13,9,5,17};
+Plane Surface(22) = {21};
+
+// tube
+Point(20) = {R,0,L1+dL,lc2};
+Point(21) = {-R,0,L1+dL,lc2};
+Point(22) = {0,R,L1+dL,lc2};
+Point(23) = {0,-R,L1+dL,lc2};
+Point(24) = {0,-R-dR,L1+dL,lc2};
+Point(25) = {0,+R+dR,L1+dL,lc2};
+Point(26) = {R+dR,0,L1+dL,lc2};
+Point(27) = {-R-dR,0,L1+dL,lc2};
+Point(28) = {0,0,L1+dL,lc2};
+Circle(29) = {23,28,20};
+Circle(30) = {20,28,22};
+Circle(31) = {22,28,21};
+Circle(32) = {21,28,23};
+Circle(33) = {24,28,26};
+Circle(34) = {26,28,25};
+Circle(35) = {25,28,27};
+Circle(36) = {27,28,24};
+Extrude {0,0,L2} {
+  Line{36,33,34,35,31,30,29,32};
+}
+Line Loop(69) = {45,49,37,41};
+Line Loop(70) = {53,65,61,57};
+Plane Surface(71) = {69,70};
+Line Loop(104) = {35,36,33,34};
+Line Loop(105) = {32,29,30,31};
+Plane Surface(106) = {104,105};
+
+// // external box
+Point(62) = {B3,B3,-B1,lcBox};
+Point(63) = {-B3,B3,-B1,lcBox};
+Point(64) = {-B3,-B3,-B1,lcBox};
+Point(65) = {B3,-B3,-B1,lcBox};
+Line(82) = {64,63};
+Line(83) = {63,62};
+Line(84) = {62,65};
+Line(85) = {65,64};
+Extrude {0,0,B1+L1+dL+L2+B2} {
+  Line{82,83,84,85};
+}
+Line Loop(123) = {107,111,115,119};
+Plane Surface(124) = {123};
+Line Loop(125) = {2,3,4,1};
+Plane Surface(126) = {125};
+Line Loop(130) = {84,85,82,83};
+Plane Surface(131) = {130};
+Surface Loop(132) = {124,110,131,118,122,114};
+Surface Loop(133) = {52,106,40,44,48,71,60,56,68,64};
+Surface Loop(134) = {12,126,8,20,16,22};
+Volume(135) = {132,133,134};
diff --git a/Benchmarks/moveIt/examples/tube/tube.mad b/Benchmarks/moveIt/examples/tube/tube.mad
new file mode 100644
index 0000000..c80e3a0
--- /dev/null
+++ b/Benchmarks/moveIt/examples/tube/tube.mad
@@ -0,0 +1,144 @@
+//-*- C++ -*-
+
+Input {
+  Mesh {
+    MshFile = "tube.msh"; // gmsh -3 -optimize tube.geo
+    //GeoFile = "tube.geo";
+    //MshFile = "tube_fullGeo.msh"; // gmsh -3 -optimize tube_fullGeo.geo -parametric
+    //GeoFile = "tube_fullGeo.geo";
+  }
+}
+Output {
+  Prefix = "result/";
+  Frequency = 100;
+  Type = Msh;
+}
+Task {
+  Type = MobileObject; // RemoveRegion SizeField RemoveSliverFaces LaplaceSmoothing GeoConstraints TopoConstraints FaceSwap UglyMesh RemoveSliverRegions DESC EdgeSwap GeoMatcher EdgeSplit EdgeCollapse EdgeSplitCollapse FaceCollapse OptimizeLength OptimizeShape None
+}
+Debug {
+  DebugLevel = 1;
+//  OpenJournal = Yes;
+//  ReferenceJournal = "";
+//  ReportSlivers = Yes;
+}
+Adaptation {
+//   LowerLengthBound     = 0.58; // 1/sqrt(3)
+//   UpperLengthBound     = 1.73; // sqrt(3)
+//   SwapMinImproveRatio  = 1.0;
+//   SliverQuality        = 0.02;
+//   SplitCanMakeSlivers    = Yes;
+//   CollapseCanMakeSlivers = Yes;
+//   SliverLowerLengthSqBound = 0.32; // 1/sqrt(10)
+//   SliverUpperLengthSqBound = 3.16; // sqrt(10)
+//   CollapseOnBoundary = Yes;
+//   BoundaryCollapses {
+//     Tolerance = 1.e-2;
+//   }
+//   SwapOnBoundary = Yes;
+//   BoundarySwaps {
+//     Tolerance = 1.e6;
+//   }
+//   TrackGeometry = No;
+//   VertexSnapping {
+//     IsMeshTheCavity = Yes;
+//     CavityThickness = 0;
+//     StiffnessAlteration = 1.;
+//   }
+  SmoothSizeField = Yes;
+  SizeFieldSmoothing {
+    // MaximumGradient = 1.000000e+00;
+  }
+}
+MovingObjects {
+  Object = "Cylinder" {
+    Geometry {
+      GeometricalType = Face; 
+      GeometricalTags = [8 12 16 20 22 126];
+    }
+    Kinematics {
+
+      KinematicsSpecification = Velocity;
+      Velocity {
+        Formulation = ["0." "0." "1.*sign(sin(2.*3.14159265/8.*t+1.e-6))"];
+        //        Formulation = ["0." "0." "1."];
+        //Formulation = ["0." "0." "0."];
+      }
+    } 
+    LocalSizeField {
+      DistanceComputation = ToWallVertices;
+      Orientation = Isotropic;
+      Radius = 1.0;
+      Isotropic {
+        Size  = "0.1+(x/1.0)*(0.6-0.1)"; // linear
+        //Size  = "0.02+(sqrt(x)/sqrt(0.5))*(0.2-0.02)"; // sqrt
+      }
+      Anisotropic {
+        NormalSize  = "0.02+(x/1.0)*(0.4-0.02)"; // linear
+        TangentSize = "0.4";
+      }
+      CurvatureBasedLimiter {
+        Enable = No;
+        TangentSizeOverRadius = 0.4;
+      }
+    }
+  }
+  Object = "Tube" {
+    Geometry {
+      GeometricalType = Face; 
+      GeometricalTags = [40 44 48 52 56 60 64 68 71 106];
+    }
+    Kinematics {
+      KinematicsSpecification = Velocity;
+      Velocity {
+        Formulation = ["0." "0." "-1.*sign(sin(2.*3.14159265/8.*t+1.e-6))"];
+        //Formulation = ["0." "0." "-1."];
+        //Formulation = ["0." "0." "0."];
+      }
+    }
+    LocalSizeField {
+      DistanceComputation = ToWallVertices;
+      Orientation = Isotropic;
+      Radius = 1.0;
+      Isotropic {
+        Size  = "0.2+(x/1.0)*(0.6-0.2)"; // linear
+      }
+      Anisotropic {
+        NormalSize  = "0.02+(x/1.0)*(0.4-0.02)"; // linear
+        TangentSize = "0.4";
+      }
+      CurvatureBasedLimiter {
+        Enable = No;
+        TangentSizeOverRadius = 0.4;
+      }
+    }
+  }
+}
+SizeField {
+  Type = Analytical;
+  Analytical {
+    OrientationType = Isotropic; // Isotropic Anisotropic
+    Isotropic {
+      Length = "0.6";
+    }
+//     Anisotropic {
+//       Lengths = ["0.6" "0.3" "0.2"];
+//       Direction1 = ["1." "0." "0."];
+//       Direction2 = ["0." "1." "0."];
+//       Direction3 = ["0." "0." "1."];
+//     }
+  }
+}
+NodeMotion {
+  Type = ElasticAnalogy; // ElasticAnalogy ForceBoundaries None
+  ElasticParameters {
+    StiffnessAlteration = 1.;
+    IsMeshTheCavity = Yes;
+    //    CavityThickness = 3;
+  }
+}
+TimeSpecifications {
+  //  MaxTimeSteps = 4000;
+  TimeStep = 0.01;
+  FinalTime = 4.0;
+}
diff --git a/Benchmarks/moveIt/examples/tube/tube_fullGeo.geo b/Benchmarks/moveIt/examples/tube/tube_fullGeo.geo
new file mode 100644
index 0000000..667d083
--- /dev/null
+++ b/Benchmarks/moveIt/examples/tube/tube_fullGeo.geo
@@ -0,0 +1,130 @@
+Point (1) = {0, 0, 0, 0.1};
+Point (2) = {0.9, 0, 0, 0.1};
+Point (3) = {0, 0.9, 0, 0.1};
+Point (4) = {0, -0.9, 0, 0.1};
+Point (5) = {-0.9, 0, 0, 0.1};
+Point (6) = {-0.9, 0, 3, 0.1};
+Point (7) = {0, 0, 3, 0.1};
+Point (8) = {0, -0.9, 3, 0.1};
+Point (9) = {0, 0.9, 3, 0.1};
+Point (10) = {0.9, 0, 3, 0.1};
+Point (20) = {1, 0, 4, 0.4};
+Point (21) = {-1, 0, 4, 0.4};
+Point (22) = {0, 1, 4, 0.4};
+Point (23) = {0, -1, 4, 0.4};
+Point (24) = {0, -1.2, 4, 0.4};
+Point (25) = {0, 1.2, 4, 0.4};
+Point (26) = {1.2, 0, 4, 0.4};
+Point (27) = {-1.2, 0, 4, 0.4};
+Point (28) = {0, 0, 4, 0.4};
+Point (29) = {-1.2, 0, 7, 0.4};
+Point (30) = {0, 0, 7, 0.4};
+Point (31) = {0, -1.2, 7, 0.4};
+Point (34) = {1.2, 0, 7, 0.4};
+Point (37) = {0, 1.2, 7, 0.4};
+Point (38) = {0, 1, 7, 0.4};
+Point (40) = {-1, 0, 7, 0.4};
+Point (41) = {1, 0, 7, 0.4};
+Point (42) = {0, -1, 7, 0.4};
+Point (62) = {3, 3, -2, 0.6};
+Point (63) = {-3, 3, -2, 0.6};
+Point (64) = {-3, -3, -2, 0.6};
+Point (65) = {3, -3, -2, 0.6};
+Point (66) = {-3, -3, 9, 0.6};
+Point (67) = {-3, 3, 9, 0.6};
+Point (69) = {3, 3, 9, 0.6};
+Point (71) = {3, -3, 9, 0.6};
+Circle (1) = {2, 1, 3};
+Circle (2) = {3, 1, 5};
+Circle (3) = {5, 1, 4};
+Circle (4) = {4, 1, 2};
+Circle (5) = {6, 7, 8};
+Line (6) = {5, 6};
+Line (7) = {4, 8};
+Circle (9) = {9, 7, 6};
+Line (10) = {3, 9};
+Circle (13) = {10, 7, 9};
+Line (14) = {2, 10};
+Circle (17) = {8, 7, 10};
+Circle (29) = {23, 28, 20};
+Circle (30) = {20, 28, 22};
+Circle (31) = {22, 28, 21};
+Circle (32) = {21, 28, 23};
+Circle (33) = {24, 28, 26};
+Circle (34) = {26, 28, 25};
+Circle (35) = {25, 28, 27};
+Circle (36) = {27, 28, 24};
+Circle (37) = {29, 30, 31};
+Line (38) = {27, 29};
+Line (39) = {24, 31};
+Circle (41) = {31, 30, 34};
+Line (43) = {26, 34};
+Circle (45) = {34, 30, 37};
+Line (47) = {25, 37};
+Circle (49) = {37, 30, 29};
+Circle (53) = {38, 30, 40};
+Line (54) = {22, 38};
+Line (55) = {21, 40};
+Circle (57) = {41, 30, 38};
+Line (58) = {20, 41};
+Circle (61) = {42, 30, 41};
+Line (62) = {23, 42};
+Circle (65) = {40, 30, 42};
+Line (82) = {64, 63};
+Line (83) = {63, 62};
+Line (84) = {62, 65};
+Line (85) = {65, 64};
+Line (107) = {66, 67};
+Line (108) = {64, 66};
+Line (109) = {63, 67};
+Line (111) = {67, 69};
+Line (113) = {62, 69};
+Line (115) = {69, 71};
+Line (117) = {65, 71};
+Line (119) = {71, 66};
+Line Loop (8) = {3, 7, -5, -6};
+Ruled Surface (8) = {8};
+Line Loop (12) = {2, 6, -9, -10};
+Ruled Surface (12) = {12};
+Line Loop (16) = {1, 10, -13, -14};
+Ruled Surface (16) = {16};
+Line Loop (20) = {4, 14, -17, -7};
+Ruled Surface (20) = {20};
+Line Loop (22) = {13, 9, 5, 17};
+Plane Surface (22) = {22};
+Line Loop (40) = {36, 39, -37, -38};
+Ruled Surface (40) = {40};
+Line Loop (44) = {33, 43, -41, -39};
+Ruled Surface (44) = {44};
+Line Loop (48) = {34, 47, -45, -43};
+Ruled Surface (48) = {48};
+Line Loop (52) = {35, 38, -49, -47};
+Ruled Surface (52) = {52};
+Line Loop (56) = {31, 55, -53, -54};
+Ruled Surface (56) = {56};
+Line Loop (60) = {30, 54, -57, -58};
+Ruled Surface (60) = {60};
+Line Loop (64) = {29, 58, -61, -62};
+Ruled Surface (64) = {64};
+Line Loop (68) = {32, 62, -65, -55};
+Ruled Surface (68) = {68};
+Line Loop (71) = {45, 49, 37, 41, -57, -61, -65, -53};
+Plane Surface (71) = {71};
+Line Loop (106) = {35, 36, 33, 34, -31, -30, -29, -32};
+Plane Surface (106) = {106};
+Line Loop (110) = {82, 109, -107, -108};
+Ruled Surface (110) = {110};
+Line Loop (114) = {83, 113, -111, -109};
+Ruled Surface (114) = {114};
+Line Loop (118) = {84, 117, -115, -113};
+Ruled Surface (118) = {118};
+Line Loop (122) = {85, 108, -119, -117};
+Ruled Surface (122) = {122};
+Line Loop (124) = {107, 111, 115, 119};
+Plane Surface (124) = {124};
+Line Loop (126) = {2, 3, 4, 1};
+Plane Surface (126) = {126};
+Line Loop (131) = {84, 85, 82, 83};
+Plane Surface (131) = {131};
+Surface Loop (135) = {124, 110, 131, 118, 122, 114, 52, 106, 40, 44, 48, 71, 60, 56, 68, 64, 12, 126, 8, 20, 16, 22};
+Volume (135) = {135};
diff --git a/Benchmarks/moveIt/main.cc b/Benchmarks/moveIt/main.cc
new file mode 100644
index 0000000..4dd8097
--- /dev/null
+++ b/Benchmarks/moveIt/main.cc
@@ -0,0 +1,1185 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+// the template parameter file for this executable
+#include "Parameters.h"
+// the parameter file for the current test case
+#ifdef _HAVE_PARSER_
+ #include "moveItParse.h"
+#else
+ #include "MyParams.h"
+#endif
+
+#include "MAdLib.h"
+#include "MathUtils.h"
+#include "MAdResourceManager.h"
+
+#include <iostream>
+#include <sstream>
+#include <math.h>
+#include <sys/time.h>
+#include <fstream>
+#include <stdlib.h>
+#include <vector>
+#include <set>
+
+#ifdef PARALLEL
+ #include "mpi.h"
+#endif
+
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::stringstream;
+using std::ofstream;
+using std::vector;
+using std::set;
+
+using namespace MAd;
+
+// ----------------------------------------------------------------------
+#ifdef PARALLEL
+class EmptyExchanger : public MDB_DataExchanger
+{
+public:
+  EmptyExchanger(int _tag): MDB_DataExchanger(_tag) {}
+  ~EmptyExchanger() {}
+
+  void * sendData (pEntity pe,    // in
+		   int iProcDest, // in
+		   int &_size ) {
+    _size = 0;
+    return NULL;
+  }
+  void receiveData (pEntity pe,      //in
+	            int iProcSender, //in
+		    void *buf ) {}
+  void deleteExternalData( pEntity pe) const {}
+};
+#endif
+
+
+// ----------------------------------------------------------------------
+double CPUTime() {
+  
+#ifdef PARALLEL
+  return MPI_Wtime();
+#else
+  struct timeval tp;
+  struct timezone tz;
+
+  gettimeofday(&tp,&tz);
+
+  return ((double) tp.tv_sec +
+          (double) ((double) .000001 * (double) tp.tv_usec));
+#endif
+}
+
+// ----------------------------------------------------------------------
+void displayMemoryUsage(string step="")
+{
+  MAdResourceManagerSgl::instance().printMemoryUsage(step,std::cout);
+}
+
+// ----------------------------------------------------------------------
+void writeSolution(MeshAdapter* ma, int iter, string type) 
+{
+  stringstream ss;
+  string iterStr;  ss << iter;  ss >> iterStr;
+  
+  if ( !strcmp(type.c_str(),"Pos") || !strcmp(type.c_str(),"MshAndPos") ) {
+    string namePos = "result" + iterStr + ".pos";
+    ma->writePos(namePos,OD_SIZEFIELD_MEAN);
+  }
+  
+  if ( !strcmp(type.c_str(),"Msh") || !strcmp(type.c_str(),"MshAndPos") ) {
+    string nameMsh = "result" + iterStr + ".msh";
+    ma->writeMsh(nameMsh);
+  }
+
+// #warning "output curvature"
+//   string nameCurv = "curvature" + iterStr;
+//   ma->writeVolumicCurvature(nameCurv);
+}
+
+// ----------------------------------------------------------------------
+void setMobileObject(mobileObject* mob, pMesh mesh, ObjectDef def)
+{
+  // --- Name ---
+  string name = def.name;
+  mob->setName(name);
+
+  // --- Geometry ---
+  int type = def.geomLevel;
+  set<int>::const_iterator gIter = def.geomTags.begin();
+  set<int>::const_iterator gLast = def.geomTags.end();
+  for (; gIter != gLast; gIter++) {
+    for (int iTag = (*gIter); iTag <= (*gIter); iTag++) {
+      mob->addGEntity(type,iTag);
+    }
+  }
+
+  // --- Kinematics ---
+  KinematicType kinType = def.kinType;
+  if ( kinType == KT_DISPLACEMENT ) {
+    mob->setDxKinematics(def.kinExpression);
+  }
+  else {
+    mob->setVKinematics(PARSED, NULL, NULL, def.kinExpression);
+  }
+
+  // --- Local size fields ---
+  std::list<LocalSFDef>::const_iterator sIter = def.sizes.begin();
+  std::list<LocalSFDef>::const_iterator sLast = def.sizes.end();
+  for (; sIter != sLast; sIter++) {
+    LocalSizeField* locSField = new LocalSizeField(mesh, (*sIter).name, 
+                                                   (*sIter).distToFaces);
+    bool   iso = (*sIter).isotropic;
+    double radius = (*sIter).radius;
+    string sizeN = (*sIter).sizeN;
+    string sizeT = (*sIter).sizeT;
+    bool   limit = (*sIter).limit;
+    double limitSizeTg = (*sIter).limitSizeTg;
+    double maxCurv = (*sIter).maxCurv;
+    if ( iso ) locSField->setIsoSize(radius,sizeN);
+    else       locSField->setAnisoSize(radius,sizeN,sizeT);
+    if ( limit ) locSField->setCurvatureLimiter(limitSizeTg, maxCurv);
+    
+    set<int>::const_iterator gIter = def.geomTags.begin();
+    set<int>::const_iterator gLast = def.geomTags.end();
+    for (; gIter != gLast; gIter++) {
+      for (int iTag = (*gIter); iTag <= (*gIter); iTag++) {
+        locSField->addGeometricEntity(type,iTag);
+      }
+    }
+    locSField->updateTree();
+    mob->addLocalSField(locSField);
+
+// #warning "debug"
+//     locSField->printPosAnisotropic(mesh,"locSF");
+  }
+}
+
+// ----------------------------------------------------------------------
+void deleteObjects(mobileObjectSet* objSet)
+{
+  set<mobileObject*> objs = objSet->getObjects();
+  set<mobileObject*>::iterator oIter = objs.begin();
+  for (; oIter != objs.end(); oIter++) {
+    
+    mobileObject * mob = *oIter;
+
+    // clean size fields
+    set<LocalSizeField* > localSFs = mob->getSizes();
+    set<LocalSizeField* >::iterator sIter = localSFs.begin();
+    for (; sIter != localSFs.end(); sIter++) {
+      if (*sIter) delete (*sIter);
+    }
+    
+    // delete object
+    if (mob) delete mob;
+  }
+}
+
+// ----------------------------------------------------------------------
+int main(int argc, char* argv[]) 
+{
+  double main_t0 = CPUTime();
+
+  MAdLibInitialize(&argc,&argv);
+
+  displayMemoryUsage("initialized");
+
+#ifdef _HAVE_PARSER_
+  parseControlFile(argc,argv);
+#endif
+
+  MoveParameters parameters = getParameters();
+
+  // ------------------------------------------------
+  // setup the output
+  // ------------------------------------------------
+
+  string outputType = parameters.outType;
+  int outputFrequency = parameters.outFrequency;
+  string outputPrefix = parameters.outPrefix;
+
+  // ------------------------------------------------
+  // load the mesh
+  // ------------------------------------------------
+
+  cout << "Loading the mesh...\n";
+  double cpu_mesh_0 = CPUTime();
+
+  // --- Reading model ---
+  string meshFileName = parameters.meshFileName;
+  string geoFileName  = parameters.geoFileName;
+  pGModel model = 0;
+  GM_create(&model,"theModel");
+  if ( !geoFileName.empty() ) GM_read(model, geoFileName.c_str());
+  else                        GM_readFromMSH(model, meshFileName.c_str());
+
+  // --- Reading mesh ---
+  pMesh mesh = M_new(model);
+  M_load(mesh,meshFileName.c_str());
+//   M_writeMsh (mesh, (outputPrefix + "initMesh.msh").c_str(), 2, NULL);
+
+  double cpu_mesh_tot = CPUTime() - cpu_mesh_0;
+  cout << "Loaded the mesh in "<<cpu_mesh_tot<<" seconds\n";
+  displayMemoryUsage("Mesh loaded");
+
+  // ------------------------------------------------
+  // build the mesh adapter
+  // ------------------------------------------------
+
+  cout << "Building the mesh adapter...\n";
+  double cpu_ma_0 = CPUTime();
+  MeshAdapter* ma = new MeshAdapter(mesh);
+
+  ma->setOutputPrefix(outputPrefix);
+
+  ma->setMaxIterationsNumber(parameters.maxInnerIter);
+
+  double lowerLenghtBound = parameters.lowerLength;
+  double upperLenghtBound = parameters.upperLength;
+  ma->setEdgeLenSqBounds( lowerLenghtBound * lowerLenghtBound,
+                          upperLenghtBound * upperLenghtBound );
+
+  ma->setSwapMinImproveRatio (parameters.swapMinImproveRatio);
+  ma->setSliverQuality       (parameters.sliverQuality);
+  ma->setSliverPermissionInESplit    (parameters.splitCanMakeSlivers,
+                                      parameters.makeSliverInSplitLenSqBound);
+  ma->setSliverPermissionInECollapse (parameters.collapseCanMakeSlivers,
+                                      parameters.makeSliverInCollapseLenSqBound);
+  ma->setCollapseOnBoundary  (parameters.collapseOnBoundary,
+                              parameters.clpOnBdryTolerance);
+  ma->setSwapOnBoundary      (parameters.swapOnBoundary,
+                              parameters.swapOnBdryTolerance);
+  ma->setGeoTracking         (parameters.trackGeometry,
+                              parameters.snap_cavityIsMesh,
+                              parameters.snap_thickness,
+                              parameters.snap_chi);
+  ma->setSizeFieldSmoothing  (parameters.SFSmoothing,
+                              parameters.SFSmoothGrad);
+  ma->setInfiniteLength(parameters.infLength);
+
+#ifdef PARALLEL
+  EmptyExchanger * dExch = new EmptyExchanger(4238458);
+  ma->setDataExchanger( dExch );
+#endif
+
+  ma->setSFUpdateFrequency(0);
+
+  double cpu_ma_tot = CPUTime() - cpu_ma_0;
+  cout << "Built the mesh adapter in "<<cpu_ma_tot<<" seconds\n";
+
+  displayMemoryUsage("Mesh adapter built");
+
+// #warning "debug"
+//   ma->writePos("testCurvMaxVec.pos",OD_CURVATURE_MAX_VEC);
+//   printf("Written!");
+
+  // ------------------------------------------------
+  // build the size fields
+  // ------------------------------------------------
+  cout << "Buidling the size fields...\n";
+  double cpu_sf_0 = CPUTime();
+
+  set<pSField> sizeFields;
+
+  std::list<SizeFieldDef>::const_iterator sIter = parameters.sizes.begin();
+  std::list<SizeFieldDef>::const_iterator sLast = parameters.sizes.end();
+  for (; sIter != sLast; sIter++) {
+
+    SizeFieldBase* sizeField = NULL;
+  
+    if ( (*sIter).type == ANALYTICALSFIELD )
+      {
+        OrientationType orient = (*sIter).orientation;
+        if ( orient == ORT_ISOTROPIC ) {
+          sizeField = new AnalyticalSField((*sIter).isoSize);
+        }
+        else {
+          sizeField = new AnalyticalSField((*sIter).anisoSize,
+                                           (*sIter).anisoDir0,
+                                           (*sIter).anisoDir1,
+                                           (*sIter).anisoDir2);
+        }
+      }
+    else if ( (*sIter).type == DISCRETESFIELD )
+      {
+        sizeField = new PWLSField(mesh);
+        string source = (*sIter).pwlSource;
+        if ( !strcmp(source.c_str(),"InitialLength") ) {
+          ((PWLSField*) sizeField)->setCurrentSize();
+        }
+        else if ( !strcmp(source.c_str(),"Curvature") ) {
+          bool aniso = (*sIter).curv_aniso;
+          double alpha = (*sIter).curv_alpha;
+          double hMin = (*sIter).curv_hMin;
+          ((PWLSField*) sizeField)->setCurvatureSize(aniso,alpha,hMin);
+        }
+        else throw;
+      }
+    else throw;
+
+    sizeFields.insert(sizeField);
+    ma->addSizeField(sizeField);
+  }
+
+  double cpu_sf_tot = CPUTime() - cpu_sf_0;
+  cout << "Built the size field in "<<cpu_sf_tot<<" seconds\n";
+
+  displayMemoryUsage("Size fields built");
+
+// #warning "debug"
+//   ma->writePos("testSF.pos",OD_SIZEFIELD_MEAN);
+
+  ma->printStatistics(cout);
+
+
+  // ------------------------------------------------
+  // setup the quality monitoring
+  // ------------------------------------------------
+
+  string qualityFileName = outputPrefix + "quality";
+  FILE* qualFile = fopen(qualityFileName.c_str(),"w");
+  if (!qualFile) {
+    cerr << "Could not open the quality file " << qualityFileName << endl;
+    throw;
+  }
+
+  double meanShape, worstShape;
+  ma->getStatistics(&meanShape,&worstShape);
+  fprintf(qualFile,"iter\tmean quality\tworst quality\n");
+  fprintf(qualFile,"%d\t%g\t%g\n",0,meanShape,worstShape);
+  fclose(qualFile);
+
+  // ------------------------------------------------
+  // setup the cpu time monitoring
+  // ------------------------------------------------
+
+  string cpuFileName = outputPrefix + "cpu";
+  FILE* cpuFile = fopen(cpuFileName.c_str(),"w");
+  if (!cpuFile) {
+    cerr << "Could not open the cpu report file " << cpuFileName << endl;
+    throw;
+  }
+
+  fprintf(cpuFile,"iter\tnodes motion\tadaptation\toutputs  \taccumulated nm\taccum adapt\taccum out\ttotal\n");
+  fclose(cpuFile);
+
+  string produceCpuInfo = "cat /proc/cpuinfo > \"" + outputPrefix + "cpuinfo\"";
+  system(produceCpuInfo.c_str());
+
+  // ------------------------------------------------
+  // setup the mesh size monitoring
+  // ------------------------------------------------
+
+  string MSFileName = outputPrefix + "meshSize";
+  FILE* MSFile = fopen(MSFileName.c_str(),"w");
+  if (!MSFile) {
+    cerr << "Could not open the mesh size report file " << MSFileName << endl;
+    throw;
+  }
+
+  fprintf(MSFile,"iter\t#nodes\t#edges\t#faces\t#regions\n");
+  fprintf(MSFile,"init\t%d\t%d\t%d\t%d\n",
+          M_numVertices(mesh),M_numEdges(mesh),M_numFaces(mesh),M_numRegions(mesh));
+  fclose(MSFile);
+
+  // ------------------------------------------------
+  // setup debug tools
+  // ------------------------------------------------
+
+  int debugLevel = parameters.debugLevel;
+  ma->setDebugLevel(debugLevel);
+
+  // --- cross checks between two executions ---
+  bool openJournal = parameters.openJournal;
+  if ( openJournal ) {
+    
+    // Will hold a list of operations and checks in this execution
+    ma->openJournal();
+
+    // Will compare the list to another one (and abort if different)
+    string refJournalName = parameters.referenceJournal;
+    if ( !refJournalName.empty() ) {
+      std::cout<<"Warning: comparing execution with the journal \'"
+               << refJournalName << "\'\n";
+      ma->setReferenceJournal(refJournalName);
+    }
+  }
+
+  // --- slivers output ---
+  bool sliverReports = parameters.sliverReports;
+  if ( sliverReports ) {
+    ma->enableSliverReports();
+  }
+  bool sliverOps = parameters.testSliverOperators;
+  ma->testSliverOperators(sliverOps);
+
+  displayMemoryUsage("Monitoring and debug tools set");
+
+  // ------------------------------------------------
+  // TEST MOBILE OBJECTS
+  // ------------------------------------------------
+  
+  if ( !strcmp(parameters.task.c_str(),"MobileObject") ) {
+
+#ifndef PARALLEL
+    ma->storeInitialCoordinates();
+
+    displayMemoryUsage("Initial coordinates stored");
+
+    // ---- build the mobile objects ----
+    cout << "Building the mobile objects...\n";
+    double cpu_mobj_0 = CPUTime();
+    mobileObjectSet* objs = new mobileObjectSet();
+    for (unsigned int iObj = 0; iObj < parameters.objects.size(); iObj++) {
+      mobileObject* mob = new mobileObject(mesh);
+      setMobileObject(mob,mesh,parameters.objects[iObj]);
+      objs->insert(mob);
+    }
+    ma->registerObjects(objs);
+    double cpu_mobj_tot = CPUTime() - cpu_mobj_0;
+    cout << "Built the mobile objects in "<<cpu_mobj_tot<<" seconds\n";
+    displayMemoryUsage("Mobile objects built");
+
+// #warning "Size field printed to debug"
+//     ma->writePos("sizeFieldInitMean.pos", OD_SIZEFIELD_MEAN);
+//     ma->writePos("sizeFieldInitMin.pos",  OD_SIZEFIELD_MIN);
+//     ma->writePos("sizeFieldInitMax.pos",  OD_SIZEFIELD_MAX);
+//     ma->writePos("sizeFieldInit0.pos",OD_ANISO_SF_AXIS0);
+//     ma->writePos("sizeFieldInit1.pos",OD_ANISO_SF_AXIS1);
+//     ma->writePos("sizeFieldInit2.pos",OD_ANISO_SF_AXIS2);
+// #warning "output curvature"
+//     string nameCurv = "curvatureInit";
+//     ma->writeVolumicCurvature(nameCurv);
+
+    // ---- get node motion parameters ----
+    string nodeMotionType = parameters.nodeMotionType;
+    double elasticChi = parameters.elasticStiffnessAlteration;
+    bool   elasticCavityMesh = parameters.elasticIsMeshTheCavity;
+    int    elasticCavityThick = parameters.elasticCavityThickness;
+#else
+    string nodeMotionType = "None";
+    double elasticChi;
+    bool   elasticCavityMesh;
+    int    elasticCavityThick;
+#endif
+
+    // ---- get time parameters ----
+    double dtGlob = parameters.timeStep;
+    double finalTime = parameters.finalTime;
+    int maxTimeSteps = parameters.maxNbTimeSteps;
+
+    // ---- the loop ----
+    double cpu_t0 = CPUTime();
+    double t = 0., dt_iter = 0.;
+    int iter = 0;
+    double cpu_move = 0., cpu_adapt = 0., cpu_output = 0.;
+    while (iter <= maxTimeSteps && t < finalTime)
+      {
+        double cpu_t1 = CPUTime();
+        if ( iter > 0 )  // a first step is performed with the adaptation before any motion occurs
+          {
+            // --- find time step for this iteration ---
+            double t_left_tot = std::max(finalTime - t, 0.0);
+            dt_iter = std::min(dtGlob, t_left_tot);
+          
+            // --- move nodes (dummy move and Laplace smoothing) ---
+            if ( !strcmp(nodeMotionType.c_str(),"ForceBoundaries") ) {
+
+              MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+                                            "Forcing boundaries is followed by Laplace smoothing");
+              throw;
+
+              double part;
+              if (!ma->partlyMoveObjects(t, dt_iter, &part)) {
+                cout <<"Could not perform a forced move\n";
+                ma->abort(__LINE__,__FILE__);
+              }
+              dt_iter *= part;
+
+              if ( debugLevel >= 1 && !(ma->checkTheMesh()) )  ma->abort(__LINE__,__FILE__);
+              ma->LaplaceSmoothing(OPTIMAL);
+              if ( debugLevel >= 1 && !(ma->checkTheMesh()) )  ma->abort(__LINE__,__FILE__);
+            }
+
+            t += dt_iter;  ma->setTime(t);
+            printf("\nGlobal time step %d, t = %f, dt = %f\n\n",iter,t,dt_iter);
+
+            // --- move nodes (elasticity analogy) ---
+            if ( !strcmp(nodeMotionType.c_str(),"ElasticAnalogy") ) {
+              ma->moveObjectsAndReposition(t, dt_iter, 
+                                           elasticChi,
+                                           elasticCavityMesh, 
+                                           elasticCavityThick);
+              displayMemoryUsage("Nodes repositionned");
+            }
+          }
+        double cpu_t2 = CPUTime(); 
+        cpu_move += ( cpu_t2 - cpu_t1 );
+
+        // --- adapt the mesh ---
+        ma->run();
+        double cpu_t3 = CPUTime();
+        cpu_adapt += ( cpu_t3 - cpu_t2 );
+        displayMemoryUsage("After adaptation");
+
+        // --- outputs ---
+
+        {  // full mesh
+          if ( ( outputFrequency > 0 ) && 
+               ( (iter%outputFrequency) == 0 ) ) {
+            writeSolution(ma,iter,outputType);
+          }
+          displayMemoryUsage("After outputs");
+        }
+
+        {  // quality monitor
+          ma->getStatistics(&meanShape,&worstShape);
+          FILE* qf = fopen(qualityFileName.c_str(),"a");
+          fprintf(qf,"%d\t%e\t%e\n",iter,meanShape,worstShape);
+          fclose(qf);
+        }
+
+        {  // cpu monitor
+          double cpu_t4 = CPUTime();
+          cpu_output += ( cpu_t4 - cpu_t3 );
+      
+          FILE* cpuF = fopen(cpuFileName.c_str(),"a");
+          fprintf(cpuF,"%d\t%e\t%e\t%e\t%e\t%e\t%e\t%e\n",
+                  iter, cpu_t2 - cpu_t1, cpu_t3 - cpu_t2, cpu_t4 - cpu_t3,
+                  cpu_move, cpu_adapt, cpu_output, cpu_t4 - cpu_t0 );
+          fclose(cpuF);
+        }
+
+        {  // mesh size monitor
+          FILE* msf = fopen(MSFileName.c_str(),"a");
+          fprintf(msf,"%d\t%d\t%d\t%d\t%d\n",
+                  iter,M_numVertices(mesh),M_numEdges(mesh),M_numFaces(mesh),M_numRegions(mesh));
+          fclose(msf);
+        }
+
+        { // slivers stats
+          if ( (iter%10) == 0 ) {
+            ofstream sliverOut( (outputPrefix + "slivers_tmp").c_str() );
+            ma->printSliverRegionStatistics(sliverOut);
+          }
+        }
+
+        { // operations stats
+          if ( (iter%10) == 0 ) {
+            ofstream operationsOut( (outputPrefix + "statistics_tmp").c_str() );
+            ma->printStatistics(operationsOut);
+          }
+        }
+
+        { // journal
+          if ( (iter%10) == 0 ) {
+            ofstream journalOut( (outputPrefix + "journal_tmp").c_str() );
+            ma->flushJournal(journalOut);
+          }
+        }
+
+        displayMemoryUsage("After monitors");
+        iter++;
+      }
+
+#ifndef PARALLEL
+    if (objs) {
+      deleteObjects(objs);
+      delete objs;
+    }
+    displayMemoryUsage("Objects deleted");
+
+    ma->removeStoredCoordinates();
+    displayMemoryUsage("Stored coordinates deleted");
+#endif
+  }
+
+  // ------------------------------------------------
+  // TEST REMOVE REGION
+  // ------------------------------------------------
+
+  else if ( !strcmp(parameters.task.c_str(),"RemoveRegion") )
+    {
+      for (int i=0; i<1; i++) {
+        int numOp = 0;
+        int oriNumFaces = M_numFaces(mesh);
+        int count = 0;
+        FIter fi = M_faceIter(mesh);
+        pFace pf;
+        while ( ( pf = FIter_next(fi) ) && ( count < oriNumFaces ) ) {
+          count++;
+          if (F_numRegions(pf) != 1) continue;
+          else {
+            pRegion pr = F_region(pf,0);
+            if (!pr) pr = F_region(pf,1);
+            if ( ma->removeRegion(pr) ) numOp++;
+          }
+        }
+        FIter_delete(fi);
+        cout << "Num region removed: "<<numOp<<endl;
+      }
+    }
+
+  // ------------------------------------------------
+  // test size fields intersection or smoothing
+  // ------------------------------------------------
+  
+  else if ( !strcmp(parameters.task.c_str(),"SizeField") )
+    {
+      ma->writePos("testSF.pos",OD_SIZEFIELD_MEAN);
+      ma->writePos("aniso0.pos",OD_ANISO_SF_AXIS0);
+      ma->writePos("aniso1.pos",OD_ANISO_SF_AXIS1);
+      ma->writePos("aniso2.pos",OD_ANISO_SF_AXIS2);
+
+      PWLSField* testSF = new PWLSField(mesh);
+      string h = "2.*x+0.1";
+      AnalyticalSField* testASF = new AnalyticalSField(h);
+
+      testSF->intersect(testASF);
+//       testSF->smooth(0.5);
+  
+      MeshAdapter* testMA = new MeshAdapter(mesh,testSF);
+  
+      testMA->writePos("sizeField.pos",OD_SIZEFIELD_MEAN);
+       //      testMA->writePos("sizeFieldSmoothed.pos",OD_SIZEFIELD_MEAN);
+
+      exit(0);
+    }
+
+  // ------------------------------------------------
+  // TEST REMOVE SLIVER FACES
+  // ------------------------------------------------
+
+  else if ( !strcmp(parameters.task.c_str(),"RemoveSliverFaces") )
+    {
+      for (int i=0; i<10; i++) {
+        ma->removeSlivers();
+        if ( !checkMesh(mesh,CHECK_ALL,1) )  ma->abort(__LINE__,__FILE__);
+      }
+    }
+
+  // ------------------------------------------------
+  // TEST LAPLACE SMOOTHING
+  // ------------------------------------------------
+  
+  else if ( !strcmp(parameters.task.c_str(),"LaplaceSmoothing") )
+    {
+      for (int i=0; i<1; i++) {
+        ma->LaplaceSmoothing(FAST);
+        cout << "Smoothing "<<i<<" operated\n";
+        if ( !checkMesh(mesh,CHECK_ALL,1) )  ma->abort(__LINE__,__FILE__);
+      }
+    }
+
+  // ------------------------------------------------
+  // TEST GEOMETRIC CONSTRAINTS
+  // ------------------------------------------------
+  
+  else if ( !strcmp(parameters.task.c_str(),"GeoConstraints") )
+    {
+      ma->setConstraint(2,5);
+      ma->removeConstraint(2,5);
+    }
+
+  // ------------------------------------------------
+  // TEST CONSTRAINTS
+  // ------------------------------------------------
+
+  else if ( !strcmp(parameters.task.c_str(),"TopoConstraints") )
+    {
+      FIter fi = M_faceIter(mesh);
+      while ( pFace pf = FIter_next(fi) ) {
+        int gtag  = GEN_tag ( EN_whatIn ((pEntity)pf) );
+        int gtype = GEN_type( EN_whatIn ((pEntity)pf) );
+        if ( gtype == 2 && ( gtag == 5 || gtag == 22 || gtag == 14 || gtag == 27 ) ) ma->setConstraint((pEntity)pf);
+      } 
+      FIter_delete(fi);
+
+      VIter vi = M_vertexIter(mesh);
+      pVertex pv;
+      while ( ( pv = VIter_next(vi) ) ) {
+        // int gtag  = GEN_tag ( EN_whatIn ((pEntity)pv) );
+        int gtype = GEN_type( EN_whatIn ((pEntity)pv) );
+        if ( gtype == 0 ) EN_constrain((pEntity)pv);
+      } 
+      VIter_delete(vi);
+    }
+
+  // ------------------------------------------------
+  // TEST FACE SWAP OPERATOR
+  // ------------------------------------------------
+
+  else if ( !strcmp(parameters.task.c_str(),"FaceSwap") )
+    {
+      for (int i=0; i<5; i++) {
+        int count=0, numOp=0;
+        int oriNumFaces = M_numFaces(mesh);
+        FIter fi = M_faceIter(mesh);
+        pFace pf;
+        while ( ( pf = FIter_next(fi) ) && ( count < oriNumFaces ) ) {
+          int res = ma->swapFace(pf);
+          if ( res ) numOp++;
+          count++;
+        }
+        FIter_delete(fi);
+        cout << "Num face swaps: "<<numOp<<endl;
+        if ( !checkMesh(mesh,CHECK_ALL,1) )  ma->abort(__LINE__,__FILE__);
+
+        int nESwaps = ma->optimiseElementShape();
+        cout<< "Edge swaps applied: "<<nESwaps<<endl;
+      }
+    }
+
+  // ------------------------------------------------
+  // MAKE A BAD MESH
+  // ------------------------------------------------
+
+  else if ( !strcmp(parameters.task.c_str(),"UglyMesh") )
+    {
+      ma->uglyTheMesh(0.2,10);
+      ma->writeMsh("uglyMesh.msh");
+    }
+
+  // ------------------------------------------------
+  // TEST REMOVE SLIVER REGIONS
+  // ------------------------------------------------
+
+  else if ( !strcmp(parameters.task.c_str(),"RemoveSliverRegions") )
+    {
+      ma->setSliverQuality(0.1);
+      for (int i=0; i<2; i++) {
+        ma->removeSlivers();
+        if ( !checkMesh(mesh,CHECK_ALL,1) )  ma->abort(__LINE__,__FILE__);
+      }
+    }
+  
+  // ------------------------------------------------
+  // TEST DOUBLE-SPLIT-COLLAPSE OPERATOR
+  // ------------------------------------------------
+
+  else if ( !strcmp(parameters.task.c_str(),"DESC") )
+    {
+      for (int i=0; i<20; i++) {
+        int numOp = 0;
+        int oriNumRgn = M_numRegions(mesh);
+        int count = 0;
+        RIter ri = M_regionIter(mesh);
+        pRegion pr;
+        while ( ( pr = RIter_next(ri) ) && ( count < oriNumRgn ) ) {
+          pEdge pe1 = R_edge(pr,0);
+          pEdge pe2 = R_gtOppEdg(pr, pe1);
+
+          if ( ma->DSplitCollapseEdge(pr,pe1,pe2) )
+            numOp++;
+          count++;
+        }
+        RIter_delete(ri);
+        cout << "Num double-split-collapses: "<<numOp<<endl;
+
+        if ( !checkMesh(mesh,CHECK_ALL,1) )  ma->abort(__LINE__,__FILE__);
+        //     ma->printStatistics(std::cout);
+
+        //     int* nbBefore = new int(0);
+        //     int* nbAfter = new int(0);
+        //     ma->removeSliverRegions(nbBefore,nbAfter);
+        //     cout <<"Nb slivers before->after realignement:\t"<<*nbBefore<<" -> "<<*nbAfter<<endl;
+      }
+    }
+
+  // ------------------------------------------------
+  // TEST EDGE SWAP
+  // ------------------------------------------------
+  
+  else if ( !strcmp(parameters.task.c_str(),"EdgeSwap") )
+    {
+      if ( !checkMesh(mesh,CHECK_ALL,1) )  ma->abort(__LINE__,__FILE__); 
+      for (int i=0; i<30; i++) {
+        int count = 0;
+        int numOp = 0;
+        int numE = M_numEdges(mesh);
+        EIter ei = M_edgeIter(mesh);
+        while ( pEdge pe = EIter_next(ei) ) {
+          count++;
+          if ( ma->swapEdge(pe) ) numOp++;
+          if ( count > numE ) break;
+        } 
+        EIter_delete(ei);
+        cout << "Num edge swaps ("<<i<<"): " << numOp << endl;
+        if ( !checkMesh(mesh,CHECK_ALL,1) )  ma->abort(__LINE__,__FILE__); 
+        writeSolution(ma,i,outputType);
+      }
+    }
+
+  // ------------------------------------------------
+  // TEST GEOMATCHER
+  // ------------------------------------------------
+  
+  else if ( !strcmp(parameters.task.c_str(),"GeoMatcher") )
+    {
+      for (int i=0; i<8; i++) {
+        int count = 0;
+        int numOp = 0;
+        int numE = M_numEdges(mesh);
+        EIter ei = M_edgeIter(mesh);
+        pEdge pe;
+        while ( ( pe = EIter_next(ei) ) ) {
+          count++;
+          if ( ma->splitEdge(pe) ) {
+            ma->snapVertices();
+            numOp++;
+          }
+          if ( count > numE ) break;
+        } 
+        EIter_delete(ei);
+        cout << "Num edge splits ("<<i<<"): " << numOp << endl;
+        if ( !checkMesh(mesh,CHECK_ALL,1) )  ma->abort(__LINE__,__FILE__); 
+      }
+    }
+
+  // ------------------------------------------------
+  // TEST EDGE SPLIT
+  // ------------------------------------------------
+  
+  else if ( !strcmp(parameters.task.c_str(),"EdgeSplit") )
+    {
+      if ( !checkMesh(mesh,CHECK_ALL,1) )  ma->abort(__LINE__,__FILE__); 
+      for (int i=0; i<5; i++) {
+
+        ma->splitEveryEdgeOnce();
+
+//         int count = 0;
+//         int numOp = 0;
+//         int numE = M_numEdges(mesh);
+//         EIter ei = M_edgeIter(mesh);
+//         pEdge pe;
+//         while ( ( pe = EIter_next(ei) ) ) {
+//           count++;
+//           if ( E_whatInType(pe) <= 2 && ma->splitEdge(pe) ) { numOp++; }
+//           if ( count > numE ) break;
+//         } 
+//         EIter_delete(ei);
+//         cout << "Num edge splits ("<<i<<"): " << numOp << endl;
+//         if ( !checkMesh(mesh,CHECK_ALL,1) )  ma->abort(__LINE__,__FILE__); 
+
+//         // --- Geometry tracking ---
+//         cout << "Snapping boundary nodes" << endl;
+//         if (numOp) ma->snapVertices();
+
+        if ( !checkMesh(mesh,CHECK_ALL,1) )  ma->abort(__LINE__,__FILE__);
+        writeSolution(ma,i,outputType);
+      }
+    }
+
+  // ------------------------------------------------
+  // TEST EDGE COLLAPSE
+  // ------------------------------------------------
+  
+  else if ( !strcmp(parameters.task.c_str(),"EdgeCollapse") )
+    {
+      //      GM_writeGEO(model,"testgeo.geo");
+      //      ma->writeMsh("MeshInit.msh");
+      for (int i=0; i<10; i++) {
+        double t0 = CPUTime();
+        int count = 0;
+        int nbEdgesInit = M_numEdges(mesh);
+        int numOp = 0;
+        EIter ei = M_edgeIter(mesh);
+        pEdge pe;
+        while ( ( pe = EIter_next(ei) ) ) {
+          count++;
+          if ( ma->collapseEdge(pe) ) { numOp++; }
+          if ( count > nbEdgesInit ) break;
+        } 
+        EIter_delete(ei);
+        double dt = CPUTime() - t0;
+        cout << "Num edge collapses ("<<i<<"): " << numOp << " in "<<dt<<" seconds\n";
+        if ( !checkMesh(mesh,CHECK_ALL,1) )  ma->abort(__LINE__,__FILE__); 
+//         ma->printStatistics(std::cout);
+        writeSolution(ma,i,outputType);
+      }
+    }
+
+  // ------------------------------------------------
+  // TEST EDGE SPLIT AND COLLAPSE
+  // ------------------------------------------------
+  
+  else if ( !strcmp(parameters.task.c_str(),"EdgeSplitCollapse") )
+    {
+      for (int i=0; i<20; i++) {
+        
+        // --- collapse as many edges as possible ---
+        int totColl = 0;
+        while (1) {
+          int numClp = 0;
+//           while (1)
+//             {
+//               pEdge pe;
+//               EIter ei = M_edgeIter(mesh);
+//               while ( ( pe = EIter_next(ei) ) ) {
+//                 if ( ma->collapseEdge(pe) ) { numClp++; break; }
+//               }
+//               EIter_delete(ei);
+//               if ( !pe ) break;
+//               if ( !checkMesh(mesh,CHECK_GEOM_COMPATIBILITY,1,std::cout) ) ma->abort(__LINE__,__FILE__); 
+//             }
+          EIter ei = M_edgeIter(mesh);
+          pEdge pe;
+          while ( ( pe = EIter_next(ei) ) ) {
+            if ( ma->collapseEdge(pe) ) numClp++;
+          }
+          EIter_delete(ei);
+          totColl += numClp;
+          cout << "Num edge collapses: "<< numClp << endl;
+          if ( ! ma->checkTheMesh() ) ma->abort(__LINE__,__FILE__); 
+          if ( numClp == 0 ) break;
+        }
+
+        // --- perform many edge splits ---
+        for (int iS=0; iS<2; iS++) {
+          int numSpl = ma->splitEveryEdgeOnce();
+          cout << "Num edge splits: " << numSpl << endl;
+          if ( ! ma->checkTheMesh() ) ma->abort(__LINE__,__FILE__); 
+        }
+
+        // --- Geometry tracking ---
+//         if (numSpl) ma->snapVertices();
+//         if ( !checkMesh(mesh,CHECK_ALL,1) )  ma->abort(__LINE__,__FILE__); 
+
+        writeSolution(ma,i,outputType);
+      }
+
+      /*
+      for (int i=0; i<10; i++) {
+        int count = 0;
+        int oriNumEdges = M_numEdges(mesh);
+        int numClp = 0, numSpl = 0;
+        EIter ei = M_edgeIter(mesh);
+        pEdge pe;
+        while ( ( pe = EIter_next(ei) ) ) {
+          count++;
+          if ( E_whatInType(pe) <= 2 ) 
+            {
+              if ( (count%3) == 0 ) {
+                if ( ma->splitEdge(pe) ) numSpl++;
+              }
+              else {
+                if ( ma->collapseEdge(pe) ) numClp++;
+              }
+            }
+          if ( count > oriNumEdges ) break;
+        } 
+        EIter_delete(ei);
+        cout << "Num edge splits ("<<i<<"): " << numSpl << endl;
+        cout << "Num edge collapses ("<<i<<"): " << numClp << endl;
+        if ( !checkMesh(mesh,CHECK_ALL,1) )  ma->abort(__LINE__,__FILE__); 
+
+        // --- Geometry tracking ---
+        if (numSpl) ma->snapVertices();
+        if ( !checkMesh(mesh,CHECK_ALL,1) )  ma->abort(__LINE__,__FILE__); 
+
+        writeSolution(ma,i,outputType);
+//         ma->printStatistics(std::cout);
+      }
+      */
+    }
+
+  // ------------------------------------------------
+  // TEST FACE COLLAPSE OPERATOR
+  // ------------------------------------------------
+
+  else if ( !strcmp(parameters.task.c_str(),"FaceCollapse") )
+    {
+      for (int i=0; i<10; i++) {
+        int numOp = 0;
+        int oriNumFaces = M_numFaces(mesh);
+        int count = 0;
+        FIter fi = M_faceIter(mesh);
+        pFace pf;
+        while ( ( pf = FIter_next(fi) ) && ( count < oriNumFaces ) ) {
+          for (int j=0; j<3; j++) {
+            pEdge pe = F_edge(pf,j);
+            if ( ma->collapseFace(pf,pe) ) {
+              numOp++;
+              break;
+            }
+          }
+          count++;
+        }
+        FIter_delete(fi);
+        cout << "Num face collapse: "<<numOp<<endl;
+        if ( !checkMesh(mesh,CHECK_ALL,1) )  ma->abort(__LINE__,__FILE__);
+//         ma->printStatistics(std::cout);
+      }
+    }
+
+  // ------------------------------------------------
+  // TEST OPTIMISE EDGE LENGTH
+  // ------------------------------------------------
+
+  else if ( !strcmp(parameters.task.c_str(),"OptimizeLength") )
+    {
+      cout<<"Split collapses applied: "<<ma->optimiseEdgeLength()<<endl;
+    }
+
+  // ------------------------------------------------
+  // TEST OPTIMISE SHAPE
+  // ------------------------------------------------
+
+  else if ( !strcmp(parameters.task.c_str(),"OptimizeShape") )
+    {
+      int nSwaps = ma->optimiseElementShape();
+      cout<< "Swaps applied: "<<nSwaps<<endl;
+    }
+
+  // ------------------------------------------------
+  // TEST METRIC
+  // ------------------------------------------------
+
+  else if ( !strcmp(parameters.task.c_str(),"Metric") )
+    {
+      double h[3] = { 2., 3., 10. };
+      double e[3][3] = {
+        {sqrt(2.)/2., sqrt(2.)/2., 0.},
+        {0., 0., 1.},
+        {sqrt(2.)/2., -sqrt(2.)/2., 0.}
+      };
+
+      MAdMetric M = MAdMetric(h[0],h[1],h[2],e[0],e[1],e[2]);
+
+      doubleMatrix V = doubleMatrix(3,3);
+      doubleVector S = doubleVector(3);
+      M.eig(V,S,true);
+
+      printVec(h,"h");
+      printMat(e,"e");
+      V.print("V");
+      S.print("S");
+    }
+
+  // ------------------------------------------------
+  // TEST CURVATURES
+  // ------------------------------------------------
+
+  else if ( !strcmp(parameters.task.c_str(),"Curvatures") )
+    {
+      ma->writePos("CurvDiv.pos",OD_CURVATURE_DIV);
+      ma->writePos("CurvMax.pos",OD_CURVATURE_MAX);
+      ma->writePos("CurvMin.pos",OD_CURVATURE_MIN);
+      ma->writePos("CurvMaxVec.pos",OD_CURVATURE_MAX_VEC);
+      ma->writePos("CurvMinVec.pos",OD_CURVATURE_MIN_VEC);
+      
+//       FIter fi = M_faceIter(mesh);
+//       pFace pf;
+//       while ( ( pf = FIter_next(fi) ) )
+//         {
+//           if ( F_whatInType(pf) != 2 ) continue;
+          
+//           pGEntity pge = F_whatIn(pf);
+//           {
+//             double u[2] = { 0., 0. };
+//             double xyz[3];
+//             GF_xyz( (pGFace) pge, u[0], u[1], xyz);
+//             printf("u: %f, v: %f\n",u[0],u[1]);
+//             printVec(xyz,"xyz");
+//           }
+          
+//           double u[2] = { 0.5, 0.5 };
+//           double xyz[3];
+//           GF_xyz( (pGFace) pge, u[0], u[1], xyz);
+//           printf("u: %f, v: %f\n",u[0],u[1]);
+//           printVec(xyz,"xyz");
+          
+//           double divCurv = GF_curvature( (pGFace)pge, u);
+//           double dirMax[3], dirMin[3], maxCurv, minCurv;
+//           double mCurv = GF_curvatures( (pGFace)pge, u,
+//                                         dirMax, dirMin, &maxCurv, &minCurv);
+          
+//           printVec(dirMax,"dirMax");
+//           printVec(dirMin,"dirMin");
+//           printf("Max curv: %f, min curv: %f, div curv: %f\n",maxCurv,minCurv,divCurv);
+          
+//           double tmp[3];
+//           tmp[0] = dotProd(xyz,dirMax);
+//           tmp[1] = dotProd(xyz,dirMin);
+//           tmp[2] = dotProd(dirMin,dirMax);
+//           printVec(tmp,"sould be 0 vector");
+          
+//           break;
+//         }
+//       FIter_delete(fi);
+    }
+
+  // ------------------------------------------------
+  else if ( !strcmp(parameters.task.c_str(),"None") )
+    {
+    }
+
+  else {
+    MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                "Unknown task %s",parameters.task.c_str());
+  }
+
+  // ------------------------------------------------
+  // Write final result
+  // ------------------------------------------------
+
+  ma->writeMsh("result.msh");
+//   ma->writePos("result.pos",OD_MEANRATIO);
+
+// #warning "Size field printed to debug"
+//     ma->writePos("sizeFieldFinalMean.pos", OD_SIZEFIELD_MEAN);
+//     ma->writePos("sizeFieldFinalMin.pos",  OD_SIZEFIELD_MIN);
+//     ma->writePos("sizeFieldFinalMax.pos",  OD_SIZEFIELD_MAX);
+//     ma->writePos("sizeFieldFinal0.pos",OD_ANISO_SF_AXIS0);
+//     ma->writePos("sizeFieldFinal1.pos",OD_ANISO_SF_AXIS1);
+//     ma->writePos("sizeFieldFinal2.pos",OD_ANISO_SF_AXIS2);
+// #warning "output curvature"
+//     ma->writeVolumicCurvature("curvatureFinal");
+
+  ma->printStatistics(cout);
+  ofstream statOut((outputPrefix + "statistics").c_str());
+  ma->printStatistics(statOut);
+
+  ofstream sliverOut((outputPrefix + "slivers").c_str());
+  ma->printSliverRegionStatistics(sliverOut);
+
+  ofstream journalOut((outputPrefix + "journal").c_str());
+  ma->flushJournal(journalOut);
+
+  // ------------------------------------------------
+  // Clean up
+  // ------------------------------------------------
+
+  if (ma) delete ma;
+  set<pSField>::iterator sfIter = sizeFields.begin();
+  set<pSField>::iterator sfLast = sizeFields.end();
+  for (; sfIter != sfLast; sfIter++) {
+    delete (*sfIter);
+  }
+  displayMemoryUsage("Adapter and size fields deleted");
+  
+  if (mesh)  M_delete(mesh);
+  if (model) GM_delete(model);
+  displayMemoryUsage("Mesh and model deleted");
+
+  MAdLibFinalize();
+
+  printf("Total execution time: %f seconds\n", CPUTime()-main_t0);
+}
+
+// ----------------------------------------------------------------------
diff --git a/Benchmarks/moveIt/moveItParse.h b/Benchmarks/moveIt/moveItParse.h
new file mode 100644
index 0000000..df96ca6
--- /dev/null
+++ b/Benchmarks/moveIt/moveItParse.h
@@ -0,0 +1,563 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MOVEITPARSE_
+#define _H_MOVEITPARSE_
+
+#ifdef _HAVE_PARSER_
+
+#include "Parser.h"
+
+#include "MSops.h"
+#include "MAdMessage.h"
+#include "Parameters.h"
+
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+
+extern int yyCMDparse();
+
+//==============================================================================
+// Control file definition 
+//==============================================================================
+
+void DefineMMCtrlFile() {
+  
+  // global input specifications
+  // ---------------------------
+
+  ClassParameter& input = Parser::instance().add("Input");
+  ClassParameter& inputMesh = input.add("Mesh");
+  inputMesh.addString("MshFile","");
+  inputMesh.addString("GeoFile","");
+  
+  // global output parameters
+  // ------------------------
+  
+  ClassParameter& output = Parser::instance().add("Output");
+  output.addString("Prefix","result/");
+  output.addInteger("Frequency",1);
+  output.addToken("Type",3,"MshAndPos","Msh","Pos","MshAndPos");
+
+  // Task parameters
+  // ----------------
+
+  ClassParameter& task = Parser::instance().add("Task");
+  task.addToken("Type",22,
+                "MobileObject",
+                "RemoveRegion",
+                "SizeField",
+                "RemoveSliverFaces",
+                "LaplaceSmoothing",
+                "GeoConstraints",
+                "TopoConstraints",
+                "FaceSwap",
+                "UglyMesh",
+                "RemoveSliverRegions",
+                "DESC",
+                "EdgeSwap",
+                "GeoMatcher",
+                "EdgeSplit",
+                "EdgeCollapse",
+                "EdgeSplitCollapse",
+                "FaceCollapse",
+                "OptimizeLength",
+                "OptimizeShape",
+                "Metric",
+                "Curvatures",
+                "None",
+                "MobileObject");
+
+  // debug parameters
+  // -----------------
+  
+  ClassParameter& debug = Parser::instance().add("Debug");
+  debug.addInteger("DebugLevel",1);
+  debug.addToken("OpenJournal",2,"Yes","No","No");
+  debug.addString("ReferenceJournal","");
+  debug.addToken("ReportSlivers",2,"Yes","No","No");
+  debug.addToken("TestSliverOperators",2,"Yes","No","No");
+
+  // Mesh adaptation
+  // ----------------
+
+  ClassParameter& ma = Parser::instance().add("Adaptation");
+  ma.addInteger("MaxNumberOfInnerIteration",10);
+  ma.addDouble("LowerLengthBound",1./sqrt(3.));
+  ma.addDouble("UpperLengthBound",sqrt(3.));
+  ma.addDouble("InfiniteEdgeLength",1.e14);
+  ma.addDouble("SwapMinImproveRatio",1.0);
+  ma.addDouble("SliverQuality",0.02);
+  ma.addToken("SplitCanMakeSlivers",2,"No","Yes","Yes");
+  ma.addToken("CollapseCanMakeSlivers",2,"No","Yes","Yes");
+  ma.addDouble("SliverLowerLengthSqBound",0.1);
+  ma.addDouble("SliverUpperLengthSqBound",10.);
+  ma.addToken("CollapseOnBoundary",2,"No","Yes","Yes");
+  ClassParameter& mabound = ma.add("BoundaryCollapses");
+  mabound.addDouble("Tolerance",1.e-6);
+  ma.addToken("SwapOnBoundary",2,"No","Yes","Yes");
+  ClassParameter& maboundswp = ma.add("BoundarySwaps");
+  maboundswp.addDouble("Tolerance",1.e-6);
+  ma.addToken("TrackGeometry",2,"No","Yes","No");
+  ClassParameter& masnap = ma.add("VertexSnapping");
+  masnap.addToken("IsMeshTheCavity",2,"No","Yes","No");
+  masnap.addInteger("CavityThickness",3);
+  masnap.addDouble("StiffnessAlteration",1.0);
+  ma.addToken("SmoothSizeField",2,"No","Yes","No");
+  ClassParameter& smoo = ma.add("SizeFieldSmoothing");
+  smoo.addDouble("MaximumGradient",1.0);
+  
+  // moving objects
+  // --------------
+
+  ClassParameter& mo = Parser::instance().add("MovingObjects");
+  ClassParameter& object = mo.addMultiple("Object");
+
+  // geometry
+  ClassParameter& obj_geom = object.add("Geometry");
+  obj_geom.addToken("GeometricalType",4,"Vertex","Edge","Face","Region","Face");
+  obj_geom.addIntegerRange("GeometricalTags");
+
+  // kinematics
+  ClassParameter& obj_kin = object.add("Kinematics");
+  obj_kin.addToken("KinematicsSpecification",2,"Displacement","Velocity","Displacement");
+  ClassParameter& kinDx = obj_kin.add("Displacement");
+  kinDx.addStringList("Formulation");
+  ClassParameter& kinV = obj_kin.add("Velocity");
+  kinV.addStringList("Formulation");
+
+  // size field
+  ClassParameter& locS = object.addMultiple("LocalSizeField");
+//   locS.addDouble("Radius",0.);
+//   locS.addToken("SizeFunction",2,"Linear","Sqrt","Linear");
+//   locS.addDouble("SizeOnObject",1.);
+//   locS.addDouble("SizeOutside",1.);
+//   locS.addToken("Orientation",2,"Isotropic","Anisotropic","Isotropic");
+//   ClassParameter& anisoLsf = locS.add("Anisotropic");
+//   anisoLsf.addDouble("SizeTangent",1.);
+  locS.addToken("DistanceComputation",2,"ToWallVertices","ToWallFaces","ToWallVertices");
+  locS.addToken("Orientation",2,"Isotropic","Anisotropic","Isotropic");
+  locS.addDouble("Radius",0.);
+  ClassParameter& isoLsf = locS.add("Isotropic");
+  isoLsf.addString("Size","");
+  ClassParameter& anisoLsf = locS.add("Anisotropic");
+  anisoLsf.addString("NormalSize","");
+  anisoLsf.addString("TangentSize","");
+  ClassParameter& limiter = locS.add("CurvatureBasedLimiter");
+  limiter.addToken("Enable",2,"Yes","No","No");
+  limiter.addDouble("TangentSizeOverRadius",1.);
+  limiter.addDouble("CurvatureLimiter",1.e6);
+
+  // Size Field parameters
+  // ---------------------
+
+  ClassParameter& sf = Parser::instance().addMultiple("SizeField");
+  sf.addToken("Type",2,"Analytical","PiecewiseLinear","Analytical");
+  ClassParameter& sf_an = sf.add("Analytical");
+  sf_an.addToken("OrientationType",2,"Isotropic","Anisotropic","Isotropic");
+  ClassParameter& sf_an_iso = sf_an.add("Isotropic");
+  sf_an_iso.addString("Length","");
+  ClassParameter& sf_an_aniso = sf_an.add("Anisotropic");
+  sf_an_aniso.addStringList("Lengths");
+  sf_an_aniso.addStringList("Direction1");
+  sf_an_aniso.addStringList("Direction2");
+  sf_an_aniso.addStringList("Direction3");
+  ClassParameter& sf_pwl = sf.add("PiecewiseLinear");
+  sf_pwl.addToken("Source",2,"InitialLength","Curvature","Curvature");
+  ClassParameter& sf_pwl_curv = sf_pwl.add("Curvature");
+  sf_pwl_curv.addToken("Anisotropic",2,"Yes","No","Yes");
+  sf_pwl_curv.addDouble("Alpha",2.);
+  sf_pwl_curv.addDouble("MinimalLength",1.e-4);
+  
+  // Node motion
+  // -----------
+
+  ClassParameter& nm = Parser::instance().add("NodeMotion");
+  nm.addToken("Type",3,"ElasticAnalogy","ForceBoundaries","None","None");
+  ClassParameter& maelas = nm.add("ElasticParameters");
+  maelas.addToken("IsMeshTheCavity",2,"No","Yes","Yes");
+  maelas.addInteger("CavityThickness",3);
+  maelas.addDouble("StiffnessAlteration",1.0);
+
+  // Time parameters
+  // ---------------
+
+  ClassParameter& time = Parser::instance().add("TimeSpecifications"); 
+  time.addInteger("MaxTimeSteps",1000000);
+  time.addDouble("TimeStep",0.1);
+  time.addDouble("FinalTime",-1.0);
+}
+
+//==============================================================================
+// Parsing functions
+//==============================================================================
+
+string parseMMCommandLine(int argc,char** argv) {
+
+  string inputFile = "";
+  string templateFile = "";
+
+  bool inputFileSpecified = false;
+  bool dumpTemplate   = false;
+
+  if (argc == 1) {
+    dumpTemplate = true;
+  }
+  else if ( argc==2 ){
+    inputFileSpecified = true;
+    inputFile = argv[1];
+  }
+  else {
+    std::cerr << "Usages:" << argv[0]<<"  control_file"<<std::endl;
+    exit(1);
+  }
+  
+  // dump a template file 
+  
+  if (dumpTemplate) {
+    templateFile = "template.mad";
+    FILE* fpcheck = fopen(templateFile.c_str(),"w");
+    fprintf(fpcheck,"//-*- C++ -*-\n");
+    printf("Writing a template parameter tree to file \'%s\'\n",templateFile.c_str());
+    Parser::instance().print(fpcheck);  
+    fclose(fpcheck);
+    exit(1);
+  } 
+
+  // read the parameters 
+  
+  if (!inputFileSpecified || inputFile == "") {
+    printf("No parameter file was specified - exiting");
+    exit(1);
+  }
+  
+  return inputFile;
+}
+
+// -----------------------------------------------------------------------------
+bool parseMMCtrlFile(const string& inputFile) {
+
+  FILE* fp = freopen(inputFile.c_str(), "r", stdin);
+  if (!fp) {
+    printf("Error: could not open parameter file \'%s\'\n",inputFile.c_str());
+    return false;
+  }
+  
+  yyCMDparse();
+
+  return true;
+}
+
+// ----------------------------------------------------------------------
+// Parse the control file
+void parseControlFile(int argc, char* argv[])
+{
+  cout << "Parsing the control file...\n";
+  DefineMMCtrlFile();
+  string inputFile = parseMMCommandLine(argc,argv);
+  parseMMCtrlFile(inputFile);
+}
+
+// ----------------------------------------------------------------------
+void setCurrentParameters(MoveParameters * params)
+{
+  // ------------------------------------------------
+  // Fill in 'params' with the parsed values
+  // ------------------------------------------------
+  cout << "Fill in the parameters from the control file...\n";
+
+  // mesh and geometry parameters
+  // -----------------------------
+
+  ClassParameter& input = Parser::instance().get("Input"); 
+  ClassParameter& inputMesh = input.get("Mesh");
+  params->meshFileName = inputMesh.getString("MshFile");
+  params->geoFileName  = inputMesh.getString("GeoFile");
+  
+  // global output parameters
+  // ------------------------
+
+  ClassParameter& outputParam = Parser::instance().get("Output");
+  params->outType = outputParam.getToken("Type");
+  params->outFrequency = outputParam.getInteger("Frequency");
+  params->outPrefix = outputParam.getString("Prefix");
+
+  // Global task parameters
+  // ----------------------
+
+  ClassParameter& taskParams = Parser::instance().get("Task");
+  params->task = taskParams.getToken("Type");
+
+  // debugging parmeters
+  // --------------------
+
+  ClassParameter& debugParams = Parser::instance().get("Debug");
+  params->debugLevel = debugParams.getInteger("DebugLevel");
+
+  params->openJournal = false;
+  string openJournal = debugParams.getToken("OpenJournal");
+  if ( !strcmp(openJournal.c_str(),"Yes") ) params->openJournal = true;
+
+  params->referenceJournal = debugParams.getString("ReferenceJournal");
+
+  params->sliverReports = false;
+  string sliverReports = debugParams.getToken("ReportSlivers");
+  if ( !strcmp(sliverReports.c_str(),"Yes") ) params->sliverReports = true;
+
+  params->testSliverOperators = false;
+  string sliverOps = debugParams.getToken("TestSliverOperators");
+  if ( !strcmp(sliverOps.c_str(),"Yes") ) params->testSliverOperators = true;
+
+  // Mesh adaptation
+  // ----------------
+
+  ClassParameter& adParam = Parser::instance().get("Adaptation");
+  params->maxInnerIter = adParam.getInteger("MaxNumberOfInnerIteration");
+  params->lowerLength = adParam.getDouble("LowerLengthBound");
+  params->upperLength = adParam.getDouble("UpperLengthBound");
+  params->infLength = adParam.getDouble("InfiniteEdgeLength");
+  params->swapMinImproveRatio = adParam.getDouble("SwapMinImproveRatio");
+  params->sliverQuality = adParam.getDouble("SliverQuality");
+
+  params->splitCanMakeSlivers = false;
+  string slivSpl = adParam.getToken("SplitCanMakeSlivers");
+  if ( !strcmp(slivSpl.c_str(),"Yes") ) params->splitCanMakeSlivers = true;
+  params->makeSliverInSplitLenSqBound = adParam.getDouble("SliverUpperLengthSqBound");
+
+  params->collapseCanMakeSlivers = false;
+  string slivColl = adParam.getToken("CollapseCanMakeSlivers");
+  if ( !strcmp(slivColl.c_str(),"Yes") ) params->collapseCanMakeSlivers = true;
+  params->makeSliverInCollapseLenSqBound = adParam.getDouble("SliverLowerLengthSqBound");
+
+  params->collapseOnBoundary = false;
+  string clpOnB = adParam.getToken("CollapseOnBoundary");
+  if ( !strcmp(clpOnB.c_str(),"Yes") ) params->collapseOnBoundary = true;
+  params->clpOnBdryTolerance = adParam.get("BoundaryCollapses").getDouble("Tolerance");
+
+  params->swapOnBoundary = false;
+  string swapOnB = adParam.getToken("SwapOnBoundary");
+  if ( !strcmp(swapOnB.c_str(),"Yes") ) params->swapOnBoundary = true;
+  params->swapOnBdryTolerance = adParam.get("BoundarySwaps").getDouble("Tolerance");
+
+  params->trackGeometry = false;
+  string trackGeo = adParam.getToken("TrackGeometry");
+  if ( !strcmp(trackGeo.c_str(),"Yes") ) {
+    if ( params->geoFileName.empty() ) {
+      printf("Error: you have to provide a geometry file if you want to track geometry\n");
+      throw;
+    }
+    params->trackGeometry = true;
+  }
+  ClassParameter& snapParams = adParam.get("VertexSnapping");
+  params->snap_cavityIsMesh = false;
+  if ( !strcmp( snapParams.getToken("IsMeshTheCavity"), "Yes" ) ) {
+    params->snap_cavityIsMesh = true;
+  }
+  params->snap_thickness = snapParams.getInteger("CavityThickness");
+  params->snap_chi       = snapParams.getDouble("StiffnessAlteration");
+  
+  params->SFSmoothing = false;
+  string smoothSF = adParam.getToken("SmoothSizeField");
+  if ( !strcmp(smoothSF.c_str(),"Yes") ) params->SFSmoothing = true;
+  ClassParameter& smoothParams = adParam.get("SizeFieldSmoothing");
+  params->SFSmoothGrad = smoothParams.getDouble("MaximumGradient");
+  
+  // Node motion
+  // -----------
+
+  ClassParameter& reposParams = Parser::instance().get("NodeMotion");
+  params->nodeMotionType = reposParams.getToken("Type");
+  ClassParameter& elParams = reposParams.get("ElasticParameters");
+  params->elasticStiffnessAlteration = elParams.getDouble("StiffnessAlteration");
+  params->elasticIsMeshTheCavity = false;
+  if ( !strcmp( elParams.getToken("IsMeshTheCavity"), "Yes" ) ) {
+    params->elasticIsMeshTheCavity = true;
+  }
+  params->elasticCavityThickness = elParams.getInteger("CavityThickness");
+
+  // Time parameters
+  // ---------------
+
+  ClassParameter& temporalParameters = Parser::instance().get("TimeSpecifications");
+  params->timeStep       = temporalParameters.getDouble("TimeStep");
+  params->finalTime      = temporalParameters.getDouble("FinalTime");
+  params->maxNbTimeSteps = temporalParameters.getInteger("MaxTimeSteps");
+  
+  // Moving objects
+  // --------------
+
+  ClassParameter& objsParam = Parser::instance().get("MovingObjects");
+  for (int iObj = 0; iObj < objsParam.get("Object").size(); iObj++)
+    {
+      ClassParameter& objParam = objsParam.get("Object",iObj);
+
+      ObjectDef object;
+
+      // --- Name ---
+
+      object.name = objParam.getTag();
+
+      // --- Geometry ---
+
+      ClassParameter& geoPar = objParam.get("Geometry");
+      string geomType = geoPar.getToken("GeometricalType");
+      if     (geomType == "Vertex")  object.geomLevel=0;
+      else if(geomType == "Edge")    object.geomLevel=1;
+      else if(geomType == "Face")    object.geomLevel=2;
+      else if(geomType == "Region")  object.geomLevel=3;
+      else
+        printf("Error: unknown geometrical type %s",geomType.c_str());
+      // get tags of entities
+      //   vector<int> geomTags = geoPar.getIntegerList("GeometricalTags");
+      vector<pair<int,int> > geomTags = geoPar.getIntegerRange("GeometricalTags");
+      for (unsigned int iTag = 0; iTag < geomTags.size(); iTag++ )
+        for (int iTag2 = (geomTags[iTag]).first; iTag2 <= (geomTags[iTag]).second; iTag2++)
+          object.geomTags.insert(iTag2);
+
+      // --- Kinematics ---
+
+      ClassParameter& kinPar = objParam.get("Kinematics");
+      string kinType = kinPar.getToken("KinematicsSpecification");
+      if ( !strcmp(kinType.c_str(),"Displacement") ) {
+        object.kinType = KT_DISPLACEMENT;
+        MAd::MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+                                           "Displacement formulation for object is wrong when using geometry tracking");
+        ClassParameter& kinParDx = kinPar.get("Displacement");
+        object.kinExpression = kinParDx.getStringList("Formulation");
+      }
+
+      else if ( !strcmp(kinType.c_str(),"Velocity") ) {
+        object.kinType = KT_VELOCITY;
+        ClassParameter& kinParV = kinPar.get("Velocity");
+        object.kinExpression = kinParV.getStringList("Formulation");
+      }
+      else throw;
+
+      if (object.kinExpression.size() != 3) {
+        cerr << "Error: exactly 3 components are required in the displacement/velocity strings list\n";
+        throw;
+      }
+
+      // --- Local size fields ---
+
+      for (int iSF = 0; iSF < objParam.get("LocalSizeField").size(); iSF++) {
+        ClassParameter& sizeP = objParam.get("LocalSizeField",iSF);
+        
+        LocalSFDef localSF;
+
+        localSF.name = sizeP.getTag();
+
+        string distComp = sizeP.getToken("DistanceComputation");
+        localSF.distToFaces = false;
+        if ( !strcmp( distComp.c_str(), "ToWallFaces" ) ) {
+          localSF.distToFaces = true;
+        }
+
+        localSF.radius = sizeP.getDouble("Radius");
+
+        string iso = sizeP.getToken("Orientation");
+        if ( !strcmp(iso.c_str(),"Isotropic") ) {
+          localSF.isotropic = true;
+          ClassParameter& isoP = sizeP.get("Isotropic");
+          localSF.sizeN = isoP.getString("Size");
+        }
+        else {
+          localSF.isotropic = false;
+          ClassParameter& anisoP = sizeP.get("Anisotropic");
+          localSF.sizeN  = anisoP.getString("NormalSize");
+          localSF.sizeT  = anisoP.getString("TangentSize");
+        }
+
+        ClassParameter& limiter = sizeP.get("CurvatureBasedLimiter");
+        localSF.limit = false;
+        if ( !strcmp(limiter.getToken("Enable"), "Yes") ) {
+          localSF.limit = true;
+          localSF.limitSizeTg = limiter.getDouble("TangentSizeOverRadius");
+          localSF.maxCurv     = limiter.getDouble("CurvatureLimiter");
+        }
+        
+        object.sizes.push_back(localSF);
+      }
+
+      params->objects.push_back(object);
+    }
+
+  // Size Field parameters
+  // ---------------------
+
+  for (int iSF = 0; iSF < Parser::instance().get("SizeField").size(); iSF++)
+    {
+      ClassParameter& sfParam = Parser::instance().get("SizeField",iSF);
+      string sfType = sfParam.getToken("Type");
+
+      SizeFieldDef sfDef;
+
+      // Analytical:
+      if ( !strcmp(sfType.c_str(),"Analytical") )
+        {
+          sfDef.type = MAd::ANALYTICALSFIELD;
+          
+          ClassParameter& anParam = sfParam.get("Analytical");
+          string orient = anParam.getToken("OrientationType");
+          if ( !strcmp(orient.c_str(),"Isotropic") ) {
+            sfDef.orientation = ORT_ISOTROPIC;
+            sfDef.isoSize = anParam.get("Isotropic").getString("Length");
+          }
+          else {
+            sfDef.orientation = ORT_ANISOTROPIC;
+            ClassParameter& an_anisoParam = anParam.get("Anisotropic");
+            
+            sfDef.anisoSize = an_anisoParam.getStringList("Lengths");
+            sfDef.anisoDir0 = an_anisoParam.getStringList("Direction1");
+            sfDef.anisoDir1 = an_anisoParam.getStringList("Direction2");
+            sfDef.anisoDir2 = an_anisoParam.getStringList("Direction3");
+            
+            if ( sfDef.anisoSize.size() != 3 || 
+                 sfDef.anisoDir0.size() != 3 || 
+                 sfDef.anisoDir1.size() != 3 ||  
+                 sfDef.anisoDir2.size() != 3 ) {
+              cerr << "Invalid number of strings in one of the lists (anisotropic case)\n";
+              throw;
+            }
+          }
+        }
+
+      // Piecewise linear:
+      else if ( !strcmp(sfType.c_str(),"PiecewiseLinear") )
+        {
+          sfDef.type = MAd::DISCRETESFIELD;
+          ClassParameter& sf_pwl = sfParam.get("PiecewiseLinear");
+          sfDef.pwlSource = sf_pwl.getToken("Source");
+          ClassParameter& sf_pwl_curv = sf_pwl.get("Curvature");
+  
+          sfDef.curv_aniso = false;
+          if ( !strcmp( sf_pwl_curv.getToken("Anisotropic"), "Yes") ) {
+            sfDef.curv_aniso = true;
+          }
+          sfDef.curv_alpha = sf_pwl_curv.getDouble("Alpha");
+          sfDef.curv_hMin  = sf_pwl_curv.getDouble("MinimalLength");
+        }
+
+      else throw;
+
+      params->sizes.push_back(sfDef);
+    }
+}
+
+// -----------------------------------------------------------------------------
+
+#endif
+
+#endif
diff --git a/Benchmarks/optimize/Makefile b/Benchmarks/optimize/Makefile
new file mode 100644
index 0000000..48353fe
--- /dev/null
+++ b/Benchmarks/optimize/Makefile
@@ -0,0 +1,59 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information. 
+# You should have received a copy of these files along with MAdLib. 
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../../variables
+
+BIN = $(MAdROOT)/bin/optimize
+
+INC =  ${MAdLib_INCLUDES}\
+       ${DASH}I$(MAdROOT)/Geo\
+       ${DASH}I$(MAdROOT)/Mesh\
+       ${DASH}I$(MAdROOT)/Common\
+       ${DASH}I$(MAdROOT)/Adapt\
+       ${DASH}I$(MAdROOT)/Adapt/constraint\
+       ${DASH}I$(MAdROOT)/Adapt/operator\
+       ${DASH}I$(MAdROOT)/Adapt/output\
+       ${DASH}I$(MAdROOT)/Adapt/quality\
+       ${DASH}I$(MAdROOT)/Adapt/repositioning\
+       ${DASH}I$(MAdROOT)/Adapt/sizeField\
+       ${DASH}I$(MAdROOT)/Adapt/utils
+
+ALLFLAGS = ${OPTIM} ${CXXFLAGS} ${MAdLib_DEFS} ${FLAGS} ${INC} ${SYSINCLUDE}
+
+SRC = main.cc
+
+OBJ = ${SRC:.cc=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cc
+
+${BIN}: ${OBJ}
+	${LINKER} ${OPTIM} ${DASH}o $@ $(OBJ) ${MAdLib_LIBS}
+
+cpobj: ${OBJ} 
+	cp -f ${OBJ} $(MAdROOT)/bin/
+
+.cc${OBJEXT}:
+	${CXX} ${ALLFLAGS} ${DASH}c $< ${DASH}o $@
+
+clean:
+	${RM} *.o *.obj
+
+purge:
+	${RM} *.msh *.geo *.pos
+
+depend:
+	(sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+         ${CXX} -MM ${ALLFLAGS} ${SRC} | sed 's/.o:/$${OBJEXT}:/g' \
+        ) > Makefile.new
+	cp Makefile Makefile.bak
+	cp Makefile.new Makefile
+	rm -f Makefile.new
\ No newline at end of file
diff --git a/Benchmarks/optimize/main.cc b/Benchmarks/optimize/main.cc
new file mode 100644
index 0000000..8589bda
--- /dev/null
+++ b/Benchmarks/optimize/main.cc
@@ -0,0 +1,80 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MSops.h"
+#include "AdaptInterface.h"
+#include "NullSField.h"
+#include "AnalyticalSField.h"
+
+#include <iostream>
+using std::cout;
+#include <string>
+using std::string;
+#include <vector>
+using std::vector;
+
+using namespace MAd;
+
+// ----------------------------------------------------------------------
+int main(int argc, char* argv[]) {
+
+  // Check input
+  // ------------
+  if ( argc != 2 ) {
+    printf("Error: usage: \'executable mshFile\'\n");
+    exit(0);
+  }
+  string meshFile = argv[1];
+
+  // Build tools
+  // ------------
+  pGModel model = 0;
+  pMesh mesh = M_new(model);
+  M_load(mesh,meshFile.c_str());
+
+  PWLSField * sizeField = new PWLSField(mesh);
+  sizeField->setCurrentSize();
+//   vector<string> h, e0, e1, e2;
+//   h.push_back("0.50"); h.push_back("0.05"); h.push_back("0.01");
+//   e0.push_back("1.0"); e0.push_back("0.0"); e0.push_back("0.0");
+//   e1.push_back("0.0"); e1.push_back("1.0"); e1.push_back("0.0");
+//   e2.push_back("0.0"); e2.push_back("0.0"); e2.push_back("1.0");
+//   AnalyticalSField* asf = new AnalyticalSField(h, e0, e1, e2);
+  
+//   MeshAdapter* ma = new MeshAdapter(mesh,asf);
+  MeshAdapter* ma = new MeshAdapter(mesh,sizeField);
+
+  // Output situation before optimization
+  // -------------------------------------
+  printf ("Statistics before optimization: \n");
+  ma->printStatistics(std::cout);
+  ma->writePos("meanRatioBefore.pos",OD_MEANRATIO);
+
+  // Optimize
+  // ---------
+  printf ("Optimizing mesh %s...\n\n",meshFile.c_str());
+  ma->run();
+
+  // Outputs final mesh
+  // -------------------
+  printf ("Statistics after optimization: \n");
+  ma->printStatistics(std::cout);
+  ma->writePos("meanRatioAfter.pos",OD_MEANRATIO);
+  M_writeMsh (mesh, "result.msh", 2, NULL);
+
+  // Cleaning
+  // ---------
+  if (ma) delete ma;
+  if (sizeField) delete sizeField;
+}
+
+// ----------------------------------------------------------------------
diff --git a/Common/MAdDefines.h b/Common/MAdDefines.h
new file mode 100644
index 0000000..b0faeca
--- /dev/null
+++ b/Common/MAdDefines.h
@@ -0,0 +1,35 @@
+// -*- C++ -*-
+
+#ifndef _H_MADDEFINES
+#define _H_MADDEFINES
+
+#define MAdTHIRD 0.33333333333333
+#define MAdSIXTH 0.16666666666667
+
+#define MAdPI    3.14159265358979
+#define MAdPITH  0.31830988618379
+
+#define MAdBIG   1.e14
+#define MAdTOL   1.e-12
+#define MAdTOLSQ 1.e-24
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  enum operationType {
+    MAd_UNKNOWNOPERATION = 0,
+    MAd_VERTEXMOVE       = 1,
+    MAd_ESPLIT           = 2,
+    MAd_ECOLLAPSE        = 3,
+    MAd_FCOLLAPSE        = 4,
+    MAd_DESPLTCLPS       = 5,
+    MAd_ESWAP            = 6,
+    MAd_FSWAP            = 7,
+    MAd_RREMOVE          = 8
+  };
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Common/MAdFieldEvaluator.h b/Common/MAdFieldEvaluator.h
new file mode 100644
index 0000000..5b2da8e
--- /dev/null
+++ b/Common/MAdFieldEvaluator.h
@@ -0,0 +1,81 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MADFIELDEVALUATORBASE
+#define _H_MADFIELDEVALUATORBASE
+
+#include <ostream>
+#include <string>
+
+namespace MAd {
+
+  // ----------------------------------------------------------------------
+  class MAdFieldEvaluator{
+  public:
+    virtual bool eval (const double space[3], double time, double* val) const = 0;
+    virtual int order () const = 0;
+    virtual int nbVar () const = 0;
+    virtual ~MAdFieldEvaluator(){};
+
+    virtual void describe(std::ostream& out, const std::string& prefix) const {out << prefix << "Dummy field evaluator \n";} 
+  };
+
+  // ----------------------------------------------------------------------
+  class MAdConstantScalar : public MAdFieldEvaluator
+  {
+    double X;
+  public :
+    MAdConstantScalar(double v):X(v){}
+    inline bool eval (const double space[3], double time, double* val) const {
+      val[0] = X;
+      return true;
+    }
+    inline int order() const{
+      return 0;
+    }
+    virtual int nbVar () const {return 1;}
+
+    virtual void describe(std::ostream& out,const std::string& prefix="") const{
+      out << prefix << "Constant scalar field evaluator u(x,y,z,t) = " << X << "\n";
+    }
+  
+  };
+
+  // ----------------------------------------------------------------------
+  class MAdConstantVector : public MAdFieldEvaluator
+  {
+    double U,V,W;
+  public:
+    MAdConstantVector(double ux=0,double uy=0,double uz=0):U(ux),V(uy),W(uz){}
+    inline bool eval (const double space[3], double time, double* val) const{
+      val[0] = U;
+      val[1] = V;
+      val[2] = W;
+      return true;
+    }
+    inline int order() const{
+      return 0;
+    }
+    virtual int nbVar () const {return 3;}
+  
+    virtual void describe(std::ostream& out,const std::string& prefix="") const{
+      out << prefix << "Constant vector field evaluator u(x,y,z,t) = (" << U << "," << V << "," << W << ")\n";
+    }
+  
+  };
+
+  // ----------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Common/MAdLib.cc b/Common/MAdLib.cc
new file mode 100644
index 0000000..57e299e
--- /dev/null
+++ b/Common/MAdLib.cc
@@ -0,0 +1,65 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifdef _HAVE_GMSH_
+#include "gmsh/Gmsh.h"
+#endif
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+#endif
+
+#include "MAdMessage.h"
+#include "MAdResourceManager.h"
+
+#include <string>
+using std::string;
+
+using namespace MAd;
+
+void MAdLibInitialize(int * argc, char** argv[])
+{
+#ifdef PARALLEL
+  MPI_Init(argc,argv);
+  AP_init(argc,argv);
+#endif
+
+#ifdef _HAVE_GMSH_
+  char * tmp[1];
+  tmp[0] = (char*)" ";
+  GmshInitialize(1,tmp);
+  unsigned int i = 1;
+  int j = 0;
+  GmshSetOption("General","Terminal",i,j);
+#endif
+
+  MAdMsgSgl::instance().initialize();
+  MAdResourceManagerSgl::instance().initialize();
+}
+
+void MAdLibFinalize()
+{
+  MAdResourceManagerSgl::instance().finalize();
+  MAdMsgSgl::instance().finalize();
+
+#ifdef _HAVE_GMSH_
+  GmshFinalize();
+#endif
+
+#ifdef PARALLEL
+  MPI_Barrier(MPI_COMM_WORLD);
+  AP_finalize();
+  MPI_Finalize();
+#endif
+}
+
diff --git a/Common/MAdLib.h b/Common/MAdLib.h
new file mode 100644
index 0000000..5d28b37
--- /dev/null
+++ b/Common/MAdLib.h
@@ -0,0 +1,31 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MAD_MADLIB
+#define _H_MAD_MADLIB
+
+// interface to the geometrical model
+#include "ModelInterface.h"
+
+// interface to the mesh
+#include "MeshDataBaseInterface.h"
+
+// interface to mesh adaptation
+#include "AdaptInterface.h"
+
+//! Needed with the Gmsh geometrical model
+void MAdLibInitialize(int * argc, char** argv[]);
+void MAdLibFinalize();
+
+#endif
+
diff --git a/Common/MAdMatrix.cc b/Common/MAdMatrix.cc
new file mode 100644
index 0000000..4a3f14e
--- /dev/null
+++ b/Common/MAdMatrix.cc
@@ -0,0 +1,95 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MAdMatrix.h"
+
+#if defined(HAVE_LAPACK)
+extern "C" {
+  void dgesv_(int *N, int *nrhs, double *A, int *lda, int *ipiv, 
+              double *b, int *ldb, int *info);
+  void dgetrf_(int *M, int *N, double *A, int *lda, int *ipiv, int *info);
+  void dgesvd_(const char* jobu, const char *jobvt, int *M, int *N,
+               double *A, int *lda, double *S, double* U, int *ldu,
+               double *VT, int *ldvt, double *work, int *lwork, int *info);
+  void dgeev_(const char *jobvl, const char *jobvr, 
+	      int *n, double *a, int *lda, 
+	      double *wr, double *wi, 
+	      double *vl, int *ldvl, 
+	      double *vr, int *ldvr, 
+	      double *work, int *lwork,
+	      int *info); 
+}
+#endif
+
+namespace MAd {
+
+#if defined(HAVE_LAPACK)
+
+  template<> 
+  bool MAd_BLASLAPACK_Matrix<double>::eig(MAd_BLASLAPACK_Matrix<double> &VL, // left eigenvectors 
+                                          MAd_BLASLAPACK_Vector<double> &DR, // Real part of eigenvalues
+                                          MAd_BLASLAPACK_Vector<double> &DI, // Im part of eigenvalues
+                                          MAd_BLASLAPACK_Matrix<double> &VR,
+                                          bool sortRealPart ) // if true: sorted from max '|DR|' to min '|DR|'
+  {
+    int N = size1(), info;
+    int LWORK = 10*N;
+    double * work = new double[LWORK];
+      
+    dgeev_("V","V",
+           &N,_data,
+           &N,DR.data,DI.data,
+           VL._data,&N,
+           VR._data,&N,
+           work,&LWORK,&info);
+      
+    delete [] work;
+      
+    if(info == 0)
+      {
+        if (sortRealPart) {
+          double tmp[8];
+          // do permutations
+          for (int i=0; i<(size1()-1); i++) {
+            int maxR = i;
+            for (int j=i+1; j<size1(); j++) if ( fabs(DR(j)) > fabs(DR(maxR)) ) maxR = j;
+            if ( maxR != i )
+              {
+                tmp[0] = DR(i); tmp[1] = DI(i);
+                tmp[2] = VL(0,i); tmp[3] = VL(1,i); tmp[4] = VL(2,i);
+                tmp[5] = VR(0,i); tmp[6] = VR(1,i); tmp[7] = VR(2,i);
+                  
+                DR(i) = DR(maxR); DI(i) = DI(maxR);
+                VL(0,i) = VL(0,maxR); VL(1,i) = VL(1,maxR); VL(2,i) = VL(2,maxR);
+                VR(0,i) = VR(0,maxR); VR(1,i) = VR(1,maxR); VR(2,i) = VR(2,maxR);
+                  
+                DR(maxR) = tmp[0]; DI(maxR) = tmp[1];
+                VL(0,maxR) = tmp[2]; VL(1,maxR) = tmp[3]; VL(2,maxR) = tmp[4];
+                VR(0,maxR) = tmp[5]; VR(1,maxR) = tmp[6]; VR(2,maxR) = tmp[7];
+              }
+          }
+        }
+        return true;
+      }
+    if(info > 0)
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "QR Algorithm failed to compute all the eigenvalues (info = %d)", info);
+    else
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Wrong %d-th argument in eig (info = %d)", -info);
+
+    return false;
+  }
+
+#endif
+}
diff --git a/Common/MAdMatrix.h b/Common/MAdMatrix.h
new file mode 100644
index 0000000..1fa73d7
--- /dev/null
+++ b/Common/MAdMatrix.h
@@ -0,0 +1,923 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MATRIX_MAD
+#define _H_MATRIX_MAD
+
+#include "MAdMessage.h"
+
+#include <assert.h>
+#include <math.h>
+#include <iostream>
+
+#if defined(_HAVE_GSL_)
+#include <gsl/gsl_linalg.h>
+#include <gsl/gsl_matrix.h>
+#include <gsl/gsl_vector.h>
+#include <gsl/gsl_blas.h>
+#endif
+
+// -------------------------------------------------------------------
+#if defined(HAVE_BLAS)
+extern "C" {
+  void dgemm_(const char *transa, const char *transb, int *m, int *n, int *k, 
+              double *alpha, double *a, int *lda, double *b, int *ldb, 
+              double *beta, double *c, int *ldc);
+  void dgemv_(const char *trans, int *m, int *n, double *alpha, double *a, 
+              int *lda, double *x, int *incx, double *beta, double *y, int *incy);
+}
+#endif
+
+// -------------------------------------------------------------------
+#if defined(HAVE_LAPACK)
+extern "C" {
+  void dgesv_(int *N, int *nrhs, double *A, int *lda, int *ipiv, 
+              double *b, int *ldb, int *info);
+  void dgetrf_(int *M, int *N, double *A, int *lda, int *ipiv, int *info);
+  void dgesvd_(const char* jobu, const char *jobvt, int *M, int *N,
+               double *A, int *lda, double *S, double* U, int *ldu,
+               double *VT, int *ldvt, double *work, int *lwork, int *info);
+  void dgeev_(const char *jobvl, const char *jobvr, 
+	      int *n, double *a, int *lda, 
+	      double *wr, double *wi, 
+	      double *vl, int *ldvl, 
+	      double *vr, int *ldvr, 
+	      double *work, int *lwork,
+	      int *info); 
+}
+#endif
+
+// -------------------------------------------------------------------
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  // Basic vector / matrix
+  // -------------------------------------------------------------------
+  template <class SCALAR>
+  class MAd_Vector
+  {
+  private:
+    int r;
+  public:
+    inline int size() const { return r; }
+    SCALAR *data;
+    ~MAd_Vector() { if(data) delete [] data; }
+    MAd_Vector() : r(0)
+    {
+      data = 0;
+    }
+    MAd_Vector(int R) : r(R)
+    {
+      data = new SCALAR[r];
+      scale(0);
+    }
+    MAd_Vector(const MAd_Vector<SCALAR> &other) : r(other.r)
+    {
+      data = new SCALAR[r];
+      for (int i = 0; i < r; ++i) data[i] = other.data[i];
+    }
+    inline MAd_Vector<SCALAR> operator= (const MAd_Vector<SCALAR> &other)
+    {
+      if ( this != &other ) {
+        r = other.r;
+        if (data) delete [] data;
+        data = new SCALAR[r];
+        for (int i = 0; i < r; ++i) data[i] = other.data[i];
+      }
+      return *this;
+    }
+    inline SCALAR operator () (int i) const
+    {
+      return data[i];
+    }
+    inline SCALAR & operator () (int i)
+    {
+      return data[i];
+    }
+    inline double norm()
+    {
+      double n = 0.;
+      for(int i = 0; i < r; ++i) n += data[i] * data[i];
+      return sqrt(n);
+    }
+    inline void scale(const SCALAR s)
+    {
+      for (int i = 0; i < r; ++i) data[i] *= s;
+    }
+    inline void set_all(const double &m) 
+    {
+      for (int i = 0; i < r; ++i) data[i] = m;
+    }
+    inline void add(const MAd_Vector &v) 
+    {
+      for (int i = 0; i < r; ++i) data[i] += v(i);    
+    }
+    void print(std::string name) const
+    {
+      printf("Vector %s:\n  ",name.c_str());
+      for (int i = 0; i < r; ++i) printf("%12.5E ",data[i]);
+      printf("\n");
+    }
+  };
+
+  // -------------------------------------------------------------------
+  template <class SCALAR>
+  class MAd_Matrix
+  {
+  private:
+    int _r, _c; // r = nb rows, c = nb columns
+    SCALAR *_data;
+
+  public:
+
+    MAd_Matrix(int R,int C) : _r(R), _c(C)
+    {
+      _data = new SCALAR[_r * _c];
+      scale(0.);
+    }
+    MAd_Matrix(const MAd_Matrix<SCALAR> &other) : _r(other._r), _c(other._c)
+    {
+      _data = new double[_r * _c];
+      memcpy(other);
+    }
+    MAd_Matrix() : _r(0), _c(0), _data(0) {}
+    ~MAd_Matrix() { delete [] _data; }
+
+  public:
+
+    void print()const {
+			printf("matrix(%d,%d)",_r,_c);
+			for(int i=0;i<_r;i++){
+				for(int j=0;j<_c;j++){
+					printf("%0.3e\t",_data[i + _r * j]);
+				}
+				printf("\n");
+			}
+			printf("--------\n");
+		}
+
+    inline int size1() const { return _r; }
+    inline int size2() const { return _c; }
+
+    inline SCALAR operator () (int i, int j) const
+    {
+      return _data[i + _r * j];
+    }
+    inline SCALAR & operator () (int i, int j)
+    {
+      return _data[i + _r * j];
+    }
+
+    MAd_Matrix<SCALAR> & operator = (const MAd_Matrix<SCALAR> &other)
+    {
+      if(this != &other){
+        _r = other._r; 
+        _c = other._c;
+        _data = new SCALAR[_r * _c];
+        memcpy(other);
+      }
+      return *this;
+    }
+    void memcpy(const MAd_Matrix &other)
+    {
+      for (int i = 0; i < _r * _c; ++i) _data[i] = other._data[i];
+    }
+
+    void copy(const MAd_Matrix<SCALAR> &a, int i0, int ni, int j0, int nj, 
+              int desti0, int destj0)
+    {
+      for(int i = i0, desti = desti0; i < i0 + ni; i++, desti++)
+        for(int j = j0, destj = destj0; j < j0 + nj; j++, destj++)
+          (*this)(desti, destj) = a(i, j);
+    }
+
+    // c = c + data * b
+    inline void mult(const MAd_Matrix<SCALAR> &b, MAd_Matrix<SCALAR> &c)
+    {
+      c.scale(0.);
+      for(int i = 0; i < _r; i++)
+        for(int j = 0; j < b.size2(); j++)
+          for(int k = 0; k < _c; k++)
+            c._data[i + _r * j] += (*this)(i, k) * b(k, j);
+    }
+
+    // y = y + data * x
+    inline void mult(const MAd_Vector<SCALAR> &x, MAd_Vector<SCALAR> &y)
+    {
+      y.scale(0.);
+      for(int i = 0; i < _r; i++)
+        for(int j = 0; j < _c; j++)
+          y._data[i] += (*this)(i, j) * x(j);
+    }
+
+    // data = alpha * ( a * b ) + beta * data
+    inline void blas_dgemm(MAd_Matrix<SCALAR> &a, MAd_Matrix<SCALAR> &b, 
+                           SCALAR alpha=1., SCALAR beta=1.)
+    {
+      MAd_Matrix<SCALAR> temp(a.size1(), b.size2()); // temp = 0;
+      a.mult(b, temp); // temp = a * b
+      temp.scale(alpha); // temp = alpha * ( a * b )
+      scale(beta);
+      add(temp);
+    }
+
+    inline void set_all(const double &m) 
+    {
+      for (int i = 0; i < _r * _c; ++i) _data[i] = m;
+    }
+    inline void setValues(const SCALAR *M[]) 
+    {
+      for (int i = 0; i < _r ; ++i) 
+        for (int j = 0; j < _c ; ++j) _data[i + _r * j] = M[i][j];
+    }
+    inline void scale(const double s)
+    {
+      if(s == 0.)
+        for(int i = 0; i < _r * _c; ++i) _data[i] = 0.;
+      else
+        for(int i = 0; i < _r * _c; ++i) _data[i] *= s;
+    }
+    inline void add(const double &a) 
+    {
+      for(int i = 0; i < _r * _c; ++i) _data[i] += a;
+    }
+    inline void add(const MAd_Matrix<SCALAR> &m) 
+    {
+      for(int i = 0; i < size1(); i++)
+        for(int j = 0; j < size2(); j++)
+          (*this)(i, j) += m(i, j);
+    }
+
+    inline MAd_Matrix<SCALAR> transpose()
+    {
+      MAd_Matrix<SCALAR> T(size2(), size1());
+      for(int i = 0; i < size1(); i++)
+        for(int j = 0; j < size2(); j++)
+          T(j, i) = (*this)(i, j);
+      return T;
+    }
+    inline bool lu_solve(const MAd_Vector<SCALAR> &rhs, MAd_Vector<SCALAR> &result)
+    {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"LU factorization requires LAPACK");
+      return false;
+    }
+    MAd_Matrix<SCALAR> cofactor(int i, int j) const 
+    {
+      int ni = size1();
+      int nj = size2();
+      MAd_Matrix<SCALAR> cof(ni - 1, nj - 1);
+      for(int I = 0; I < ni; I++){
+        for(int J = 0; J < nj; J++){
+          if(J != j && I != i)
+            cof(I < i ? I : I - 1, J < j ? J : J - 1) = (*this)(I, J);
+        }
+      }
+      return cof;
+    }
+    SCALAR determinant() const
+    {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"Determinant computation requires LAPACK");
+      return 0.;
+    }
+    bool svd(MAd_Matrix<SCALAR> &V, MAd_Vector<SCALAR> &S)
+    {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"Singular value decomposition requires LAPACK");
+      return false;
+    } 
+    bool eig(MAd_Matrix<double> &VL, // left eigenvectors 
+             MAd_Vector<double> &DR, // Real part of eigenvalues
+             MAd_Vector<double> &DI, // Im part of eigenvalues
+             MAd_Matrix<double> &VR,
+             bool sortRealPart=false )
+    {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"Eigen vectors computation requires LAPACK");
+      return false;
+    } 
+    void print(std::string name) const
+    {
+      printf("Matrix %s (%d, %d):\n  ",name.c_str(),_r,_c);
+      for(int i = 0; i < _r ; ++i) {
+        for(int j = 0; j < _c ; ++j) printf("%12.5E ",(*this)(i, j));
+        printf("\n");
+      }
+    }
+  };
+
+
+// -------------------------------------------------------------------
+// With BLAS / LAPACK
+// -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  template <class SCALAR>
+  class MAd_BLASLAPACK_Vector
+  {
+  private:
+    int r;
+  public:
+    inline int size() const { return r; }
+    SCALAR *data;
+    ~MAd_BLASLAPACK_Vector() { delete [] data; }
+    MAd_BLASLAPACK_Vector() : r(0)
+    {
+      data = 0;
+    }
+    MAd_BLASLAPACK_Vector(int R) : r(R)
+    {
+      data = new SCALAR[r];
+      scale(0);
+    }
+    MAd_BLASLAPACK_Vector(const MAd_BLASLAPACK_Vector<SCALAR> &other) : r(other.r)
+    {
+      data = new double[r];
+      for (int i = 0; i < r; ++i) data[i] = other.data[i];
+    }
+    inline SCALAR operator () (int i) const
+    {
+      return data[i];
+    }
+    inline SCALAR & operator () (int i)
+    {
+      return data[i];
+    }
+    inline double norm()
+    {
+      double n = 0.;
+      for(int i = 0; i < r; ++i) n += data[i] * data[i];
+      return sqrt(n);
+    }
+    inline void scale(const SCALAR s)
+    {
+      for (int i = 0; i < r; ++i) data[i] *= s;
+    }
+    inline void set_all(const double &m) 
+    {
+      for (int i = 0; i < r; ++i) data[i] = m;
+    }
+    inline void add(const MAd_BLASLAPACK_Vector &v) 
+    {
+      for (int i = 0; i < r; ++i) data[i] += v(i);    
+    }
+    void print(std::string name) const
+    {
+      printf("Vector %s:\n  ",name.c_str());
+      for (int i = 0; i < r; ++i) printf("%12.5E ",data[i]);
+      printf("\n");
+    }
+  };
+
+  // -------------------------------------------------------------------
+  template <class SCALAR>
+  class MAd_BLASLAPACK_Matrix
+  {
+  private:
+    int _r, _c; // r = nb rows, c = nb columns
+    SCALAR *_data;
+
+  public:
+
+    MAd_BLASLAPACK_Matrix(int R,int C) : _r(R), _c(C)
+    {
+      _data = new SCALAR[_r * _c];
+      scale(0.);
+    }
+    MAd_BLASLAPACK_Matrix(const MAd_BLASLAPACK_Matrix<SCALAR> &other) : _r(other._r), _c(other._c)
+    {
+      _data = new double[_r * _c];
+      memcpy(other);
+    }
+    MAd_BLASLAPACK_Matrix() : _r(0), _c(0), _data(0) {}
+    ~MAd_BLASLAPACK_Matrix() { delete [] _data; }
+
+  public:
+
+    inline int size1() const { return _r; }
+    inline int size2() const { return _c; }
+
+    inline SCALAR operator () (int i, int j) const
+    {
+      return _data[i + _r * j];
+    }
+    inline SCALAR & operator () (int i, int j)
+    {
+      return _data[i + _r * j];
+    }
+
+    MAd_BLASLAPACK_Matrix<SCALAR> & operator = (const MAd_BLASLAPACK_Matrix<SCALAR> &other)
+    {
+      if(this != &other){
+        _r = other._r; 
+        _c = other._c;
+        _data = new SCALAR[_r * _c];
+        memcpy(other);
+      }
+      return *this;
+    }
+    void memcpy(const MAd_BLASLAPACK_Matrix &other)
+    {
+      for (int i = 0; i < _r * _c; ++i) _data[i] = other._data[i];
+    }
+
+    void copy(const MAd_BLASLAPACK_Matrix<SCALAR> &a, int i0, int ni, int j0, int nj, 
+              int desti0, int destj0)
+    {
+      for(int i = i0, desti = desti0; i < i0 + ni; i++, desti++)
+        for(int j = j0, destj = destj0; j < j0 + nj; j++, destj++)
+          (*this)(desti, destj) = a(i, j);
+    }
+
+    // c = c + data * b
+    inline void mult(const MAd_BLASLAPACK_Matrix<SCALAR> &b, MAd_BLASLAPACK_Matrix<SCALAR> &c)
+    {
+#if defined(HAVE_BLAS)
+      int M = c.size1(), N = c.size2(), K = _c;
+      int LDA = _r, LDB = b.size1(), LDC = c.size1();
+      double alpha = 1., beta = 0.;
+      dgemm_("N", "N", &M, &N, &K, &alpha, _data, &LDA, b._data, &LDB, 
+             &beta, c._data, &LDC);
+#else
+      c.scale(0.);
+      for(int i = 0; i < _r; i++)
+        for(int j = 0; j < b.size2(); j++)
+          for(int k = 0; k < _c; k++)
+            c._data[i + _r * j] += (*this)(i, k) * b(k, j);
+#endif
+    }
+
+    // y = y + data * x
+    inline void mult(const MAd_BLASLAPACK_Vector<SCALAR> &x, MAd_BLASLAPACK_Vector<SCALAR> &y)
+    {
+#if defined(HAVE_BLAS)
+      int M = _r, N = _c, LDA = _r, INCX = 1, INCY = 1;
+      double alpha = 1., beta = 0.;
+      dgemv_("N", &M, &N, &alpha, _data, &LDA, x._data, &INCX,
+             &beta, y._data, &INCY);
+#else
+      y.scale(0.);
+      for(int i = 0; i < _r; i++)
+        for(int j = 0; j < _c; j++)
+          y._data[i] += (*this)(i, j) * x(j);
+#endif
+    }
+
+    // data = alpha * ( a * b ) + beta * data
+    inline void blas_dgemm(MAd_BLASLAPACK_Matrix<SCALAR> &a, MAd_BLASLAPACK_Matrix<SCALAR> &b, 
+                           SCALAR alpha=1., SCALAR beta=1.)
+    {
+#if defined(HAVE_BLAS)
+      int M = size1(), N = size2(), K = a.size2();
+      int LDA = a.size1(), LDB = b.size1(), LDC = size1();
+      dgemm_("N", "N", &M, &N, &K, &alpha, a._data, &LDA, b._data, &LDB, 
+             &beta, _data, &LDC);
+#else
+      MAd_BLASLAPACK_Matrix<SCALAR> temp(a.size1(), b.size2()); // temp = 0;
+      a.mult(b, temp); // temp = a * b
+      temp.scale(alpha); // temp = alpha * ( a * b )
+      scale(beta);
+      add(temp);
+#endif
+    }
+
+    inline void set_all(const double &m) 
+    {
+      for (int i = 0; i < _r * _c; ++i) _data[i] = m;
+    }
+    inline void setValues(const SCALAR *M[]) 
+    {
+      for (int i = 0; i < _r ; ++i) 
+        for (int j = 0; j < _c ; ++j) _data[i + _r * j] = M[i][j];
+    }
+    inline void scale(const double s)
+    {
+      if(s == 0.)
+        for(int i = 0; i < _r * _c; ++i) _data[i] = 0.;
+      else
+        for(int i = 0; i < _r * _c; ++i) _data[i] *= s;
+    }
+    inline void add(const double &a) 
+    {
+      for(int i = 0; i < _r * _c; ++i) _data[i] += a;
+    }
+    inline void add(const MAd_BLASLAPACK_Matrix<SCALAR> &m) 
+    {
+      for(int i = 0; i < size1(); i++)
+        for(int j = 0; j < size2(); j++)
+          (*this)(i, j) += m(i, j);
+    }
+
+    inline MAd_BLASLAPACK_Matrix<SCALAR> transpose()
+    {
+      MAd_BLASLAPACK_Matrix<SCALAR> T(size2(), size1());
+      for(int i = 0; i < size1(); i++)
+        for(int j = 0; j < size2(); j++)
+          T(j, i) = (*this)(i, j);
+      return T;
+    }
+    inline bool lu_solve(const MAd_BLASLAPACK_Vector<SCALAR> &rhs, MAd_BLASLAPACK_Vector<SCALAR> &result)
+    {
+#if defined(HAVE_LAPACK)
+      int N = size1(), nrhs = 1, lda = N, ldb = N, info;
+      int *ipiv = new int[N];
+      for(int i = 0; i < N; i++) result(i) = rhs(i);
+      dgesv_(&N, &nrhs, _data, &lda, ipiv, result.data, &ldb, &info);
+      delete [] ipiv;
+      if(info == 0) return true;
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"Problem in LAPACK LU (info=%d)", info);
+#else
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"LU factorization requires LAPACK");
+#endif
+      return false;
+    }
+    MAd_BLASLAPACK_Matrix<SCALAR> cofactor(int i, int j) const 
+    {
+      int ni = size1();
+      int nj = size2();
+      MAd_BLASLAPACK_Matrix<SCALAR> cof(ni - 1, nj - 1);
+      for(int I = 0; I < ni; I++){
+        for(int J = 0; J < nj; J++){
+          if(J != j && I != i)
+            cof(I < i ? I : I - 1, J < j ? J : J - 1) = (*this)(I, J);
+        }
+      }
+      return cof;
+    }
+    SCALAR determinant() const
+    {
+#if defined(HAVE_LAPACK)
+      MAd_BLASLAPACK_Matrix<SCALAR> tmp(*this);
+      int M = size1(), N = size2(), lda = size1(), info;
+      int *ipiv = new int[std::min(M, N)];
+      dgetrf_(&M, &N, tmp._data, &lda, ipiv, &info);
+      SCALAR det = 1.;
+      for(int i = 0; i < size1(); i++){
+        det *= tmp(i, i);
+        if(ipiv[i] != i + 1) det = -det;
+      }
+      return det;
+#else
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"Determinant computation requires LAPACK");
+      return 0.;
+#endif
+    }
+    bool svd(MAd_BLASLAPACK_Matrix<SCALAR> &V, MAd_BLASLAPACK_Vector<SCALAR> &S)
+    {
+#if defined(HAVE_LAPACK)
+      MAd_BLASLAPACK_Matrix<SCALAR> VT(V.size2(), V.size1());
+      int M = size1(), N = size2(), LDA = size1(), LDVT = VT.size1(), info;
+      int LWORK = std::max(3 * std::min(M, N) + std::max(M, N), 5 * std::min(M, N));
+      MAd_BLASLAPACK_Vector<SCALAR> WORK(LWORK);
+      dgesvd_("O", "A", &M, &N, _data, &LDA, S._data, _data, &LDA,
+              VT._data, &LDVT, WORK._data, &LWORK, &info);
+      V = VT.transpose();
+      if(info == 0) return true;
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"Problem in LAPACK SVD (info=%d)", info);
+#else
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"Singular value decomposition requires LAPACK");
+#endif
+      return false;
+    }
+    bool eig(MAd_BLASLAPACK_Matrix<double> &VL, // left eigenvectors 
+             MAd_BLASLAPACK_Vector<double> &DR, // Real part of eigenvalues
+             MAd_BLASLAPACK_Vector<double> &DI, // Im part of eigenvalues
+             MAd_BLASLAPACK_Matrix<double> &VR,
+             bool sortRealPart=false ) // if true: sorted from max '|DR|' to min '|DR|'
+#if defined(HAVE_LAPACK)
+      ;
+#else
+    {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"Eigen vectors computation requires LAPACK");
+      return false;
+    }
+#endif
+    void print(std::string name) const
+    {
+      printf("Matrix %s (%d, %d):\n  ",name.c_str(),_r,_c);
+      for(int i = 0; i < _r ; ++i) {
+        for(int j = 0; j < _c ; ++j) printf("%12.5E ",(*this)(i, j));
+        printf("\n");
+      }
+    }
+  };
+
+// -------------------------------------------------------------------
+// With GSL
+// -------------------------------------------------------------------
+#ifdef _HAVE_GSL_
+
+  class MAd_GSL_Vector
+  {
+  private:
+    int _r;
+    gsl_vector *_data;
+    friend class MAd_GSL_Matrix;
+
+  public:
+
+    MAd_GSL_Vector(int r) : _r(r)
+    {
+      _data = gsl_vector_calloc(_r);
+    }
+    MAd_GSL_Vector(const MAd_GSL_Vector &other) : _r(other._r)
+    {
+      _data = gsl_vector_calloc(_r);
+      gsl_vector_memcpy(_data, other._data);
+    }
+    ~MAd_GSL_Vector() { gsl_vector_free(_data); }
+
+    inline int size() const { return _r; }
+
+    inline double operator () (int i) const
+    {
+      return gsl_vector_get(_data, i);
+    }
+    inline double & operator () (int i)
+    {
+      return *gsl_vector_ptr(_data, i);
+    }
+    inline double norm()
+    {
+      return gsl_blas_dnrm2(_data);
+    }
+    inline void scale(const double s)
+    {
+      if(s == 0.) gsl_vector_set_zero(_data);
+      else gsl_vector_scale(_data, s);
+    }
+    inline void set_all(const double &m) 
+    {
+      gsl_vector_set_all(_data, m);
+    }
+    inline void add(const MAd_GSL_Vector &v) 
+    {
+      gsl_vector_add (_data, v._data);
+    }
+    void print(std::string name) const
+    {
+      printf("Vector %s:\n  ",name.c_str());
+      for (int i = 0; i < _r; ++i) printf("%12.5E ",gsl_vector_get(_data, i));
+      printf("\n");
+    }
+  };
+
+  // -------------------------------------------------------------------
+  class MAd_GSL_Matrix
+  {
+  private:
+    gsl_matrix *_data;
+  
+  public:
+    MAd_GSL_Matrix(int r, int  c) { _data = gsl_matrix_calloc(r, c); }
+    MAd_GSL_Matrix(const MAd_GSL_Matrix &other) : _data(0)
+    {
+      if(_data) gsl_matrix_free(_data);
+      _data = gsl_matrix_calloc(other._data->size1, other._data->size2);
+      gsl_matrix_memcpy(_data, other._data);
+    }
+    MAd_GSL_Matrix() : _data(0) {}
+    ~MAd_GSL_Matrix() { if(_data && _data->owner == 1) gsl_matrix_free(_data); }
+
+  public:
+    inline int size1() const { return _data->size1; }
+    inline int size2() const { return _data->size2; }
+    MAd_GSL_Matrix & operator = (const MAd_GSL_Matrix &other)
+    {
+      if(&other != this){
+        if(_data) gsl_matrix_free(_data);
+        _data = gsl_matrix_calloc(other._data->size1, other._data->size2);
+        gsl_matrix_memcpy(_data, other._data);
+      }
+      return *this;
+    }
+    void memcpy(const MAd_GSL_Matrix &other)
+    {
+      gsl_matrix_memcpy(_data, other._data);
+    }
+    inline double operator () (int i, int j) const
+    {
+      return gsl_matrix_get(_data, i, j);
+    }
+    inline double & operator () (int i, int j)
+    {
+      return *gsl_matrix_ptr(_data, i, j);
+    }
+    void copy(const MAd_GSL_Matrix &a, int i0, int ni, int j0, int nj, 
+              int desti0, int destj0)
+    {
+      for(int i = i0, desti = desti0; i < i0 + ni; i++, desti++)
+        for(int j = j0, destj = destj0; j < j0 + nj; j++, destj++)
+          (*this)(desti, destj) = a(i, j);
+    }
+    inline void mult(const MAd_GSL_Matrix &b, MAd_GSL_Matrix &c)
+    {
+      gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1., _data, b._data, 0., c._data);
+    }
+    inline void mult(const MAd_GSL_Vector &x, MAd_GSL_Vector &y)
+    {
+      gsl_blas_dgemv(CblasNoTrans, 1., _data, x._data, 0., y._data);
+    }
+    inline void blas_dgemm(MAd_GSL_Matrix &a, MAd_GSL_Matrix &b, 
+                           double alpha=1., double beta=1.)
+    {      
+      gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, alpha, a._data, b._data, beta, _data);
+    }
+    inline void set_all(const double &m) 
+    {
+      gsl_matrix_set_all(_data, m);
+    }
+    inline void setValues(const double *M[]) 
+    {
+      for (int i = 0; i < size1() ; ++i) 
+        for (int j = 0; j < size2() ; ++j) *gsl_matrix_ptr(_data, i, j) = M[i][j];
+    }
+    inline void scale(const double s) 
+    {
+      if(s == 0.) gsl_matrix_set_zero(_data);
+      else gsl_matrix_scale(_data, s);
+    }
+    inline void add(const double &a) 
+    {
+      gsl_matrix_add_constant(_data, a);
+    }
+    inline void add(const MAd_GSL_Matrix &m) 
+    {
+      gsl_matrix_add(_data, m._data);
+    }
+    inline MAd_GSL_Matrix transpose()
+    {
+      MAd_GSL_Matrix T(size2(), size1());
+      for(int i = 0; i < size1(); i++)
+        for(int j = 0; j < size2(); j++)
+          T(j, i) = (*this)(i, j);
+      return T;
+    }
+    inline bool lu_solve(const MAd_GSL_Vector &rhs, MAd_GSL_Vector &result)
+    {
+      int s;
+      gsl_permutation *p = gsl_permutation_alloc(size1());
+      gsl_linalg_LU_decomp(_data, p, &s);
+      gsl_linalg_LU_solve(_data, p, rhs._data, result._data);
+      gsl_permutation_free(p);
+      return true;
+    }
+    MAd_GSL_Matrix cofactor(int i, int j) const 
+    {
+      int ni = size1();
+      int nj = size2();
+      MAd_GSL_Matrix cof(ni - 1, nj - 1);
+      for(int I = 0; I < ni; I++){
+        for(int J = 0; J < nj; J++){
+          if(J != j && I != i)
+            cof(I < i ? I : I - 1, J < j ? J : J - 1) = (*this)(I, J);
+        }
+      }
+      return cof;
+    }
+    double determinant() const 
+    {
+      MAd_GSL_Matrix tmp = *this;
+      gsl_permutation *p = gsl_permutation_alloc(size1());
+      int s;
+      gsl_linalg_LU_decomp(tmp._data, p, &s);
+      gsl_permutation_free(p);
+      return gsl_linalg_LU_det(tmp._data, s);
+    } 
+    bool svd(MAd_GSL_Matrix &V, MAd_GSL_Vector &S)
+    {
+      MAd_GSL_Vector tmp(S.size());
+      gsl_linalg_SV_decomp(_data, V._data, S._data, tmp._data);
+      return true;
+    }
+    inline void invert ()
+    {
+      int s;
+      gsl_permutation *p = gsl_permutation_alloc (size1());
+      gsl_linalg_LU_decomp(_data, p, &s);
+      gsl_matrix *data_inv = gsl_matrix_calloc(size1(), size2());
+      gsl_linalg_LU_invert(_data, p, data_inv) ;
+      gsl_matrix_memcpy(_data, data_inv);
+      gsl_matrix_free(data_inv);
+      gsl_permutation_free(p);
+    }
+    inline bool invertSecure(double &det)
+    {
+      int s;
+      gsl_permutation *p = gsl_permutation_alloc (size1());
+      gsl_linalg_LU_decomp(_data, p, &s);
+      det = gsl_linalg_LU_det(_data, s);
+      gsl_matrix *data_inv = gsl_matrix_calloc(size1(), size2());
+      gsl_linalg_LU_invert(_data, p, data_inv);
+      gsl_matrix_memcpy(_data, data_inv);
+      gsl_matrix_free(data_inv);
+      gsl_permutation_free(p);
+      return (det != 0.);
+    }
+    bool eig(MAd_GSL_Matrix &VL, // left eigenvectors 
+             MAd_GSL_Vector &DR, // Real part of eigenvalues
+             MAd_GSL_Vector &DI, // Im part of eigenvalues
+             MAd_GSL_Matrix &VR,
+             bool sortRealPart=false )
+    {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,"Eigen vectors computation requires LAPACK");
+      return false;
+    }
+    void print(std::string name) const
+    {
+      printf("Matrix %s (%d, %d):\n  ",name.c_str(),_data->size1,_data->size2);
+      for(int i = 0; i < _data->size1 ; ++i) {
+        for(int j = 0; j < _data->size2 ; ++j) printf("%12.5E ",(*this)(i, j));
+        printf("\n");
+      }
+    }
+  };
+
+#endif
+
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+
+#if defined(HAVE_LAPACK)
+  typedef MAd_BLASLAPACK_Matrix<double> doubleMatrix;
+  typedef MAd_BLASLAPACK_Vector<double> doubleVector;
+#else
+ #if defined(_HAVE_GSL_)
+   typedef MAd_GSL_Matrix doubleMatrix;
+   typedef MAd_GSL_Vector doubleVector;
+ #else
+   typedef MAd_Matrix<double> doubleMatrix;
+   typedef MAd_Vector<double> doubleVector;
+ #endif
+#endif
+
+  // -------------------------------------------------------------------
+
+  // Should be used for operations on small matrices
+  typedef MAd_Matrix<double> smallMatrix;
+  typedef MAd_Vector<double> smallVector;
+
+  // -------------------------------------------------------------------
+
+}
+
+// -------------------------------------------------------------------
+// Gmsh matrices
+// -------------------------------------------------------------------
+
+#ifdef _HAVE_GMSH_
+
+#include "gmsh/GmshMatrix.h"
+namespace MAd {
+  typedef gmshMatrix<double> gmshMat;
+  typedef gmshVector<double> gmshVec;
+}
+
+#else
+
+namespace MAd {
+  
+  class nullVector {
+  public:
+    nullVector() {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Not implemented, Gmsh required");
+    }
+    nullVector(double) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Not implemented, Gmsh required");
+    }
+    inline double operator () (int i) const { return -1.; }
+    void print(const char * name="") const {}
+  };
+  class nullMatrix {
+  public:
+    nullMatrix() {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Not implemented, Gmsh required");
+    }
+    nullMatrix(double, double) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Not implemented, Gmsh required");
+    }
+    inline double operator () (int i, int j) const { return -1.; }
+    void print(const char * name="") const {}
+  };
+
+  typedef nullMatrix gmshMat;
+  typedef nullVector gmshVec;
+}
+
+#endif
+
+  // -------------------------------------------------------------------
+
+#endif
diff --git a/Common/MAdMessage.cc b/Common/MAdMessage.cc
new file mode 100644
index 0000000..2ad99a2
--- /dev/null
+++ b/Common/MAdMessage.cc
@@ -0,0 +1,126 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MAdMessage.h"
+
+#include <cstdarg>
+#include <iostream>
+#include <sstream>
+#include <stdlib.h>
+
+using std::stringstream;
+using std::string;
+using std::ostream;
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  MAdMsg::MAdMsg()
+  {
+    outStream = &std::cout;
+    errStream = &std::cerr;
+  }
+
+  // -------------------------------------------------------------------
+  void MAdMsg::initialize()
+  {
+  }
+
+  // -------------------------------------------------------------------
+  void MAdMsg::finalize()
+  {
+  }
+
+  // -------------------------------------------------------------------
+  void MAdMsg::registerAbortFct(AbortFunction fct, void * data)
+  {
+    abortFcts.push_back(std::make_pair(fct,data));
+  }
+
+  // -------------------------------------------------------------------
+  void MAdMsg::info(int line,
+                    const char* file,
+                    const char* fmt,...) const
+  {
+    char buff[1024];
+    va_list args;
+    va_start (args, fmt);
+    vsprintf(buff, fmt, args);
+    va_end (args);
+
+    if ( line >= 0 ) {
+      *outStream << "Info: " << buff << writePosition(line,file) << "" << std::endl;
+    }
+    else {
+      *outStream << "Info: " << buff << std::endl;
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void MAdMsg::warning(int line,
+                       const char* file,
+                       const char* fmt,...) const
+  {
+    char buff[1024];
+    va_list args;
+    va_start (args, fmt);
+    vsprintf(buff, fmt, args);
+    va_end (args);
+
+    if ( line >= 0 ) {
+      *outStream << "WARNING: " << buff << writePosition(line,file) << "" << std::endl;
+    }
+    else {
+      *outStream << "WARNING: " << buff << std::endl;
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void MAdMsg::error(int line,
+                     const char* file,
+                     const char* fmt,...) const
+  {
+    char buff[1024];
+    va_list args;
+    va_start (args, fmt);
+    vsprintf(buff, fmt, args);
+    va_end (args);
+
+    if ( line >= 0 ) {
+      *outStream << "ERROR: " << buff << writePosition(line,file) << "" << std::endl;
+    }
+    else {
+      *outStream << "ERROR: " << buff << std::endl;
+    }
+
+    // call abort functions
+    std::list<std::pair<AbortFunction,void*> >::const_iterator iter = abortFcts.begin();
+    for (; iter != abortFcts.end(); iter++) {
+      AbortFunction fct = (*iter).first;
+      void * data       = (*iter).second;
+      fct(data);
+    }
+
+    abort();
+  }
+
+  // -------------------------------------------------------------------
+  string MAdMsg::writePosition(int line, const char* file) const
+  {
+    stringstream ss;
+    string iStr;  ss << line;  ss >> iStr;
+    return  " (line " + iStr + " in file \'" + file + "\')";
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Common/MAdMessage.h b/Common/MAdMessage.h
new file mode 100644
index 0000000..89c931f
--- /dev/null
+++ b/Common/MAdMessage.h
@@ -0,0 +1,64 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MESSAGE_MAD_
+#define _H_MESSAGE_MAD_
+
+#include "MAdSingleton.h"
+
+#include <ostream>
+#include <list>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  // abort function
+  typedef void (*AbortFunction)(void *);
+
+  // -------------------------------------------------------------------
+  class MAdMsg {
+
+  public:
+
+    MAdMsg();
+    ~MAdMsg() {}
+  
+    void initialize();
+    void finalize();
+
+    void registerAbortFct(AbortFunction, void *);
+
+    void info   (int, const char*, const char*,...) const;
+    void warning(int, const char*, const char*,...) const;
+    void error  (int, const char*, const char*,...) const;
+
+  private:
+
+    std::string writePosition(int, const char*) const;
+
+  private:
+
+    std::ostream* outStream;
+    std::ostream* errStream;
+
+    std::list<std::pair<AbortFunction,void*> > abortFcts; 
+
+  };
+
+  // -------------------------------------------------------------------
+
+  typedef MAdSingleton<MAdMsg> MAdMsgSgl;
+
+}
+
+#endif
diff --git a/Common/MAdMetric.cc b/Common/MAdMetric.cc
new file mode 100644
index 0000000..416dfb3
--- /dev/null
+++ b/Common/MAdMetric.cc
@@ -0,0 +1,144 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MAdMetric.h"
+
+namespace MAd {
+
+  MAdMetric::MAdMetric(const double l1, // (h_1)^-2
+                       const double l2,
+                       const double l3,
+                       const double t1[3],
+                       const double t2[3],
+                       const double t3[3])
+    {
+      // M = e^1 * diag * e^1^t
+      // where the elements of diag are l_i = h_i^-2
+      // and the rows of e are the UNIT and ORTHOGONAL directions
+
+      double e[3][3];
+      e[0][0] = t1[0]; e[0][1] = t1[1]; e[0][2] = t1[2];
+      e[1][0] = t2[0]; e[1][1] = t2[1]; e[1][2] = t2[2];
+      e[2][0] = t3[0]; e[2][1] = t3[1]; e[2][2] = t3[2];
+      invertMat(e);
+    
+      double tmp[3][3];
+      tmp[0][0] = l1 * e[0][0]; tmp[0][1] = l2 * e[0][1]; tmp[0][2] = l3 * e[0][2];
+      tmp[1][0] = l1 * e[1][0]; tmp[1][1] = l2 * e[1][1]; tmp[1][2] = l3 * e[1][2];
+      tmp[2][0] = l1 * e[2][0]; tmp[2][1] = l2 * e[2][1]; tmp[2][2] = l3 * e[2][2];
+      
+      transpose(e);
+
+      _val[0] = tmp[0][0] * e[0][0] + tmp[0][1] * e[1][0] + tmp[0][2] * e[2][0];
+      _val[1] = tmp[1][0] * e[0][0] + tmp[1][1] * e[1][0] + tmp[1][2] * e[2][0];
+      _val[2] = tmp[1][0] * e[0][1] + tmp[1][1] * e[1][1] + tmp[1][2] * e[2][1];
+      _val[3] = tmp[2][0] * e[0][0] + tmp[2][1] * e[1][0] + tmp[2][2] * e[2][0];
+      _val[4] = tmp[2][0] * e[0][1] + tmp[2][1] * e[1][1] + tmp[2][2] * e[2][1];
+      _val[5] = tmp[2][0] * e[0][2] + tmp[2][1] * e[1][2] + tmp[2][2] * e[2][2];
+    }
+//     MAdMetric(const double l1, // (h_1)^-2
+//               const double l2,
+//               const double l3,
+//               const double t1[3],
+//               const double t2[3],
+//               const double t3[3]){
+//       double t1b[3], t2b[3], t3b[3];
+//       t1b[0] = t1[0] * l1; t2b[0] = t2[0] * l1; t3b[0] = t3[0] * l1;
+//       t1b[1] = t1[1] * l2; t2b[1] = t2[1] * l2; t3b[1] = t3[1] * l2;
+//       t1b[2] = t1[2] * l3; t2b[2] = t2[2] * l3; t3b[2] = t3[2] * l3;
+//       _val[0] = dotProd (t1b,t1);
+//       _val[1] = dotProd (t2b,t1);
+//       _val[2] = dotProd (t2b,t2);
+//       _val[3] = dotProd (t3b,t1);
+//       _val[4] = dotProd (t3b,t2);    
+//       _val[5] = dotProd (t3b,t3);
+//     }
+
+  void MAdMetric::print (const char *s) const
+  {
+    printf(" metric %s : %12.5E %12.5E %12.5E %12.5E %12.5E %12.5E \n",s,
+           (*this)(0,0),(*this)(1,1),(*this)(2,2),
+           (*this)(0,1),(*this)(0,2),(*this)(1,2));
+  }
+
+
+  MAdMetric intersection (const MAdMetric &m1, const MAdMetric &m2)
+  {
+    MAdMetric im1 = m1.invert();
+    doubleMatrix V(3,3);
+    doubleVector S(3);
+    im1 *= m2;
+    im1.eig(V,S,true);
+    double v0[3]; v0[0] = V(0,0); v0[1] = V(1,0); v0[2] = V(2,0);
+    double v1[3]; v1[0] = V(0,1); v1[1] = V(1,1); v1[2] = V(2,1);
+    double v2[3]; v2[0] = V(0,2); v2[1] = V(1,2); v2[2] = V(2,2);
+    double l0 = std::max(dot(v0,m1,v0),dot(v0,m2,v0));
+    double l1 = std::max(dot(v1,m1,v1),dot(v1,m2,v1));
+    double l2 = std::max(dot(v2,m1,v2),dot(v2,m2,v2));
+    MAdMetric iv(l0,l1,l2,v0,v1,v2);
+    return iv;
+  }
+
+  // (1-t) * m1 + t * m2
+  MAdMetric interpolation (const MAdMetric &m1, 
+                           const MAdMetric &m2, 
+                           const double t)
+  {
+    MAdMetric im1 = m1.invert();
+    MAdMetric im2 = m2.invert();
+    im1 *= (1.-t);
+    im2 *= t;
+    im1 += im2;
+    return im1.invert();
+  }
+
+  MAdMetric interpolation (const MAdMetric &m1, 
+                           const MAdMetric &m2, 
+                           const MAdMetric &m3, 
+                           const double u,
+                           const double v)
+  {
+    MAdMetric im1 = m1.invert();
+    MAdMetric im2 = m2.invert();
+    MAdMetric im3 = m3.invert();
+    im1 *= (1.-u-v);
+    im2 *= u;
+    im3 *= v;
+    im1 += im2;
+    im1 += im3;
+    return im1.invert();
+  }
+
+  MAdMetric interpolation (const MAdMetric &m1, 
+                           const MAdMetric &m2, 
+                           const MAdMetric &m3,  
+                           const MAdMetric &m4, 
+                           const double u,
+                           const double v,
+                           const double w)
+  {
+    MAdMetric im1 = m1.invert();
+    MAdMetric im2 = m2.invert();
+    MAdMetric im3 = m3.invert();
+    MAdMetric im4 = m4.invert();
+    im1 *= (1.-u-v-w);
+    im2 *= u;
+    im3 *= v;
+    im4 *= w;
+    im1 += im2;
+    im1 += im3;
+    im1 += im4;
+    return im1.invert();
+  }
+
+}
diff --git a/Common/MAdMetric.h b/Common/MAdMetric.h
new file mode 100644
index 0000000..4160c3e
--- /dev/null
+++ b/Common/MAdMetric.h
@@ -0,0 +1,151 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MADMETRIC
+#define _H_MADMETRIC
+
+#include "MAdMatrix.h"
+#include "MathUtils.h"
+
+namespace MAd {
+
+  // class for symmetric positive definite 3x3 matrix
+  class MAdMetric {
+
+  protected:
+    // lower diagonal storage
+    // 00 10 11 20 21 22 
+    double _val[6];
+
+  public:
+
+    inline int getIndex(int i, int j) const{
+      static int _index[3][3] = {{0,1,3},{1,2,4},{3,4,5}};
+      return _index[i][j];
+    }
+    void getMat (doubleMatrix & mat) const{
+      for (int i=0;i<3;i++){
+        for (int j=0;j<3;j++){
+          mat(i,j) = _val[getIndex(i,j)];			     
+        }
+      }
+    }
+    void getMat (double mat[3][3]) const{
+      for (int i=0;i<3;i++){
+        for (int j=0;j<3;j++){
+          mat[i][j] = _val[getIndex(i,j)];			     
+        }
+      }
+    }
+    void setMat (const double mat[3][3]){
+      for (int i=0;i<3;i++)
+        for (int j=i;j<3;j++)
+          _val[getIndex(i,j)] = mat[i][j];			     
+    }
+    MAdMetric(const MAdMetric& m){
+      for (int i=0; i<6; i++) _val[i]=m._val[i];
+    }
+    // default constructor, identity 
+    MAdMetric(const double v = 1.0){
+      _val[0] = _val[2] = _val[5] = v;
+      _val[1] = _val[3] = _val[4] = 0.0;
+    }
+    MAdMetric(const double l1, // (h_1)^-2
+              const double l2,
+              const double l3,
+              const double t1[3],
+              const double t2[3],
+              const double t3[3]);
+    inline double &operator()(int i, int j){ 
+      return _val[getIndex(i,j)];
+    }
+    inline double operator()(int i, int j) const{ 
+      return _val[getIndex(i,j)];
+    }  
+    MAdMetric invert () const {
+      double m[3][3];
+      getMat(m);
+      invertMat(m);
+      MAdMetric ithis;
+      ithis.setMat(m);
+      return ithis;
+    }
+    MAdMetric operator + (const MAdMetric &other) const {
+      MAdMetric res(*this);
+      for (int i=0;i<6;i++) res._val[i] += other._val[i];
+      return res;
+    }
+    MAdMetric& operator += (const MAdMetric &other)  {
+      for (int i=0;i<6;i++) _val[i] += other._val[i];
+      return *this;
+    }
+    MAdMetric& operator *= (const double &other) {
+      for (int i=0;i<6;i++) _val[i] *= other;
+      return *this;
+    }
+    MAdMetric& operator *= (const MAdMetric &other) {
+      double m1[3][3], m2[3][3], m3[3][3];
+      getMat(m1);
+      other.getMat(m2);
+      matMat(m1,m2,m3);
+      setMat(m3);
+      return *this;
+    }
+    MAdMetric transform (double V[3][3]){
+      double m[3][3], result[3][3], temp[3][3];
+      getMat(m);
+      transpose(V);
+      matMat(V,m,temp);
+      matMat(temp,V,result);
+      MAdMetric a; a.setMat(result);
+      return a;
+    }
+    // s: true if eigenvalues are sorted (from max to min of the absolute value of the REAL part)
+    void eig (doubleMatrix &V, doubleVector &S, bool s=false) const {
+      doubleMatrix me(3,3),right(3,3);
+      doubleVector im(3);
+      getMat(me);
+      me.eig(V,S,im,right,s);
+    }
+    void print(const char *) const;
+  };
+
+  // scalar product with respect to the metric
+  inline double dot(const double a[3], const MAdMetric &m, const double b[3])
+  { return 
+      b[0] * ( m(0,0) * a[0] + m(1,0) * a[1] + m(2,0) * a[2] ) + 
+      b[1] * ( m(0,1) * a[0] + m(1,1) * a[1] + m(2,1) * a[2] ) + 
+      b[2] * ( m(0,2) * a[0] + m(1,2) * a[1] + m(2,2) * a[2] ) ;}
+
+  // compute the largest inscribed ellipsoid...
+  MAdMetric intersection (const MAdMetric &m1, 
+                          const MAdMetric &m2);
+  MAdMetric interpolation (const MAdMetric &m1, 
+                           const MAdMetric &m2, 
+                           const double t);
+  MAdMetric interpolation (const MAdMetric &m1, 
+                           const MAdMetric &m2, 
+                           const MAdMetric &m3, 
+                           const double u,
+                           const double v);
+  MAdMetric interpolation (const MAdMetric &m1, 
+                           const MAdMetric &m2, 
+                           const MAdMetric &m3, 
+                           const MAdMetric &m4, 
+                           const double u,
+                           const double v,
+                           const double w);
+
+}
+
+#endif
diff --git a/Common/MAdResourceManager.cc b/Common/MAdResourceManager.cc
new file mode 100644
index 0000000..845c7ba
--- /dev/null
+++ b/Common/MAdResourceManager.cc
@@ -0,0 +1,189 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MAdResourceManager.h"
+#include "MAdMessage.h"
+
+#include <fstream>
+
+#ifdef PARALLEL
+ #include <mpi.h>
+#else
+ #ifndef _WIN_
+  #include <sys/time.h>
+ #else
+  #include <time.h>
+  #include <windows.h> 
+  #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
+   #define DELTA_EPOCH_IN_MICROSECS  11644473600000000Ui64
+  #else
+   #define DELTA_EPOCH_IN_MICROSECS  11644473600000000ULL
+  #endif
+
+struct timezone 
+{
+  int  tz_minuteswest; /* minutes W of Greenwich */
+  int  tz_dsttime;     /* type of dst correction */
+};
+ 
+int get_time_of_day(struct timeval *tv, struct timezone *tz)
+{
+  FILETIME ft;
+  unsigned __int64 tmpres = 0;
+  static int tzflag;
+ 
+  if (NULL != tv)
+    {
+      GetSystemTimeAsFileTime(&ft);
+ 
+      tmpres |= ft.dwHighDateTime;
+      tmpres <<= 32;
+      tmpres |= ft.dwLowDateTime;
+ 
+      // converting file time
+      tmpres -= DELTA_EPOCH_IN_MICROSECS; 
+      tmpres /= 10;  // convert into microseconds
+      tv->tv_sec = (long)(tmpres / 1000000UL);
+      tv->tv_usec = (long)(tmpres % 1000000UL);
+    }
+ 
+  if (NULL != tz)
+    {
+      if (!tzflag)
+        {
+          _tzset();
+          tzflag++;
+        }
+      tz->tz_minuteswest = _timezone / 60;
+      tz->tz_dsttime = _daylight;
+    }
+ 
+  return 0;
+}
+ #endif
+
+#endif
+
+#if defined(__linux) || defined(linux)
+
+void process_mem_usage(double& vm_usage, double& resident_set)
+{
+  using std::ios_base;
+  using std::ifstream;
+  using std::string;
+  
+  vm_usage     = 0.0;
+  resident_set = 0.0;
+  
+  // 'file' stat seems to give the most reliable results
+  //
+  ifstream stat_stream("/proc/self/stat",ios_base::in);
+  
+  // dummy vars for leading entries in stat that we don't care about
+  //
+  string pid, comm, state, ppid, pgrp, session, tty_nr;
+  string tpgid, flags, minflt, cminflt, majflt, cmajflt;
+  string utime, stime, cutime, cstime, priority, nice;
+  string O, itrealvalue, starttime;
+  
+  // the two fields we want
+  //
+  unsigned long vsize;
+  long rss;
+  
+  stat_stream >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr
+              >> tpgid >> flags >> minflt >> cminflt >> majflt >> cmajflt
+              >> utime >> stime >> cutime >> cstime >> priority >> nice
+              >> O >> itrealvalue >> starttime >> vsize >> rss; // don't care about the rest
+  
+  long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages
+  vm_usage     = vsize / 1024.0 / 1024;
+  resident_set = rss * page_size_kb / 1024;
+}
+
+#endif
+
+// -------------------------------------------------------------------
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  void MAdResourceManager::initialize()
+  {
+  }
+
+  // -------------------------------------------------------------------
+  void MAdResourceManager::finalize()
+  {
+  }
+
+  // -------------------------------------------------------------------
+  double MAdResourceManager::getTime() const {
+  
+#ifdef PARALLEL
+    return MPI_Wtime();
+#else
+    struct timeval tp;
+    struct timezone tz;
+#ifdef _WIN_
+    get_time_of_day(&tp,&tz);
+#else
+    gettimeofday(&tp,&tz);
+#endif
+
+    return ((double) tp.tv_sec +
+            (double) ((double) .000001 * (double) tp.tv_usec));
+#endif
+  }
+
+  // -------------------------------------------------------------------
+  double MAdResourceManager::elapsedTime() const {
+
+    return ( getTime() - initialTime );
+
+  }
+
+  // -------------------------------------------------------------------
+  bool MAdResourceManager::getMemoryUsage(double& resident_size,
+                                          double& virtual_size) const
+  {
+#if defined(__linux) || defined(linux)
+    process_mem_usage(virtual_size,resident_size);
+  
+#ifdef PARALLEL
+    double send[2] = {virtual_size,resident_size};
+    double recv[2];
+    MPI_Allreduce(send,recv,2,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
+    virtual_size  = recv[0];
+    resident_size = recv[1];
+#endif
+    return true;
+#else
+    MAdMsgSgl::instance().info(__LINE__,__FILE__,
+                               "Process memory statistics not reliable on this platform");
+    return false;
+#endif
+  }
+
+  // -------------------------------------------------------------------
+  void MAdResourceManager::printMemoryUsage(std::string step, 
+                                            std::ostream& out) const
+  {
+    double ram, virt;
+    getMemoryUsage(ram,virt);
+    out << "Memory usage at step \'"<<step<<"\': " 
+        << ram  << " Mb (resident), "
+        << virt << " Mb (virtual)\n";
+  }
+}
+
+// -------------------------------------------------------------------
diff --git a/Common/MAdResourceManager.h b/Common/MAdResourceManager.h
new file mode 100644
index 0000000..e6de555
--- /dev/null
+++ b/Common/MAdResourceManager.h
@@ -0,0 +1,54 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MADRESOURCEMANAGER
+#define _H_MADRESOURCEMANAGER
+
+#include "MAdSingleton.h"
+#include <iostream>
+#include <string>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class MAdResourceManager {
+
+  public:
+  
+    MAdResourceManager()  { reset(); };
+    ~MAdResourceManager() {};
+  
+    void initialize();
+    void finalize();
+
+    void reset() { initialTime = getTime(); };
+    double elapsedTime() const;
+    double getTime() const;
+
+    //! Gives the amount of memory currently used in the RAM (resident_size) 
+    //! and in total (RAM, cache, disk) (virtual_size) \ingroup tools
+    bool getMemoryUsage(double& resident_size, double& virtual_size) const;
+    void printMemoryUsage(std::string step="", std::ostream& out=std::cout) const;
+
+  private:
+
+    double initialTime;
+
+  };
+
+  // -------------------------------------------------------------------
+
+  typedef MAdSingleton<MAdResourceManager> MAdResourceManagerSgl;
+}
+
+#endif
diff --git a/Common/MAdSingleton.h b/Common/MAdSingleton.h
new file mode 100644
index 0000000..4e37ec4
--- /dev/null
+++ b/Common/MAdSingleton.h
@@ -0,0 +1,20 @@
+// -*- C++ -*-
+
+#ifndef MAD_H_MADSINGLETON
+#define MAD_H_MADSINGLETON
+
+template<typename T> class MAdSingleton
+{
+ public:
+
+  static T& instance()
+    {
+      static T theSingleInstance; // suppose T has a default constructor
+      return theSingleInstance;
+    }
+
+ private:
+  MAdSingleton();
+};
+
+#endif
diff --git a/Common/MAdStringFieldEvaluator.cc b/Common/MAdStringFieldEvaluator.cc
new file mode 100644
index 0000000..7a76953
--- /dev/null
+++ b/Common/MAdStringFieldEvaluator.cc
@@ -0,0 +1,143 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifdef _HAVE_MATHEX_
+
+#include "MAdStringFieldEvaluator.h"
+
+#include <iostream>
+#include <iomanip>
+#include <stdlib.h>
+using std::list;
+using std::vector;
+using std::string;
+
+namespace MAd {
+
+  // ----------------------------------------------------------------------
+  MAdStringFieldEvaluator :: MAdStringFieldEvaluator (int numberOfStrings, ...):
+    MAdFieldEvaluator() 
+  {
+    vector<string> exp;
+  
+    va_list ap;
+    va_start(ap,numberOfStrings);
+    for (int i=0;i<numberOfStrings;i++){
+      const char *s = va_arg(ap,const char *); 
+      string str = s;
+      exp.push_back(str);
+    }
+    va_end(ap);
+
+    buildEvaluators(exp);
+  }
+
+  // ----------------------------------------------------------------------
+  MAdStringFieldEvaluator::MAdStringFieldEvaluator(const vector<string>& exp):
+    MAdFieldEvaluator()
+  {
+    buildEvaluators(exp);
+  }
+
+  // ----------------------------------------------------------------------
+  void MAdStringFieldEvaluator::buildEvaluators(const vector<string>& exp)
+  {
+    vector<string>::const_iterator eIter = exp.begin();
+    for (;eIter!=exp.end();eIter++) {
+
+      smlib::mathex * expr = new smlib::mathex();
+      expr->addvar("x",&x);
+      expr->addvar("y",&y);
+      expr->addvar("z",&z);
+      expr->addvar("t",&t);
+
+      bool success = false;
+      bool parsed  = false;
+      try {
+        expr->expression(*eIter);
+        expr->parse();
+        parsed  = true;
+        success = true;
+      }
+      catch(smlib::mathex::error e) {
+        std::cout << e.what() << std::endl;
+        if(!parsed) {
+          std::cout << *eIter << std::endl;
+          std::cout << std::setw(expr->stopposition()) << "^" << std::endl;
+        }
+      }
+      if ( !success ){
+        std::cerr << "Error when parsing string field evaluator: possible symbols are exp, log, log10, sqrt, sin, cos, tan, sinh, cosh, tanh, asin, acos, atan, abs, round, floor, ceil, trunc, deg, fac, rad\n";
+        exit(0);
+      }
+      expressions.push_back(expr);
+    }
+  }
+
+  // ----------------------------------------------------------------------
+  MAdStringFieldEvaluator::~MAdStringFieldEvaluator()
+  {
+    std::list<smlib::mathex*>::iterator it = expressions.begin();
+    for (; it!=expressions.end(); ++it) {
+      delete(*it);
+    }
+  }
+
+  // ----------------------------------------------------------------------
+  bool MAdStringFieldEvaluator::eval(const vector<double> space, 
+                                            double time, 
+                                            double * val) const 
+  {
+    if (space.size() != 3) throw;
+
+    double spaceTbl[3];
+    for (int i=0; i<3; i++) spaceTbl[i] = space[i];
+
+    return eval(spaceTbl, time, val);
+  }
+
+  // ----------------------------------------------------------------------
+  bool MAdStringFieldEvaluator::eval(const double space[3], 
+                                            double time, 
+                                            double * val) const 
+  {
+    x = space[0];
+    y = space[1];
+    z = space[2];
+    t = time;
+  
+    int i = 0;
+    std::list<smlib::mathex*>::const_iterator it = expressions.begin();
+    for (; it!=expressions.end(); ++it) {
+      val[i++] = (*it)->eval();
+    }
+
+    return true;
+  }
+
+  // ----------------------------------------------------------------------
+  int MAdStringFieldEvaluator::nbVar() const
+  {
+    return expressions.size();
+  }
+
+  // ----------------------------------------------------------------------
+  int MAdStringFieldEvaluator::order() const
+  {
+    return 3;
+  }
+
+  // ----------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Common/MAdStringFieldEvaluator.h b/Common/MAdStringFieldEvaluator.h
new file mode 100644
index 0000000..d65e964
--- /dev/null
+++ b/Common/MAdStringFieldEvaluator.h
@@ -0,0 +1,108 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MADSTRINGFIELDEVALUATOR
+#define _H_MADSTRINGFIELDEVALUATOR
+
+#include "MAdFieldEvaluator.h"
+
+#ifdef _HAVE_MATHEX_
+
+#include "mathex.h"
+
+#include <list>
+#include <cstdarg>
+#include <string>
+#include <vector>
+
+namespace MAd {
+
+  // ----------------------------------------------------------------------
+  class MAdStringFieldEvaluator : public MAdFieldEvaluator
+  {
+
+  public:
+
+    ~MAdStringFieldEvaluator ();
+    // int numberOfStrings is the number of "const char *" given in "..."
+    MAdStringFieldEvaluator (int numberOfStrings, ...);
+    MAdStringFieldEvaluator(const std::vector<std::string>&);
+
+  private:
+
+    void buildEvaluators(const std::vector<std::string>& exp);
+
+  public:
+
+    bool eval (const double space[3], double time, double * val) const ;
+    bool eval (const std::vector<double> space, double time, double * val) const ;
+
+    int nbVar() const;
+    int order() const;
+
+  private:
+
+    mutable double x,y,z,t;
+    std::list<smlib::mathex*> expressions;
+
+  };
+
+}
+
+#else
+
+#include "MAdMessage.h"
+
+namespace MAd {
+
+  // ----------------------------------------------------------------------
+  class MAdStringFieldEvaluator : public MAdFieldEvaluator
+  {
+
+  public:
+
+    ~MAdStringFieldEvaluator () {}
+    MAdStringFieldEvaluator (int, ...)
+    {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "No string evaluation library available");
+    }
+    MAdStringFieldEvaluator(const std::vector<std::string>&)
+    {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "No string evaluation library available");
+    }
+
+  private:
+
+    void buildEvaluators(const std::vector<std::string>&) { throw; }
+
+  public:
+
+    bool eval (const double space[3], double time, double * val) const 
+    { throw; return false; }
+    bool eval (const std::vector<double> space, double time, double * val) const 
+    { throw; return false; }
+
+    int nbVar() const { throw; return -1; }
+    int order() const { throw; return -1; }
+
+  };
+
+  // ----------------------------------------------------------------------
+
+}
+
+#endif
+
+#endif
diff --git a/Common/MAdVector3.h b/Common/MAdVector3.h
new file mode 100644
index 0000000..b93120b
--- /dev/null
+++ b/Common/MAdVector3.h
@@ -0,0 +1,71 @@
+// -*- C++ -*-
+
+#ifndef _H_MADVECTOR3
+#define _H_MADVECTOR3
+
+#ifdef _HAVE_GMSH_
+  
+#include "gmsh/SVector3.h"
+namespace MAd {
+  typedef SVector3 vec3;
+}
+
+#else
+  
+#include "MAdMessage.h"
+
+namespace MAd {
+
+  class MAdVector3
+  {
+  public:
+    MAdVector3() {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Metric not implemented in MAdLib, Gmsh required");
+    }
+    MAdVector3(double x, double y, double z) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Metric not implemented in MAdLib, Gmsh required");
+    }
+    MAdVector3(double v) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Metric not implemented in MAdLib, Gmsh required");
+    }
+    MAdVector3(const double *array) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Metric not implemented in MAdLib, Gmsh required");
+    }
+    MAdVector3(const MAdVector3& v) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Metric not implemented in MAdLib, Gmsh required");
+    }
+    inline double x(void) const { return -1.; }
+    inline double y(void) const { return -1.; }
+    inline double z(void) const { return -1.; }
+    inline double norm() { return -1.; }
+    inline double normSq() { return -1.; }
+    double normalize() { return -1.; }
+    void negate() {}  
+    double &operator[](int i){ }
+    double operator[](int i) const { return -1.; }
+    double &operator()(int i){ }
+    double operator()(int i) const { return -1.; }
+    MAdVector3 & operator += (const MAdVector3 &a) { return *this; }
+    MAdVector3 & operator -= (const MAdVector3 &a) { return *this; }
+    MAdVector3 & operator *= (const MAdVector3 &a) { return *this; }
+    MAdVector3 & operator *= (const double v) { return *this; }
+    MAdVector3 & operator = (double v) { return *this; }
+    operator double *() { return NULL; }
+    void print(std::string name="") const {}
+  };
+  
+  typedef MAdVector3 vec3;
+  
+  inline MAdVector3 crossprod(const MAdVector3 &a, const MAdVector3 &b)
+  { return MAdVector3(); }
+
+}
+
+#endif
+
+#endif
diff --git a/Common/Makefile b/Common/Makefile
new file mode 100644
index 0000000..3f66744
--- /dev/null
+++ b/Common/Makefile
@@ -0,0 +1,54 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information. 
+# You should have received a copy of these files along with MAdLib. 
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../variables
+
+LIB = ../lib/libMAdCommon${LIBEXT}
+
+INC = ${MAdLib_INCLUDES}
+
+ALLFLAGS = ${OPTIM} ${CXXFLAGS} ${MAdLib_DEFS} ${FLAGS} ${INC} ${SYSINCLUDE}
+
+SRC = MathUtils.cc\
+      MAdStringFieldEvaluator.cc\
+      MAdMessage.cc\
+      MAdMatrix.cc\
+      MAdMetric.cc\
+      MAdResourceManager.cc\
+      MAdLib.cc
+
+OBJ = ${SRC:.cc=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cc
+
+${LIB}: ${OBJ} 
+	${AR} ${ARFLAGS} ${LIB} ${OBJ}
+	${RANLIB} ${LIB}
+
+cpobj: ${OBJ} 
+	cp -f ${OBJ} ${MAdLib_TMPDIR}/.
+
+.cc${OBJEXT}:
+	${CXX} ${ALLFLAGS} ${DASH}c $< ${DASH}o $@
+
+clean:
+	${RM} */*.o *.o *.obj
+
+purge:
+
+depend:
+	(sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+         ${CXX} -MM ${ALLFLAGS} ${SRC} | sed 's/.o:/$${OBJEXT}:/g' \
+        ) > Makefile.new
+	cp Makefile Makefile.bak
+	cp Makefile.new Makefile
+	rm -f Makefile.new
\ No newline at end of file
diff --git a/Common/MathUtils.cc b/Common/MathUtils.cc
new file mode 100644
index 0000000..4fdddf2
--- /dev/null
+++ b/Common/MathUtils.cc
@@ -0,0 +1,728 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#include "MathUtils.h"
+#include "MAdMessage.h"
+#include "MAdDefines.h"
+
+#include <stdio.h>
+#include <math.h>
+
+#ifdef _HAVE_GSL_
+#include <gsl/gsl_math.h>
+#include <gsl/gsl_eigen.h>
+#endif
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  // VECTORS
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  void diffVec(const double v1[3], const double v0[3], double v01[3])
+  {
+    v01[0] = v1[0] - v0[0];
+    v01[1] = v1[1] - v0[1];
+    v01[2] = v1[2] - v0[2];
+  }
+
+  // -------------------------------------------------------------------
+  double dotProd(const double v1[3], const double v2[3])
+  {
+    return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
+  }
+
+  // -------------------------------------------------------------------
+  void crossProd(const double v1[3], const double v2[3], double cp[3])
+  {
+    cp[0] = v1[1]*v2[2] - v1[2]*v2[1];
+    cp[1] = v1[2]*v2[0] - v1[0]*v2[2];
+    cp[2] = v1[0]*v2[1] - v1[1]*v2[0];
+  }
+
+  // -------------------------------------------------------------------
+  void normalizeVec(const double v[3], double nv[3])
+  {
+    double lSq = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+    if ( lSq <= MAdTOLSQ ) {
+      MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+                                    "Normalization called for a zero vector");
+      nv[0] = v[0]; 
+      nv[1] = v[1]; 
+      nv[2] = v[2];
+    }
+    double invNorm = 1. / sqrt( lSq );
+    nv[0] = v[0] * invNorm ; 
+    nv[1] = v[1] * invNorm ; 
+    nv[2] = v[2] * invNorm ;
+  }
+
+  // -------------------------------------------------------------------
+  void printVec(const double vec[3], const char * name)
+  {
+    printf("\nPrinting vector %s\n",name);
+    for (int i=0; i<3; i++) printf("  %g",vec[i]);
+    printf("\n\n");
+  }
+
+  // -------------------------------------------------------------------
+  bool isNanVec (const double vec[3])
+  {
+    if ( isnan(vec[0]) || isnan(vec[1]) || isnan(vec[2]) ) return true;
+    return false;
+  }
+
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  // MATRICES
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  void transpose(double mat[3][3])
+  {
+    double tmp;
+    tmp = mat[0][1]; mat[0][1] = mat[1][0]; mat[1][0] = tmp;
+    tmp = mat[0][2]; mat[0][2] = mat[2][0]; mat[2][0] = tmp;
+    tmp = mat[1][2]; mat[1][2] = mat[2][1]; mat[2][1] = tmp;
+  }
+
+  // -------------------------------------------------------------------
+  void transpMat(const double mat[3][3], double matT[3][3])
+  {
+    for(int i=0; i<3; i++) for(int j=0; j<3; j++)
+      matT[i][j] = mat[j][i];
+  }
+
+  // -------------------------------------------------------------------
+  double detMat(const double mat[3][3])
+  {
+    return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) -
+            mat[0][1] * (mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]) +
+            mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]));
+  }
+
+  // -------------------------------------------------------------------
+  double traceMat(const double mat[3][3])
+  {
+    return mat[0][0] + mat[1][1] + mat[2][2];
+  }
+
+  // -------------------------------------------------------------------
+  double traceMatMat(const double mat[3][3])
+  {
+    double a00 =  mat[0][0] * mat[0][0] + mat[1][0] * mat[0][1] + mat[2][0] * mat[0][2]; 
+    double a11 =  mat[1][0] * mat[0][1] + mat[1][1] * mat[1][1] + mat[1][2] * mat[2][1]; 
+    double a22 =  mat[2][0] * mat[0][2] + mat[2][1] * mat[1][2] + mat[2][2] * mat[2][2];
+  
+    return a00 + a11 + a22;
+  }
+
+  // -------------------------------------------------------------------
+  void vecMat(const double vec[3], const double mat[3][3], double res[3])
+  {
+    res[0] = mat[0][0] * vec[0] + mat[1][0] * vec[1] + mat[2][0] * vec[2];
+    res[1] = mat[0][1] * vec[0] + mat[1][1] * vec[1] + mat[2][1] * vec[2];
+    res[2] = mat[0][2] * vec[0] + mat[1][2] * vec[1] + mat[2][2] * vec[2];
+  }
+
+  // -------------------------------------------------------------------
+  void matVec(const double mat[3][3], const double vec[3], double res[3])
+  {
+    res[0] = mat[0][0] * vec[0] + mat[0][1] * vec[1] + mat[0][2] * vec[2];
+    res[1] = mat[1][0] * vec[0] + mat[1][1] * vec[1] + mat[1][2] * vec[2];
+    res[2] = mat[2][0] * vec[0] + mat[2][1] * vec[1] + mat[2][2] * vec[2];
+  }
+
+  // -------------------------------------------------------------------
+  void matMat(const double mat1[3][3], const double mat2[3][3], double res[3][3])
+  {
+    res[0][0] = mat1[0][0] * mat2[0][0] + mat1[0][1] * mat2[1][0] + mat1[0][2] * mat2[2][0];
+    res[0][1] = mat1[0][0] * mat2[0][1] + mat1[0][1] * mat2[1][1] + mat1[0][2] * mat2[2][1];
+    res[0][2] = mat1[0][0] * mat2[0][2] + mat1[0][1] * mat2[1][2] + mat1[0][2] * mat2[2][2];
+
+    res[1][0] = mat1[1][0] * mat2[0][0] + mat1[1][1] * mat2[1][0] + mat1[1][2] * mat2[2][0];
+    res[1][1] = mat1[1][0] * mat2[0][1] + mat1[1][1] * mat2[1][1] + mat1[1][2] * mat2[2][1];
+    res[1][2] = mat1[1][0] * mat2[0][2] + mat1[1][1] * mat2[1][2] + mat1[1][2] * mat2[2][2];
+
+    res[2][0] = mat1[2][0] * mat2[0][0] + mat1[2][1] * mat2[1][0] + mat1[2][2] * mat2[2][0];
+    res[2][1] = mat1[2][0] * mat2[0][1] + mat1[2][1] * mat2[1][1] + mat1[2][2] * mat2[2][1];
+    res[2][2] = mat1[2][0] * mat2[0][2] + mat1[2][1] * mat2[1][2] + mat1[2][2] * mat2[2][2];
+  }
+
+  // -------------------------------------------------------------------
+  double vecMatVec(const double mat[3][3], const double vec[3])
+  {
+    double tmp[3];
+    matVec(mat,vec,tmp);
+    return dotProd(vec,tmp);
+  }
+
+  // -------------------------------------------------------------------
+  double inverseMat(const double mat[3][3], double inv[3][3])
+  {
+    double det = detMat(mat);
+    if(det) {
+      double idet = 1. / det;
+      inv[0][0] =  (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) * idet;
+      inv[1][0] = -(mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]) * idet;
+      inv[2][0] =  (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]) * idet;
+      inv[0][1] = -(mat[0][1] * mat[2][2] - mat[0][2] * mat[2][1]) * idet;
+      inv[1][1] =  (mat[0][0] * mat[2][2] - mat[0][2] * mat[2][0]) * idet;
+      inv[2][1] = -(mat[0][0] * mat[2][1] - mat[0][1] * mat[2][0]) * idet;
+      inv[0][2] =  (mat[0][1] * mat[1][2] - mat[0][2] * mat[1][1]) * idet;
+      inv[1][2] = -(mat[0][0] * mat[1][2] - mat[0][2] * mat[1][0]) * idet;
+      inv[2][2] =  (mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0]) * idet;
+    }
+    else{
+      printf("Error: Singular matrix\n");
+      for(int i=0; i<3; i++) for(int j=0; j<3; j++) inv[i][j] = 0.;
+    }
+    return det;
+  }
+
+  // -------------------------------------------------------------------
+  double invertMat(double mat[3][3])
+  {
+    double inv[3][3];
+    double det = inverseMat(mat,inv);
+    for (int i=0; i<3; i++) {
+      for (int j=0; j<3; j++) {
+        mat[i][j] = inv[i][j];
+      }
+    }
+    return det;
+  }
+
+  // -------------------------------------------------------------------
+  bool system(const double A[3][3], const double b[3], double res[3], double * det)
+  {
+    *det = detMat(A);
+    if(*det == 0.0) {
+      res[0] = res[1] = res[2] = 0.0;
+      return false;
+    }
+
+    res[0] = b[0] * (A[1][1] * A[2][2] - A[1][2] * A[2][1]) -
+      A[0][1] * (b[1] * A[2][2] - A[1][2] * b[2]) +
+      A[0][2] * (b[1] * A[2][1] - A[1][1] * b[2]);
+    res[1] = A[0][0] * (b[1] * A[2][2] - A[1][2] * b[2]) -
+      b[0] * (A[1][0] * A[2][2] - A[1][2] * A[2][0]) +
+      A[0][2] * (A[1][0] * b[2] - b[1] * A[2][0]);
+    res[2] = A[0][0] * (A[1][1] * b[2] - b[1] * A[2][1]) -
+      A[0][1] * (A[1][0] * b[2] - b[1] * A[2][0]) +
+      b[0] * (A[1][0] * A[2][1] - A[1][1] * A[2][0]);
+
+    double idet = 1. / (*det);
+    for(int i=0; i<3; i++) res[i] *= idet;
+
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  void printMat(const double mat[3][3], const char * name)
+  {
+    printf("\nPrinting matrix %s\n",name);
+    for (int i=0; i<3; i++) {
+      for (int j=0; j<3; j++) {
+        printf("  %g",mat[i][j]);
+      }
+      printf("\n");
+    }
+    printf("\n");  
+  }
+
+  // -------------------------------------------------------------------
+  void meanRow33(const double mat[3][3], double mean[3])
+  {
+    mean[0] = MAdTHIRD * ( mat[0][0] + mat[1][0] + mat[2][0] );
+    mean[1] = MAdTHIRD * ( mat[0][1] + mat[1][1] + mat[2][1] );
+    mean[2] = MAdTHIRD * ( mat[0][2] + mat[1][2] + mat[2][2] );
+  }
+
+  // -------------------------------------------------------------------
+  void meanRow43(const double mat[4][3], double mean[3])
+  {
+    mean[0] = 0.25 * ( mat[0][0] + mat[1][0] + mat[2][0] + mat[3][0] );
+    mean[1] = 0.25 * ( mat[0][1] + mat[1][1] + mat[2][1] + mat[3][1] );
+    mean[2] = 0.25 * ( mat[0][2] + mat[1][2] + mat[2][2] + mat[3][2] );
+  }
+
+  // -------------------------------------------------------------------
+  bool isNanMat (const double mat[3][3])
+  {
+    if ( isNanVec(mat[0]) || isNanVec(mat[1]) || isNanVec(mat[2]) ) return true;
+    return false;
+  }
+
+  // -------------------------------------------------------------------
+  // Miscellaneous
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  void sort(double lst[3])
+  {
+    for (int i=0; i<3; i++) {
+      int k = i;
+      double mx = lst[i];
+      for (int j=i+1; j<3; j++) if (lst[j] >= mx) { mx = lst[j]; k = j; }
+      if (k != i) { lst[k] = lst[i]; lst[i] = mx; }
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void cubicRoots(const double coef[4], double real[3], double imag[3]) // GCTODO: to be rewritten
+  {
+    double a = coef[3];
+    double b = coef[2];
+    double c = coef[1];
+    double d = coef[0];
+
+    if(!a || !d){
+      printf("Error: Degenerate cubic: use a second degree solver!\n");
+      return;
+    }
+
+    b /= a;
+    c /= a;
+    d /= a;
+  
+    double q = (3.0*c - (b*b))/9.0;
+    double r = -(27.0*d) + b*(9.0*c - 2.0*(b*b));
+    r /= 54.0;
+
+    double discrim = q*q*q + r*r;
+    imag[0] = 0.0; // The first root is always real.
+    double term1 = (b/3.0);
+
+    if (discrim > 0) { // one root is real, two are complex
+      double s = r + sqrt(discrim);
+      s = ((s < 0) ? -pow(-s, (1.0/3.0)) : pow(s, (1.0/3.0)));
+      double t = r - sqrt(discrim);
+      t = ((t < 0) ? -pow(-t, (1.0/3.0)) : pow(t, (1.0/3.0)));
+      real[0] = -term1 + s + t;
+      term1 += (s + t)/2.0;
+      real[1] = real[2] = -term1;
+      term1 = sqrt(3.0)*(-t + s)/2;
+      imag[1] = term1;
+      imag[2] = -term1;
+      return;
+    }
+
+    // The remaining options are all real
+    imag[1] = imag[2] = 0.0;
+  
+    double r13;
+    if (discrim == 0){ // All roots real, at least two are equal.
+      r13 = ((r < 0) ? -pow(-r,(1.0/3.0)) : pow(r,(1.0/3.0)));
+      real[0] = -term1 + 2.0*r13;
+      real[1] = real[2] = -(r13 + term1);
+      return;
+    }
+
+    // Only option left is that all roots are real and unequal (to get
+    // here, q < 0)
+    q = -q;
+    double dum1 = q*q*q;
+    dum1 = acos(r/sqrt(dum1));
+    r13 = 2.0*sqrt(q);
+    real[0] = -term1 + r13*cos(dum1/3.0);
+    real[1] = -term1 + r13*cos((dum1 + 2.0*M_PI)/3.0);
+    real[2] = -term1 + r13*cos((dum1 + 4.0*M_PI)/3.0);
+  }
+
+
+  // -------------------------------------------------------------------
+  // solve x^2 + b x + c = 0
+  // x[2] is always set to be zero
+  // long FindQuadraticRoots(const double b, const double c, double x[3]) // GCTODO: to be rewritten
+  // {
+  //   //    printf("Quadratic roots\n");
+  //   x[2]=0.0;
+  //   double delt=b*b-4.*c;
+  //   if( delt >=0 ) {
+  //     delt=sqrt(delt);
+  //     x[0]=(-b+delt)/2.0;
+  //     x[1]=(-b-delt)/2.0;
+  //     return 3;
+  //   }
+    
+  //   printf("Imaginary roots, impossible, delt=%f\n",delt);
+  //   return 1;
+  // }
+  
+  // -------------------------------------------------------------------
+  // solve x^3 + a1 x^2 + a2 x + a3 = 0
+  // long FindCubicRoots(const double coeff[4], double x[3]) // GCTODO: to be rewritten
+  // {
+  //   double a1 = coeff[2] / coeff[3];
+  //   double a2 = coeff[1] / coeff[3];
+  //   double a3 = coeff[0] / coeff[3];
+    
+  //   if( fabs(a3)<1.0e-8 ) 
+  //     return FindQuadraticRoots(a1,a2,x);
+    
+  //   double Q = (a1 * a1 - 3 * a2) / 9.;
+  //   double R = (2. * a1 * a1 * a1 - 9. * a1 * a2 + 27. * a3) / 54.;
+  //   double Qcubed = Q * Q * Q;
+  //   double d = Qcubed - R * R;
+    
+  //   //    printf ("d = %22.15e Q = %12.5E R = %12.5E Qcubed %12.5E\n",d,Q,R,Qcubed);
+
+  //   /// three roots, 2 equal 
+  //     if(Qcubed == 0.0 || fabs ( Qcubed - R * R ) < 1.e-8 * (fabs ( Qcubed) + fabs( R * R)) )
+  //       {
+  //         double theta;
+  //         if (Qcubed <= 0.0)theta = acos(1.0);
+  //         else if (R / sqrt(Qcubed) > 1.0)theta = acos(1.0); 
+  //         else if (R / sqrt(Qcubed) < -1.0)theta = acos(-1.0); 
+  //         else theta = acos(R / sqrt(Qcubed));
+  //         double sqrtQ = sqrt(Q);
+  //         //      printf("sqrtQ = %12.5E teta=%12.5E a1=%12.5E\n",sqrt(Q),theta,a1);
+  //         x[0] = -2 * sqrtQ * cos( theta           / 3) - a1 / 3;
+  //         x[1] = -2 * sqrtQ * cos((theta + 2 * M_PI) / 3) - a1 / 3;
+  //         x[2] = -2 * sqrtQ * cos((theta + 4 * M_PI) / 3) - a1 / 3;
+  //         return (3);
+  //       }
+
+  //     // Three real roots 
+  //     if (d >= 0.0) {
+  //       double theta = acos(R / sqrt(Qcubed));
+  //       double sqrtQ = sqrt(Q);
+  //       x[0] = -2 * sqrtQ * cos( theta           / 3) - a1 / 3;
+  //       x[1] = -2 * sqrtQ * cos((theta + 2 * M_PI) / 3) - a1 / 3;
+  //       x[2] = -2 * sqrtQ * cos((theta + 4 * M_PI) / 3) - a1 / 3;
+  //       return (3);
+  //     }
+    
+  //     // One real root 
+  //     else {
+  //       printf("IMPOSSIBLE !!!\n");
+
+  //       double e = pow(sqrt(-d) + fabs(R), 1. / 3.);
+  //       if (R > 0)
+  //         e = -e;
+  //       x[0] = (e + Q / e) - a1 / 3.;
+  //       return (1);
+  //     }
+  // }
+
+  // -------------------------------------------------------------------
+  int indexOfMin(double v0, double v1, double v2)
+  {
+    double minV = v0;
+    int index   = 0;
+    if ( v1 < minV ) { minV = v1; index = 1; }
+    if ( v2 < minV ) { minV = v2; index = 2; }
+    return index;
+  }
+
+  // -------------------------------------------------------------------
+  int indexOfMax(double v0, double v1, double v2)
+  {
+    double maxV = v0;
+    int index   = 0;
+    if ( v1 > maxV ) { maxV = v1; index = 1; }
+    if ( v2 > maxV ) { maxV = v2; index = 2; }
+    return index;
+  }
+
+  // -------------------------------------------------------------------
+  double Tri_area(const double xyz[3][3])
+  {
+    double e0[3], e1[3];
+    diffVec(xyz[1],xyz[0],e0);
+    diffVec(xyz[2],xyz[0],e1);
+    double nor[3];
+    crossProd(e0,e1,nor);
+    return ( 0.5 * dotProd(nor,nor) );
+  }
+
+  // -------------------------------------------------------------------
+  double distToLineSq(const double p0[3], const double p1[3], 
+                      const double xyz[3], double proj2pt[3], bool * onSegment)
+  {
+    double v01[3]; diffVec(p1,p0,v01);
+    double v0x[3]; diffVec(xyz,p0,v0x);
+    double t = dotProd(v01,v0x) / dotProd(v01,v01);
+    
+    if ( onSegment ) {
+      *onSegment = false;
+      if ( t >= 0. && t <= 1. ) *onSegment = true;
+    }
+
+    for (int i=0; i<3; i++) {
+      proj2pt[i] = xyz[i] - ( (1.-t) * p0[i] + t * p1[i] );
+    }
+
+    return dotProd(proj2pt,proj2pt);
+  }
+
+  // -------------------------------------------------------------------
+//   double distToLineSq(const double p0[3], const double p1[3], 
+//                       const double xyz[3], bool * onSegment)
+//   {
+//     double v01[3]; diffVec(p1,p0,v01);
+//     double vx0[3]; diffVec(p0,xyz,vx0);
+//     double d01Sq = dotProd(v01,v01);
+//     double dx0Sq = dotProd(vx0,vx0);
+//     double prod  = dotProd(vx0,v01);
+
+//     if ( onSegment ) {
+//       *onSegment = false;
+//       double vx1[3]; diffVec(p1,xyz,vx1);
+//       if ( prod <= 0. && dotProd(vx1,v01) >= 0. ) *onSegment = true;
+//     }
+
+//     return std::max( ( dx0Sq * d01Sq - prod * prod ) / d01Sq, 0. );
+//   }
+  
+  // -------------------------------------------------------------------
+  //! Returns the coordinates (u,v) of the point in the parent element
+  void Tri_linearParams(const double tri[3][3], const double xyz[3], 
+                        double res[2])
+  {
+    double v0X[3], v01[3], v02[3];
+    diffVec(xyz,tri[0],v0X);
+    diffVec(tri[1],tri[0],v01);
+    diffVec(tri[2],tri[0],v02);
+
+    double n[3], nTmp[3];
+    crossProd(v01,v02,n);
+    double ASqInv = 1. / dotProd(n,n);
+
+    crossProd(v0X,v02,nTmp);
+    double A0X2Sq = dotProd(nTmp,nTmp);
+    res[0] = sqrt( A0X2Sq * ASqInv );
+    if ( dotProd(n,nTmp) < 0. ) res[0] = -res[0];
+
+    crossProd(v01,v0X,nTmp);
+    double A01XSq = dotProd(nTmp,nTmp);
+    res[1] = sqrt( A01XSq * ASqInv );
+    if ( dotProd(n,nTmp) < 0. ) res[1] = -res[1];
+
+//     double n[3];
+//     crossProd(v01,v02,n);
+//     double A = sqrt ( dotProd(n,n) );
+//     crossProd(v0X,v02,n);
+//     double A1 = sqrt ( dotProd(n,n) );
+//     crossProd(v01,v0X,n);
+//     double A2 = sqrt ( dotProd(n,n) );
+    
+//     res[0] = A1/A;
+//     res[1] = A2/A;
+  }
+
+  // -------------------------------------------------------------------
+  //! Gets the projection of a point on a plane defined by 3 points
+  //! and a bit representing the zone of the plane on wich the projection 
+  //! falls given by:
+  //!
+  //!            010=2   | 011=3  /  001=1
+  //!                    |       /
+  //!        ------------+--e2--+-----------
+  //!                  v0|     /v2
+  //!                    | 7  /
+  //!            110=6   e0  e1
+  //!                    |  /
+  //!                    | /    101=5
+  //!                    |/
+  //!                  v1+
+  //!                   /|
+  //!                  / |
+  //!                   4
+  //!
+  //! and 8, 9 or 10 if it falls on v0, v1 or v2 (respectively)
+  //!
+  //! Computes the square area of the faces of the tetrahedron defined by the 
+  //! triangle and the point, projected on the plane of the triangle, 
+  //! with the triangle being the first, and then 
+  //! the 3 faces being ordered the same way as the edges e0, e1, e2 in 
+  //! the triangle.
+  //!
+  void pointToTriangle(const double tri[3][3], 
+                       const double xyz[3], 
+                       double proj[3],
+                       int * bit,
+                       double area[4])
+  {
+    pointToPlane(tri,xyz,proj);
+    
+    // find if the projection coincides with any of the 3 points 
+    for(int i=0; i<3; i++) {
+      if( distanceSq(proj,tri[i]) < MAdTOL ) {
+        *bit=8+i;
+//         area[0] = triArea(tri);
+//         area[1] = area[2] = area[3] = 0.;
+//#warning "implement this"
+        return;
+      }
+    }
+    
+    // find normal to the triangle
+    double v01[3], v02[3], norm[3];
+    diffVec(tri[1],tri[0],v01);
+    diffVec(tri[2],tri[0],v02);
+    crossProd(v01,v02,norm);
+
+    double ri[3], rj[3], rk[3];
+    diffVec(proj,tri[0],ri);
+    diffVec(proj,tri[1],rj);
+    diffVec(proj,tri[2],rk);
+    
+    // determine on which side of the edges does the point lie.
+    // First get normal vectors 
+    double temp[3];
+    double normi[3], normj[3], normk[3];
+    crossProd(v01,ri,normi);
+    diffVec(tri[2],tri[1],temp);
+    crossProd(temp,rj,normj);
+    diffVec(tri[0],tri[2],temp);
+    crossProd(temp,rk,normk);
+    
+    double mag[3];
+    mag[0] = dotProd(normi,norm);
+    mag[1] = dotProd(normj,norm);
+    mag[2] = dotProd(normk,norm);
+    
+    if (area) {
+      area[0] = 0.5 * dotProd(norm,norm);
+      area[1] = 0.5 * dotProd(normi,normi);
+      area[2] = 0.5 * dotProd(normj,normj);
+      area[3] = 0.5 * dotProd(normk,normk);
+    }
+
+    int filter[] = {1,2,4};
+    *bit=0;
+    for(int i=0; i<3; i++){
+      if( mag[i] > 0. ) {
+        *bit = *bit | filter[i];
+      }
+    }
+
+  }
+
+  // -------------------------------------------------------------------
+  //! Gets the distance from a point to a triangle. Consider the 
+  //! projection of the point to the plane of the triangle and a bit
+  //! taking the following values according to the zone in which the 
+  //! projection falls:
+  //!
+  //!            010=2   | 011=3|
+  //!                    |      |     001=1
+  //!        ------------+--e2--+v2
+  //!                  v0|     / \
+  //!                    | 7  /   \
+  //!            110=6   e0  e1    \
+  //!                    |  /       \
+  //!                    | /  101=5
+  //!                  v1|/
+  //!        ------------+
+  //!                     \
+  //!             100=4    \
+  //!                       \
+  //!
+  //! and 8, 9 or 10 if it falls on v0, v1 or v2 (respectively).
+  //! The distance will be 
+  //!    * the distance to v0, v1, v2 if the bit = 2,4,1 resp.,
+  //!    * the distance to e0, e1, e2 if the bit = 6,5,3 resp.,
+  //!    * the distance to the projection point if the bit >= 7
+  //!
+  //! Computes the vector from the closest point on the tri to 'xyz'.
+  //!
+  double distToTriangleSq(const double tri[3][3], 
+                          const double xyz[3],
+                          double vec[3])
+  {
+    double distSq = MAdBIG;
+
+    double proj[3];
+    pointToPlane(tri,xyz,proj);
+
+    double par[2];
+    Tri_linearParams(tri,proj,par);
+    
+    // -- see if the closest point is inside the triangle ---
+    if (  par[0] >= 0. && par[1] >= 0. && 
+          par[0] + par[1] <= 1. )
+      {
+        diffVec(xyz,proj,vec);
+        distSq = dotProd(vec,vec);
+      }
+    // --- else ---
+    else
+      {
+        // --- see if the closest point is on an edge of the triangle ---
+        bool onSeg=false, onSegTest;
+        double testD;
+        double testVec[3];
+        for (int iE=0; iE<3; iE++) {
+          testD = distToLineSq(tri[iE],tri[(iE+1)%3],xyz,testVec,&onSegTest);
+          if ( onSegTest ) {
+            if ( testD < distSq ) {
+              distSq = testD;
+              vec[0] = testVec[0]; vec[1] = testVec[1]; vec[2] = testVec[2];
+            }
+            onSeg = true;
+          }
+        }
+
+        // --- otherwise it is a summit of the triangle
+        if ( !onSeg ) {
+          for (int iV=0; iV<3; iV++) {
+            diffVec(xyz,tri[iV],testVec);
+            testD = dotProd(testVec,testVec);
+            if ( testD < distSq ) {
+              distSq = testD;
+              vec[0] = testVec[0]; vec[1] = testVec[1]; vec[2] = testVec[2];
+            }
+          }
+        }
+      }
+
+    return distSq;
+  }
+
+  // -------------------------------------------------------------------
+  //! Gets the projection of a point on a plane defined by 3 points
+  void pointToPlane(const double plane[3][3], 
+                    const double xyz[3], 
+                    double proj[3])
+  {
+    double v01[3], v02[3];
+    diffVec(plane[1],plane[0],v01);
+    diffVec(plane[2],plane[0],v02);
+    double normal[3];
+    crossProd(v01,v02,normal);
+    double areaSq = dotProd(normal,normal);
+  
+    double v0X[3];
+    diffVec(xyz,plane[0],v0X);
+    double ASqX = dotProd(v0X,normal);
+  
+    double ratio = ASqX / areaSq;
+    for (int i=0; i<3; i++) proj[i] = xyz[i] - ratio * normal[i];
+  }
+
+  // -------------------------------------------------------------------
+  double distanceSq(const double xyz0[3], const double xyz1[3])
+  {
+    return ( ( xyz1[0] - xyz0[0] ) * ( xyz1[0] - xyz0[0] ) +
+             ( xyz1[1] - xyz0[1] ) * ( xyz1[1] - xyz0[1] ) +
+             ( xyz1[2] - xyz0[2] ) * ( xyz1[2] - xyz0[2] )  );
+  }
+
+  // -------------------------------------------------------------------
+
+} // End of namespace MAd
diff --git a/Common/MathUtils.h b/Common/MathUtils.h
new file mode 100644
index 0000000..8469b87
--- /dev/null
+++ b/Common/MathUtils.h
@@ -0,0 +1,69 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Gaetan Compere, Jean-Francois Remacle
+// -------------------------------------------------------------------
+
+#ifndef _H_MATHUTILS
+#define _H_MATHUTILS
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  // --- Vectors ---
+
+  void   diffVec      (const double [3], const double [3], double [3]);
+  double dotProd      (const double [3], const double [3]);
+  void   crossProd    (const double [3], const double [3], double [3]);
+  void   normalizeVec (const double [3], double[3]);
+  void   printVec     (const double [3], const char * name="");
+  bool   isNanVec     (const double [3]);
+
+  // -------------------------------------------------------------------
+  // --- Matrices ---
+
+  void   transpose    (double [3][3]);
+  void   transpMat    (const double [3][3], double [3][3]);
+  double detMat       (const double [3][3]);
+  double traceMat     (const double [3][3]);
+  double traceMatMat  (const double [3][3]);
+  void   vecMat       (const double [3],    const double [3][3], double [3]);
+  void   matVec       (const double [3][3], const double [3],    double [3]);
+  double vecMatVec    (const double [3][3], const double [3]);
+  void   matMat       (const double [3][3], const double [3][3], double [3][3]);
+  double inverseMat   (const double [3][3], double [3][3]);
+  double invertMat    (double [3][3]);
+  bool   system       (const double [3][3], const double [3], double [3], double *);
+  void   printMat     (const double [3][3], const char * name="");
+  void   meanRow33    (const double [3][3], double [3]);
+  void   meanRow43    (const double [4][3], double [3]);
+  bool   isNanMat     (const double [3][3]);
+
+  // -------------------------------------------------------------------
+
+  void sort(double [3]);
+  void cubicRoots(const double [4], double [3], double [3]);
+  int indexOfMin(double, double, double);
+  int indexOfMax(double, double, double);
+  double Tri_area(const double [3][3]);
+  void Tri_linearParams(const double tri[3][3], const double xyz[3], double res[2]);
+  double distToLineSq(const double p0[3], const double p1[3], 
+                      const double xyz[3], double proj2pt[3], bool *onSegment=0);
+  double distToTriangleSq(const double tri[3][3], const double xyz[3], double vec[3]);
+  void pointToTriangle(const double tri[3][3], const double xyz[3], 
+                       double proj[3], int * bit, double area[4]=0);
+  void pointToPlane(const double [3][3], const double [3], double[3]);
+  double distanceSq(const double[3], const double[3]);
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Contrib/ANN/Copyright.txt b/Contrib/ANN/Copyright.txt
new file mode 100755
index 0000000..201b616
--- /dev/null
+++ b/Contrib/ANN/Copyright.txt
@@ -0,0 +1,47 @@
+ANN: Approximate Nearest Neighbors
+Version: 1.1
+Release Date: May 3, 2005
+----------------------------------------------------------------------------
+Copyright (c) 1997-2006 University of Maryland and Sunil Arya and David
+Mount All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU Lesser Public License as published by the
+Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser Public License for more details.
+
+A copy of the terms and conditions of the license can be found in
+License.txt or online at
+
+    http://www.gnu.org/copyleft/lesser.html
+
+To obtain a copy, write to the Free Software Foundation, Inc.,
+59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Disclaimer
+----------
+The University of Maryland and the authors make no representations about
+the suitability or fitness of this software for any purpose.  It is
+provided "as is" without express or implied warranty.
+---------------------------------------------------------------------
+
+Authors
+-------
+David Mount
+Dept of Computer Science
+University of Maryland,
+College Park, MD 20742 USA
+mount at cs.umd.edu
+http://www.cs.umd.edu/~mount/
+
+Sunil Arya
+Dept of Computer Science
+Hong University of Science and Technology
+Clearwater Bay, HONG KONG
+arya at cs.ust.hk
+http://www.cs.ust.hk/faculty/arya/
diff --git a/Contrib/ANN/License.txt b/Contrib/ANN/License.txt
new file mode 100755
index 0000000..456ea97
--- /dev/null
+++ b/Contrib/ANN/License.txt
@@ -0,0 +1,450 @@
+----------------------------------------------------------------------
+The ANN Library (all versions) is provided under the terms and
+conditions of the GNU Lesser General Public Library, which is stated
+below.  It can also be found at:
+
+   http://www.gnu.org/copyleft/lesser.html
+
+----------------------------------------------------------------------
+
+GNU LESSER GENERAL PUBLIC LICENSE
+
+Version 2.1, February 1999
+
+Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+as the successor of the GNU Library Public License, version 2, hence the
+version number 2.1.]
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to
+share and change it. By contrast, the GNU General Public Licenses are
+intended to guarantee your freedom to share and change free software--to
+make sure the software is free for all its users.
+
+This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the Free
+Software Foundation and other authors who decide to use it. You can use
+it too, but we suggest you first think carefully about whether this
+license or the ordinary General Public License is the better strategy to
+use in any particular case, based on the explanations below.
+
+When we speak of free software, we are referring to freedom of use, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish); that you receive source code or can get it if
+you want it; that you can change the software and use pieces of it in
+new free programs; and that you are informed that you can do these
+things.
+
+To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for you
+if you distribute copies of the library or if you modify it.
+
+For example, if you distribute copies of the library, whether gratis or
+for a fee, you must give the recipients all the rights that we gave you.
+You must make sure that they, too, receive or can get the source code.
+If you link other code with the library, you must provide complete
+object files to the recipients, so that they can relink them with the
+library after making changes to the library and recompiling it. And you
+must show them these terms so they know their rights.
+
+We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+To protect each distributor, we want to make it very clear that there is
+no warranty for the free library. Also, if the library is modified by
+someone else and passed on, the recipients should know that what they
+have is not the original version, so that the original author's
+reputation will not be affected by problems that might be introduced by
+others.
+
+Finally, software patents pose a constant threat to the existence of any
+free program. We wish to make sure that a company cannot effectively
+restrict the users of a free program by obtaining a restrictive license
+from a patent holder. Therefore, we insist that any patent license
+obtained for a version of the library must be consistent with the full
+freedom of use specified in this license.
+
+Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License. This license, the GNU Lesser General Public
+License, applies to certain designated libraries, and is quite different
+from the ordinary General Public License. We use this license for
+certain libraries in order to permit linking those libraries into
+non-free programs.
+
+When a program is linked with a library, whether statically or using a
+shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the entire
+combination fits its criteria of freedom. The Lesser General Public
+License permits more lax criteria for linking other code with the
+library.
+
+We call this license the "Lesser" General Public License because it does
+Less to protect the user's freedom than the ordinary General Public
+License. It also provides other free software developers Less of an
+advantage over competing non-free programs. These disadvantages are the
+reason we use the ordinary General Public License for many libraries.
+However, the Lesser license provides advantages in certain special
+circumstances.
+
+For example, on rare occasions, there may be a special need to encourage
+the widest possible use of a certain library, so that it becomes a
+de-facto standard. To achieve this, non-free programs must be allowed to
+use the library. A more frequent case is that a free library does the
+same job as widely used non-free libraries. In this case, there is
+little to gain by limiting the free library to free software only, so we
+use the Lesser General Public License.
+
+In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of free
+software. For example, permission to use the GNU C Library in non-free
+programs enables many more people to use the whole GNU operating system,
+as well as its variant, the GNU/Linux operating system.
+
+Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is linked
+with the Library has the freedom and the wherewithal to run that program
+using a modified version of the Library.
+
+The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or other
+authorized party saying it may be distributed under the terms of this
+Lesser General Public License (also called "this License"). Each
+licensee is addressed as "you".
+
+A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+The "Library", below, refers to any such software library or work which
+has been distributed under these terms. A "work based on the Library"
+means either the Library or any derivative work under copyright law:
+that is to say, a work containing the Library or a portion of it, either
+verbatim or with modifications and/or translated straightforwardly into
+another language. (Hereinafter, translation is included without
+limitation in the term "modification".)
+
+"Source code" for a work means the preferred form of the work for making
+modifications to it. For a library, complete source code means all the
+source code for all modules it contains, plus any associated interface
+definition files, plus the scripts used to control compilation and
+installation of the library.
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of running
+a program using the Library is not restricted, and output from such a
+program is covered only if its contents constitute a work based on the
+Library (independent of the use of the Library in a tool for writing
+it). Whether that is true depends on what the Library does and what the
+program that uses the Library does.
+
+1. You may copy and distribute verbatim copies of the Library's complete
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the notices
+that refer to this License and to the absence of any warranty; and
+distribute a copy of this License along with the Library.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Library or any portion of
+it, thus forming a work based on the Library, and copy and distribute
+such modifications or work under the terms of Section 1 above, provided
+that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+    b) You must cause the files modified to carry prominent notices
+       stating that you changed the files and the date of any change.
+    c) You must cause the whole of the work to be licensed at no
+       charge to all third parties under the terms of this License.
+    d) If a facility in the modified Library refers to a function or a
+       table of data to be supplied by an application program that uses
+       the facility, other than as an argument passed when the facility
+       is invoked, then you must make a good faith effort to ensure that,
+       in the event an application does not supply such function or
+       table, the facility still operates, and performs whatever part of
+       its purpose remains meaningful.
+
+      (For example, a function in a library to compute square roots has
+a purpose that is entirely well-defined independent of the application.
+Therefore, Subsection 2d requires that any application-supplied function
+or table used by this function must be optional: if the application does
+not supply it, the square root function must still compute square
+roots.)
+
+      These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library, and
+can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based on
+the Library, the distribution of the whole must be on the terms of this
+License, whose permissions for other licensees extend to the entire
+whole, and thus to each and every part regardless of who wrote it.
+
+      Thus, it is not the intent of this section to claim rights or
+contest your rights to work written entirely by you; rather, the intent
+is to exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+      In addition, mere aggregation of another work not based on the
+Library with the Library (or with a work based on the Library) on a
+volume of a storage or distribution medium does not bring the other work
+under the scope of this License. 
+
+3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so that
+they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in these
+notices.
+
+Once this change is made in a given copy, it is irreversible for that
+copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+This option is useful when you wish to copy part of the code of the
+Library into a program that is not a library.
+
+4. You may copy and distribute the Library (or a portion or derivative
+of it, under Section 2) in object code or executable form under the
+terms of Sections 1 and 2 above provided that you accompany it with the
+complete corresponding machine-readable source code, which must be
+distributed under the terms of Sections 1 and 2 above on a medium
+customarily used for software interchange.
+
+If distribution of object code is made by offering access to copy from a
+designated place, then offering equivalent access to copy the source
+code from the same place satisfies the requirement to distribute the
+source code, even though third parties are not compelled to copy the
+source along with the object code.
+
+5. A program that contains no derivative of any portion of the Library,
+but is designed to work with the Library by being compiled or linked
+with it, is called a "work that uses the Library". Such a work, in
+isolation, is not a derivative work of the Library, and therefore falls
+outside the scope of this License.
+
+However, linking a "work that uses the Library" with the Library creates
+an executable that is a derivative of the Library (because it contains
+portions of the Library), rather than a "work that uses the library".
+The executable is therefore covered by this License. Section 6 states
+terms for distribution of such executables.
+
+When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be linked
+without the Library, or if the work is itself a library. The threshold
+for this to be true is not precisely defined by law.
+
+If such an object file uses only numerical parameters, data structure
+layouts and accessors, and small macros and small inline functions (ten
+lines or less in length), then the use of the object file is
+unrestricted, regardless of whether it is legally a derivative work.
+(Executables containing this object code plus portions of the Library
+will still fall under Section 6.)
+
+Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6, whether
+or not they are linked directly with the Library itself.
+
+6. As an exception to the Sections above, you may also combine or link a
+"work that uses the Library" with the Library to produce a work
+containing portions of the Library, and distribute that work under terms
+of your choice, provided that the terms permit modification of the work
+for the customer's own use and reverse engineering for debugging such
+modifications.
+
+You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work during
+execution displays copyright notices, you must include the copyright
+notice for the Library among them, as well as a reference directing the
+user to the copy of this License. Also, you must do one of these things:
+
+    a) Accompany the work with the complete corresponding
+       machine-readable source code for the Library including whatever
+       changes were used in the work (which must be distributed under
+       Sections 1 and 2 above); and, if the work is an executable linked
+       with the Library, with the complete machine-readable "work that
+       uses the Library", as object code and/or source code, so that the
+       user can modify the Library and then relink to produce a modified
+       executable containing the modified Library. (It is understood that
+       the user who changes the contents of definitions files in the
+       Library will not necessarily be able to recompile the application
+       to use the modified definitions.)
+    b) Use a suitable shared library mechanism for linking with the
+       Library. A suitable mechanism is one that (1) uses at run time a
+       copy of the library already present on the user's computer system,
+       rather than copying library functions into the executable, and (2)
+       will operate properly with a modified version of the library, if
+       the user installs one, as long as the modified version is
+       interface-compatible with the version that the work was made with.
+    c) Accompany the work with a written offer, valid for at least
+       three years, to give the same user the materials specified in
+       Subsection 6a, above, for a charge no more than the cost of
+       performing this distribution.
+    d) If distribution of the work is made by offering access to copy
+       from a designated place, offer equivalent access to copy the above
+       specified materials from the same place.
+    e) Verify that the user has already received a copy of these
+       materials or that you have already sent this user a copy. 
+
+For an executable, the required form of the "work that uses the Library"
+must include any data and utility programs needed for reproducing the
+executable from it. However, as a special exception, the materials to be
+distributed need not include anything that is normally distributed (in
+either source or binary form) with the major components (compiler,
+kernel, and so on) of the operating system on which the executable runs,
+unless that component itself accompanies the executable.
+
+It may happen that this requirement contradicts the license restrictions
+of other proprietary libraries that do not normally accompany the
+operating system. Such a contradiction means you cannot use both them
+and the Library together in an executable that you distribute.
+
+7. You may place library facilities that are a work based on the Library
+side-by-side in a single library together with other library facilities
+not covered by this License, and distribute such a combined library,
+provided that the separate distribution of the work based on the Library
+and of the other library facilities is otherwise permitted, and provided
+that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+       based on the Library, uncombined with any other library
+       facilities. This must be distributed under the terms of the
+       Sections above.
+    b) Give prominent notice with the combined library of the fact
+       that part of it is a work based on the Library, and explaining
+       where to find the accompanying uncombined form of the same work. 
+
+8. You may not copy, modify, sublicense, link with, or distribute the
+Library except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense, link with, or distribute the
+Library is void, and will automatically terminate your rights under this
+License. However, parties who have received copies, or rights, from you
+under this License will not have their licenses terminated so long as
+such parties remain in full compliance.
+
+9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and all
+its terms and conditions for copying, distributing or modifying the
+Library or works based on it.
+
+10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot distribute
+so as to satisfy simultaneously your obligations under this License and
+any other pertinent obligations, then as a consequence you may not
+distribute the Library at all. For example, if a patent license would
+not permit royalty-free redistribution of the Library by all those who
+receive copies directly or indirectly through you, then the only way you
+could satisfy both it and this License would be to refrain entirely from
+distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply, and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is implemented
+by public license practices. Many people have made generous
+contributions to the wide range of software distributed through that
+system in reliance on consistent application of that system; it is up to
+the author/donor to decide if he or she is willing to distribute
+software through any other system and a licensee cannot impose that
+choice.
+
+This section is intended to make thoroughly clear what is believed to be
+a consequence of the rest of this License.
+
+12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may
+add an explicit geographical distribution limitation excluding those
+countries, so that distribution is permitted only in or among countries
+not thus excluded. In such case, this License incorporates the
+limitation as if written in the body of this License.
+
+13. The Free Software Foundation may publish revised and/or new versions
+of the Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a license
+version number, you may choose any version ever published by the Free
+Software Foundation.
+
+14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free Software
+Foundation; we sometimes make exceptions for this. Our decision will be
+guided by the two goals of preserving the free status of all derivatives
+of our free software and of promoting the sharing and reuse of software
+generally.
+
+NO WARRANTY
+
+15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH
+YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
+DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
+DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY
+(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
+INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF
+THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR
+OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 
diff --git a/Contrib/ANN/Makefile b/Contrib/ANN/Makefile
new file mode 100755
index 0000000..4451f2e
--- /dev/null
+++ b/Contrib/ANN/Makefile
@@ -0,0 +1,25 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information. 
+# You should have received a copy of these files along with MAdLib. 
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../../variables
+
+default:
+	@cd src && ${MAKE}
+
+cpobj:
+	@cd src && ${MAKE} cpobj
+
+clean:
+	@cd src && ${MAKE} clean
+
+depend:
+	@cd src && ${MAKE} depend
diff --git a/Contrib/ANN/README b/Contrib/ANN/README
new file mode 100755
index 0000000..e55716c
--- /dev/null
+++ b/Contrib/ANN/README
@@ -0,0 +1,2 @@
+See the Copyright.txt and License.txt files for copyright and license
+information.
diff --git a/Contrib/ANN/include/ANN/ANN.h b/Contrib/ANN/include/ANN/ANN.h
new file mode 100755
index 0000000..ca8146a
--- /dev/null
+++ b/Contrib/ANN/include/ANN/ANN.h
@@ -0,0 +1,829 @@
+//----------------------------------------------------------------------
+// File:			ANN.h
+// Programmer:		Sunil Arya and David Mount
+// Last modified:	05/03/05 (Release 1.1)
+// Description:		Basic include file for approximate nearest
+//					neighbor searching.
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+//
+// This software and related documentation is part of the 
+// Approximate Nearest Neighbor Library (ANN).
+// 
+// Permission to use, copy, and distribute this software and its 
+// documentation is hereby granted free of charge, provided that 
+// (1) it is not a component of a commercial product, and 
+// (2) this notice appears in all copies of the software and
+//   related documentation. 
+// 
+// The University of Maryland (U.M.) and the authors make no representations
+// about the suitability or fitness of this software for any purpose.  It is
+// provided "as is" without express or implied warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//	Revision 1.0  04/01/05
+//		Added copyright and revision information
+//		Added ANNcoordPrec for coordinate precision.
+//		Added methods theDim, nPoints, maxPoints, thePoints to ANNpointSet.
+//		Cleaned up C++ structure for modern compilers
+//	Revision 1.1  05/03/05
+//		Added fixed-radius k-NN searching
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// ANN - approximate nearest neighbor searching
+//	ANN is a library for approximate nearest neighbor searching,
+//	based on the use of standard and priority search in kd-trees
+//	and balanced box-decomposition (bbd) trees. Here are some
+//	references to the main algorithmic techniques used here:
+//
+//		kd-trees:
+//			Friedman, Bentley, and Finkel, ``An algorithm for finding
+//				best matches in logarithmic expected time,'' ACM
+//				Transactions on Mathematical Software, 3(3):209-226, 1977.
+//
+//		Priority search in kd-trees:
+//			Arya and Mount, ``Algorithms for fast vector quantization,''
+//				Proc. of DCC '93: Data Compression Conference, eds. J. A.
+//				Storer and M. Cohn, IEEE Press, 1993, 381-390.
+//
+//		Approximate nearest neighbor search and bbd-trees:
+//			Arya, Mount, Netanyahu, Silverman, and Wu, ``An optimal
+//				algorithm for approximate nearest neighbor searching,''
+//				5th Ann. ACM-SIAM Symposium on Discrete Algorithms,
+//				1994, 573-582.
+//----------------------------------------------------------------------
+
+#ifndef ANN_H
+#define ANN_H
+
+#ifdef WIN33
+  //----------------------------------------------------------------------
+  // For Microsoft Visual C++, externally accessible symbols must be
+  // explicitly indicated with DLL_API, which is somewhat like "extern."
+  //
+  // The following ifdef block is the standard way of creating macros
+  // which make exporting from a DLL simpler. All files within this DLL
+  // are compiled with the DLL_EXPORTS preprocessor symbol defined on the
+  // command line. In contrast, projects that use (or import) the DLL
+  // objects do not define the DLL_EXPORTS symbol. This way any other
+  // project whose source files include this file see DLL_API functions as
+  // being imported from a DLL, wheras this DLL sees symbols defined with
+  // this macro as being exported.
+  //----------------------------------------------------------------------
+  #ifdef DLL_EXPORTS
+	 #define DLL_API __declspec(dllexport)
+  #else
+	#define DLL_API __declspec(dllimport)
+  #endif
+  //----------------------------------------------------------------------
+  // DLL_API is ignored for all other systems
+  //----------------------------------------------------------------------
+#else
+  #define DLL_API
+#endif
+
+//----------------------------------------------------------------------
+//  basic includes
+//----------------------------------------------------------------------
+
+#include <cmath>			// math includes
+#include <iostream>			// I/O streams
+
+//----------------------------------------------------------------------
+// Limits
+// There are a number of places where we use the maximum double value as
+// default initializers (and others may be used, depending on the
+// data/distance representation). These can usually be found in limits.h
+// (as LONG_MAX, INT_MAX) or in float.h (as DBL_MAX, FLT_MAX).
+//
+// Not all systems have these files.  If you are using such a system,
+// you should set the preprocessor symbol ANN_NO_LIMITS_H when
+// compiling, and modify the statements below to generate the
+// appropriate value. For practical purposes, this does not need to be
+// the maximum double value. It is sufficient that it be at least as
+// large than the maximum squared distance between between any two
+// points.
+//----------------------------------------------------------------------
+#ifdef ANN_NO_LIMITS_H					// limits.h unavailable
+  #include <cvalues>					// replacement for limits.h
+  const double ANN_DBL_MAX = MAXDOUBLE;	// insert maximum double
+#else
+  #include <climits>
+  #include <cfloat>
+  const double ANN_DBL_MAX = DBL_MAX;
+#endif
+
+#define ANNversion 		"1.0"			// ANN version and information
+#define ANNversionCmt	""
+#define ANNcopyright	"David M. Mount and Sunil Arya"
+#define ANNlatestRev	"Mar 1, 2005"
+
+//----------------------------------------------------------------------
+//	ANNbool
+//	This is a simple boolean type. Although ANSI C++ is supposed
+//	to support the type bool, some compilers do not have it.
+//----------------------------------------------------------------------
+
+enum ANNbool {ANNfalse = 0, ANNtrue = 1}; // ANN boolean type (non ANSI C++)
+
+//----------------------------------------------------------------------
+//	ANNcoord, ANNdist
+//		ANNcoord and ANNdist are the types used for representing
+//		point coordinates and distances.  They can be modified by the
+//		user, with some care.  It is assumed that they are both numeric
+//		types, and that ANNdist is generally of an equal or higher type
+//		from ANNcoord.	A variable of type ANNdist should be large
+//		enough to store the sum of squared components of a variable
+//		of type ANNcoord for the number of dimensions needed in the
+//		application.  For example, the following combinations are
+//		legal:
+//
+//		ANNcoord		ANNdist
+//		---------		-------------------------------
+//		short			short, int, long, float, double
+//		int				int, long, float, double
+//		long			long, float, double
+//		float			float, double
+//		double			double
+//
+//		It is the user's responsibility to make sure that overflow does
+//		not occur in distance calculation.
+//----------------------------------------------------------------------
+
+typedef double	ANNcoord;				// coordinate data type
+typedef double	ANNdist;				// distance data type
+
+//----------------------------------------------------------------------
+//	ANNidx
+//		ANNidx is a point index.  When the data structure is built, the
+//		points are given as an array.  Nearest neighbor results are
+//		returned as an integer index into this array.  To make it
+//		clearer when this is happening, we define the integer type
+//		ANNidx.	 Indexing starts from 0.
+//		
+//		For fixed-radius near neighbor searching, it is possible that
+//		there are not k nearest neighbors within the search radius.  To
+//		indicate this, the algorithm returns ANN_NULL_IDX as its result.
+//		It should be distinguishable from any valid array index.
+//----------------------------------------------------------------------
+
+typedef int		ANNidx;					// point index
+const ANNidx	ANN_NULL_IDX = -1;		// a NULL point index
+
+//----------------------------------------------------------------------
+//	Infinite distance:
+//		The code assumes that there is an "infinite distance" which it
+//		uses to initialize distances before performing nearest neighbor
+//		searches.  It should be as larger or larger than any legitimate
+//		nearest neighbor distance.
+//
+//		On most systems, these should be found in the standard include
+//		file <limits.h> or possibly <float.h>.  If you do not have these
+//		file, some suggested values are listed below, assuming 64-bit
+//		long, 32-bit int and 16-bit short.
+//
+//		ANNdist ANN_DIST_INF	Values (see <limits.h> or <float.h>)
+//		------- ------------	------------------------------------
+//		double	DBL_MAX			1.79769313486231570e+308
+//		float	FLT_MAX			3.40282346638528860e+38
+//		long	LONG_MAX		0x7fffffffffffffff
+//		int		INT_MAX			0x7fffffff
+//		short	SHRT_MAX		0x7fff
+//----------------------------------------------------------------------
+
+const ANNdist	ANN_DIST_INF = ANN_DBL_MAX;
+
+//----------------------------------------------------------------------
+//	Significant digits for tree dumps:
+//		When floating point coordinates are used, the routine that dumps
+//		a tree needs to know roughly how many significant digits there
+//		are in a ANNcoord, so it can output points to full precision.
+//		This is defined to be ANNcoordPrec.  On most systems these
+//		values can be found in the standard include files <limits.h> or
+//		<float.h>.  For integer types, the value is essentially ignored.
+//
+//		ANNcoord ANNcoordPrec	Values (see <limits.h> or <float.h>)
+//		-------- ------------	------------------------------------
+//		double	 DBL_DIG		15
+//		float	 FLT_DIG		6
+//		long	 doesn't matter 19
+//		int		 doesn't matter 10
+//		short	 doesn't matter 5
+//----------------------------------------------------------------------
+
+#ifdef DBL_DIG							// number of sig. bits in ANNcoord
+	const int	 ANNcoordPrec	= DBL_DIG;
+#else
+	const int	 ANNcoordPrec	= 15;	// default precision
+#endif
+
+//----------------------------------------------------------------------
+// Self match?
+//	In some applications, the nearest neighbor of a point is not
+//	allowed to be the point itself. This occurs, for example, when
+//	computing all nearest neighbors in a set.  By setting the
+//	parameter ANN_ALLOW_SELF_MATCH to ANNfalse, the nearest neighbor
+//	is the closest point whose distance from the query point is
+//	strictly positive.
+//----------------------------------------------------------------------
+
+const ANNbool	ANN_ALLOW_SELF_MATCH	= ANNtrue;
+
+//----------------------------------------------------------------------
+//	Norms and metrics:
+//		ANN supports any Minkowski norm for defining distance.  In
+//		particular, for any p >= 1, the L_p Minkowski norm defines the
+//		length of a d-vector (v0, v1, ..., v(d-1)) to be
+//
+//				(|v0|^p + |v1|^p + ... + |v(d-1)|^p)^(1/p),
+//
+//		(where ^ denotes exponentiation, and |.| denotes absolute
+//		value).  The distance between two points is defined to be the
+//		norm of the vector joining them.  Some common distance metrics
+//		include
+//
+//				Euclidean metric		p = 2
+//				Manhattan metric		p = 1
+//				Max metric				p = infinity
+//
+//		In the case of the max metric, the norm is computed by taking
+//		the maxima of the absolute values of the components.  ANN is
+//		highly "coordinate-based" and does not support general distances
+//		functions (e.g. those obeying just the triangle inequality).  It
+//		also does not support distance functions based on
+//		inner-products.
+//
+//		For the purpose of computing nearest neighbors, it is not
+//		necessary to compute the final power (1/p).  Thus the only
+//		component that is used by the program is |v(i)|^p.
+//
+//		ANN parameterizes the distance computation through the following
+//		macros.  (Macros are used rather than procedures for
+//		efficiency.) Recall that the distance between two points is
+//		given by the length of the vector joining them, and the length
+//		or norm of a vector v is given by formula:
+//
+//				|v| = ROOT(POW(v0) # POW(v1) # ... # POW(v(d-1)))
+//
+//		where ROOT, POW are unary functions and # is an associative and
+//		commutative binary operator mapping the following types:
+//
+//			**	POW:	ANNcoord				--> ANNdist
+//			**	#:		ANNdist x ANNdist		--> ANNdist
+//			**	ROOT:	ANNdist (>0)			--> double
+//
+//		For early termination in distance calculation (partial distance
+//		calculation) we assume that POW and # together are monotonically
+//		increasing on sequences of arguments, meaning that for all
+//		v0..vk and y:
+//
+//		POW(v0) #...# POW(vk) <= (POW(v0) #...# POW(vk)) # POW(y).
+//
+//	Incremental Distance Calculation:
+//		The program uses an optimized method of computing distances for
+//		kd-trees and bd-trees, called incremental distance calculation.
+//		It is used when distances are to be updated when only a single
+//		coordinate of a point has been changed.  In order to use this,
+//		we assume that there is an incremental update function DIFF(x,y)
+//		for #, such that if:
+//
+//					s = x0 # ... # xi # ... # xk 
+//
+//		then if s' is equal to s but with xi replaced by y, that is, 
+//		
+//					s' = x0 # ... # y # ... # xk
+//
+//		then the length of s' can be computed by:
+//
+//					|s'| = |s| # DIFF(xi,y).
+//
+//		Thus, if # is + then DIFF(xi,y) is (yi-x).  For the L_infinity
+//		norm we make use of the fact that in the program this function
+//		is only invoked when y > xi, and hence DIFF(xi,y)=y.
+//
+//		Finally, for approximate nearest neighbor queries we assume
+//		that POW and ROOT are related such that
+//
+//					v*ROOT(x) = ROOT(POW(v)*x)
+//
+//		Here are the values for the various Minkowski norms:
+//
+//		L_p:	p even:							p odd:
+//				-------------------------		------------------------
+//				POW(v)			= v^p			POW(v)			= |v|^p
+//				ROOT(x)			= x^(1/p)		ROOT(x)			= x^(1/p)
+//				#				= +				#				= +
+//				DIFF(x,y)		= y - x			DIFF(x,y)		= y - x 
+//
+//		L_inf:
+//				POW(v)			= |v|
+//				ROOT(x)			= x
+//				#				= max
+//				DIFF(x,y)		= y
+//
+//		By default the Euclidean norm is assumed.  To change the norm,
+//		uncomment the appropriate set of macros below.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+//	Use the following for the Euclidean norm
+//----------------------------------------------------------------------
+#define ANN_POW(v)			((v)*(v))
+#define ANN_ROOT(x)			sqrt(x)
+#define ANN_SUM(x,y)		((x) + (y))
+#define ANN_DIFF(x,y)		((y) - (x))
+
+//----------------------------------------------------------------------
+//	Use the following for the L_1 (Manhattan) norm
+//----------------------------------------------------------------------
+// #define ANN_POW(v)		fabs(v)
+// #define ANN_ROOT(x)		(x)
+// #define ANN_SUM(x,y)		((x) + (y))
+// #define ANN_DIFF(x,y)	((y) - (x))
+
+//----------------------------------------------------------------------
+//	Use the following for a general L_p norm
+//----------------------------------------------------------------------
+// #define ANN_POW(v)		pow(fabs(v),p)
+// #define ANN_ROOT(x)		pow(fabs(x),1/p)
+// #define ANN_SUM(x,y)		((x) + (y))
+// #define ANN_DIFF(x,y)	((y) - (x))
+
+//----------------------------------------------------------------------
+//	Use the following for the L_infinity (Max) norm
+//----------------------------------------------------------------------
+// #define ANN_POW(v)		fabs(v)
+// #define ANN_ROOT(x)		(x)
+// #define ANN_SUM(x,y)		((x) > (y) ? (x) : (y))
+// #define ANN_DIFF(x,y)	(y)
+
+//----------------------------------------------------------------------
+//	Array types
+//		The following array types are of basic interest.  A point is
+//		just a dimensionless array of coordinates, a point array is a
+//		dimensionless array of points.  A distance array is a
+//		dimensionless array of distances and an index array is a
+//		dimensionless array of point indices.  The latter two are used
+//		when returning the results of k-nearest neighbor queries.
+//----------------------------------------------------------------------
+
+typedef ANNcoord* ANNpoint;			// a point
+typedef ANNpoint* ANNpointArray;	// an array of points 
+typedef ANNdist*  ANNdistArray;		// an array of distances 
+typedef ANNidx*   ANNidxArray;		// an array of point indices
+
+//----------------------------------------------------------------------
+//	Basic point and array utilities:
+//		The following procedures are useful supplements to ANN's nearest
+//		neighbor capabilities.
+//
+//		annDist():
+//			Computes the (squared) distance between a pair of points.
+//			Note that this routine is not used internally by ANN for
+//			computing distance calculations.  For reasons of efficiency
+//			this is done using incremental distance calculation.  Thus,
+//			this routine cannot be modified as a method of changing the
+//			metric.
+//
+//		Because points (somewhat like strings in C) are stored as
+//		pointers.  Consequently, creating and destroying copies of
+//		points may require storage allocation.  These procedures do
+//		this.
+//
+//		annAllocPt() and annDeallocPt():
+//				Allocate a deallocate storage for a single point, and
+//				return a pointer to it.  The argument to AllocPt() is
+//				used to initialize all components.
+//
+//		annAllocPts() and annDeallocPts():
+//				Allocate and deallocate an array of points as well a
+//				place to store their coordinates, and initializes the
+//				points to point to their respective coordinates.  It
+//				allocates point storage in a contiguous block large
+//				enough to store all the points.  It performs no
+//				initialization.
+//
+//		annCopyPt():
+//				Creates a copy of a given point, allocating space for
+//				the new point.  It returns a pointer to the newly
+//				allocated copy.
+//----------------------------------------------------------------------
+   
+DLL_API ANNdist annDist(
+	int				dim,		// dimension of space
+	ANNpoint		p,			// points
+	ANNpoint		q);
+
+DLL_API ANNpoint annAllocPt(
+	int				dim,		// dimension
+	ANNcoord		c = 0);		// coordinate value (all equal)
+
+DLL_API ANNpointArray annAllocPts(
+	int				n,			// number of points
+	int				dim);		// dimension
+
+DLL_API void annDeallocPt(
+	ANNpoint		&p);		// deallocate 1 point
+   
+DLL_API void annDeallocPts(
+	ANNpointArray	&pa);		// point array
+
+DLL_API ANNpoint annCopyPt(
+	int				dim,		// dimension
+	ANNpoint		source);	// point to copy
+
+//----------------------------------------------------------------------
+//Overall structure: ANN supports a number of different data structures
+//for approximate and exact nearest neighbor searching.  These are:
+//
+//		ANNbruteForce	A simple brute-force search structure.
+//		ANNkd_tree		A kd-tree tree search structure.  ANNbd_tree
+//		A bd-tree tree search structure (a kd-tree with shrink
+//		capabilities).
+//
+//		At a minimum, each of these data structures support k-nearest
+//		neighbor queries.  The nearest neighbor query, annkSearch,
+//		returns an integer identifier and the distance to the nearest
+//		neighbor(s) and annRangeSearch returns the nearest points that
+//		lie within a given query ball.
+//
+//		Each structure is built by invoking the appropriate constructor
+//		and passing it (at a minimum) the array of points, the total
+//		number of points and the dimension of the space.  Each structure
+//		is also assumed to support a destructor and member functions
+//		that return basic information about the point set.
+//
+//		Note that the array of points is not copied by the data
+//		structure (for reasons of space efficiency), and it is assumed
+//		to be constant throughout the lifetime of the search structure.
+//
+//		The search algorithm, annkSearch, is given the query point (q),
+//		and the desired number of nearest neighbors to report (k), and
+//		the error bound (eps) (whose default value is 0, implying exact
+//		nearest neighbors).  It returns two arrays which are assumed to
+//		contain at least k elements: one (nn_idx) contains the indices
+//		(within the point array) of the nearest neighbors and the other
+//		(dd) contains the squared distances to these nearest neighbors.
+//
+//		The search algorithm, annkFRSearch, is a fixed-radius kNN
+//		search.  In addition to a query point, it is given a (squared)
+//		radius bound.  (This is done for consistency, because the search
+//		returns distances as squared quantities.) It does two things.
+//		First, it computes the k nearest neighbors within the radius
+//		bound, and second, it returns the total number of points lying
+//		within the radius bound. It is permitted to set k = 0, in which
+//		case it effectively answers a range counting query.  If the
+//		error bound epsilon is positive, then the search is approximate
+//		in the sense that it is free to ignore any point that lies
+//		outside a ball of radius r/(1+epsilon), where r is the given
+//		(unsquared) radius bound.
+//
+//		The generic object from which all the search structures are
+//		dervied is given below.  It is a virtual object, and is useless
+//		by itself.
+//----------------------------------------------------------------------
+
+class DLL_API ANNpointSet {
+public:
+	virtual ~ANNpointSet() {}			// virtual distructor
+
+	virtual void annkSearch(			// approx k near neighbor search
+		ANNpoint		q,				// query point
+		int				k,				// number of near neighbors to return
+		ANNidxArray		nn_idx,			// nearest neighbor array (modified)
+		ANNdistArray	dd,				// dist to near neighbors (modified)
+		double			eps=0.0			// error bound
+		) = 0;							// pure virtual (defined elsewhere)
+
+	virtual int annkFRSearch(			// approx fixed-radius kNN search
+		ANNpoint		q,				// query point
+		ANNdist			sqRad,			// squared radius
+		int				k = 0,			// number of near neighbors to return
+		ANNidxArray		nn_idx = NULL,	// nearest neighbor array (modified)
+		ANNdistArray	dd = NULL,		// dist to near neighbors (modified)
+		double			eps=0.0			// error bound
+		) = 0;							// pure virtual (defined elsewhere)
+
+	virtual int theDim() = 0;			// return dimension of space
+	virtual int nPoints() = 0;			// return number of points
+										// return pointer to points
+	virtual ANNpointArray thePoints() = 0;
+};
+
+//----------------------------------------------------------------------
+//	Brute-force nearest neighbor search:
+//		The brute-force search structure is very simple but inefficient.
+//		It has been provided primarily for the sake of comparison with
+//		and validation of the more complex search structures.
+//
+//		Query processing is the same as described above, but the value
+//		of epsilon is ignored, since all distance calculations are
+//		performed exactly.
+//
+//		WARNING: This data structure is very slow, and should not be
+//		used unless the number of points is very small.
+//
+//		Internal information:
+//		---------------------
+//		This data structure bascially consists of the array of points
+//		(each a pointer to an array of coordinates).  The search is
+//		performed by a simple linear scan of all the points.
+//----------------------------------------------------------------------
+
+class DLL_API ANNbruteForce: public ANNpointSet {
+	int				dim;				// dimension
+	int				n_pts;				// number of points
+	ANNpointArray	pts;				// point array
+public:
+	ANNbruteForce(						// constructor from point array
+		ANNpointArray	pa,				// point array
+		int				n,				// number of points
+		int				dd);			// dimension
+
+	~ANNbruteForce();					// destructor
+
+	void annkSearch(					// approx k near neighbor search
+		ANNpoint		q,				// query point
+		int				k,				// number of near neighbors to return
+		ANNidxArray		nn_idx,			// nearest neighbor array (modified)
+		ANNdistArray	dd,				// dist to near neighbors (modified)
+		double			eps=0.0);		// error bound
+
+	int annkFRSearch(					// approx fixed-radius kNN search
+		ANNpoint		q,				// query point
+		ANNdist			sqRad,			// squared radius
+		int				k = 0,			// number of near neighbors to return
+		ANNidxArray		nn_idx = NULL,	// nearest neighbor array (modified)
+		ANNdistArray	dd = NULL,		// dist to near neighbors (modified)
+		double			eps=0.0);		// error bound
+
+	int theDim()						// return dimension of space
+		{ return dim; }
+
+	int nPoints()						// return number of points
+		{ return n_pts; }
+
+	ANNpointArray thePoints()			// return pointer to points
+		{  return pts;  }
+};
+
+//----------------------------------------------------------------------
+// kd- and bd-tree splitting and shrinking rules
+//		kd-trees supports a collection of different splitting rules.
+//		In addition to the standard kd-tree splitting rule proposed
+//		by Friedman, Bentley, and Finkel, we have introduced a
+//		number of other splitting rules, which seem to perform
+//		as well or better (for the distributions we have tested).
+//
+//		The splitting methods given below allow the user to tailor
+//		the data structure to the particular data set.  They are
+//		are described in greater details in the kd_split.cc source
+//		file.  The method ANN_KD_SUGGEST is the method chosen (rather
+//		subjectively) by the implementors as the one giving the
+//		fastest performance, and is the default splitting method.
+//
+//		As with splitting rules, there are a number of different
+//		shrinking rules.  The shrinking rule ANN_BD_NONE does no
+//		shrinking (and hence produces a kd-tree tree).  The rule
+//		ANN_BD_SUGGEST uses the implementors favorite rule.
+//----------------------------------------------------------------------
+
+enum ANNsplitRule {
+		ANN_KD_STD				= 0,	// the optimized kd-splitting rule
+		ANN_KD_MIDPT			= 1,	// midpoint split
+		ANN_KD_FAIR				= 2,	// fair split
+		ANN_KD_SL_MIDPT			= 3,	// sliding midpoint splitting method
+		ANN_KD_SL_FAIR			= 4,	// sliding fair split method
+		ANN_KD_SUGGEST			= 5};	// the authors' suggestion for best
+const int ANN_N_SPLIT_RULES		= 6;	// number of split rules
+
+enum ANNshrinkRule {
+		ANN_BD_NONE				= 0,	// no shrinking at all (just kd-tree)
+		ANN_BD_SIMPLE			= 1,	// simple splitting
+		ANN_BD_CENTROID			= 2,	// centroid splitting
+		ANN_BD_SUGGEST			= 3};	// the authors' suggested choice
+const int ANN_N_SHRINK_RULES	= 4;	// number of shrink rules
+
+//----------------------------------------------------------------------
+//	kd-tree:
+//		The main search data structure supported by ANN is a kd-tree.
+//		The main constructor is given a set of points and a choice of
+//		splitting method to use in building the tree.
+//
+//		Construction:
+//		-------------
+//		The constructor is given the point array, number of points,
+//		dimension, bucket size (default = 1), and the splitting rule
+//		(default = ANN_KD_SUGGEST).  The point array is not copied, and
+//		is assumed to be kept constant throughout the lifetime of the
+//		search structure.  There is also a "load" constructor that
+//		builds a tree from a file description that was created by the
+//		Dump operation.
+//
+//		Search:
+//		-------
+//		There are two search methods:
+//
+//			Standard search (annkSearch()):
+//				Searches nodes in tree-traversal order, always visiting
+//				the closer child first.
+//			Priority search (annkPriSearch()):
+//				Searches nodes in order of increasing distance of the
+//				associated cell from the query point.  For many
+//				distributions the standard search seems to work just
+//				fine, but priority search is safer for worst-case
+//				performance.
+//
+//		Printing:
+//		---------
+//		There are two methods provided for printing the tree.  Print()
+//		is used to produce a "human-readable" display of the tree, with
+//		indenation, which is handy for debugging.  Dump() produces a
+//		format that is suitable reading by another program.  There is a
+//		"load" constructor, which constructs a tree which is assumed to
+//		have been saved by the Dump() procedure.
+//		
+//		Performance and Structure Statistics:
+//		-------------------------------------
+//		The procedure getStats() collects statistics information on the
+//		tree (its size, height, etc.)  See ANNperf.h for information on
+//		the stats structure it returns.
+//
+//		Internal information:
+//		---------------------
+//		The data structure consists of three major chunks of storage.
+//		The first (implicit) storage are the points themselves (pts),
+//		which have been provided by the users as an argument to the
+//		constructor, or are allocated dynamically if the tree is built
+//		using the load constructor).  These should not be changed during
+//		the lifetime of the search structure.  It is the user's
+//		responsibility to delete these after the tree is destroyed.
+//
+//		The second is the tree itself (which is dynamically allocated in
+//		the constructor) and is given as a pointer to its root node
+//		(root).  These nodes are automatically deallocated when the tree
+//		is deleted.  See the file src/kd_tree.h for further information
+//		on the structure of the tree nodes.
+//
+//		Each leaf of the tree does not contain a pointer directly to a
+//		point, but rather contains a pointer to a "bucket", which is an
+//		array consisting of point indices.  The third major chunk of
+//		storage is an array (pidx), which is a large array in which all
+//		these bucket subarrays reside.  (The reason for storing them
+//		separately is the buckets are typically small, but of varying
+//		sizes.  This was done to avoid fragmentation.)  This array is
+//		also deallocated when the tree is deleted.
+//
+//		In addition to this, the tree consists of a number of other
+//		pieces of information which are used in searching and for
+//		subsequent tree operations.  These consist of the following:
+//
+//		dim						Dimension of space
+//		n_pts					Number of points currently in the tree
+//		n_max					Maximum number of points that are allowed
+//								in the tree
+//		bkt_size				Maximum bucket size (no. of points per leaf)
+//		bnd_box_lo				Bounding box low point
+//		bnd_box_hi				Bounding box high point
+//		splitRule				Splitting method used
+//
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// Some types and objects used by kd-tree functions
+// See src/kd_tree.h and src/kd_tree.cpp for definitions
+//----------------------------------------------------------------------
+class ANNkdStats;				// stats on kd-tree
+class ANNkd_node;				// generic node in a kd-tree
+typedef ANNkd_node*	ANNkd_ptr;	// pointer to a kd-tree node
+
+class DLL_API ANNkd_tree: public ANNpointSet {
+protected:
+	int				dim;				// dimension of space
+	int				n_pts;				// number of points in tree
+	int				bkt_size;			// bucket size
+	ANNpointArray	pts;				// the points
+	ANNidxArray		pidx;				// point indices (to pts array)
+	ANNkd_ptr		root;				// root of kd-tree
+	ANNpoint		bnd_box_lo;			// bounding box low point
+	ANNpoint		bnd_box_hi;			// bounding box high point
+
+	void SkeletonTree(					// construct skeleton tree
+		int				n,				// number of points
+		int				dd,				// dimension
+		int				bs,				// bucket size
+		ANNpointArray pa = NULL,		// point array (optional)
+		ANNidxArray pi = NULL);			// point indices (optional)
+
+public:
+	ANNkd_tree(							// build skeleton tree
+		int				n = 0,			// number of points
+		int				dd = 0,			// dimension
+		int				bs = 1);		// bucket size
+
+	ANNkd_tree(							// build from point array
+		ANNpointArray	pa,				// point array
+		int				n,				// number of points
+		int				dd,				// dimension
+		int				bs = 1,			// bucket size
+		ANNsplitRule	split = ANN_KD_SUGGEST);	// splitting method
+
+	ANNkd_tree(							// build from dump file
+		std::istream&	in);			// input stream for dump file
+
+	~ANNkd_tree();						// tree destructor
+
+	void annkSearch(					// approx k near neighbor search
+		ANNpoint		q,				// query point
+		int				k,				// number of near neighbors to return
+		ANNidxArray		nn_idx,			// nearest neighbor array (modified)
+		ANNdistArray	dd,				// dist to near neighbors (modified)
+		double			eps=0.0);		// error bound
+
+	void annkPriSearch( 				// priority k near neighbor search
+		ANNpoint		q,				// query point
+		int				k,				// number of near neighbors to return
+		ANNidxArray		nn_idx,			// nearest neighbor array (modified)
+		ANNdistArray	dd,				// dist to near neighbors (modified)
+		double			eps=0.0);		// error bound
+
+	int annkFRSearch(					// approx fixed-radius kNN search
+		ANNpoint		q,				// the query point
+		ANNdist			sqRad,			// squared radius of query ball
+		int				k,				// number of neighbors to return
+		ANNidxArray		nn_idx = NULL,	// nearest neighbor array (modified)
+		ANNdistArray	dd = NULL,		// dist to near neighbors (modified)
+		double			eps=0.0);		// error bound
+
+	int theDim()						// return dimension of space
+		{ return dim; }
+
+	int nPoints()						// return number of points
+		{ return n_pts; }
+
+	ANNpointArray thePoints()			// return pointer to points
+		{  return pts;  }
+
+	virtual void Print(					// print the tree (for debugging)
+		ANNbool			with_pts,		// print points as well?
+		std::ostream&	out);			// output stream
+
+	virtual void Dump(					// dump entire tree
+		ANNbool			with_pts,		// print points as well?
+		std::ostream&	out);			// output stream
+								
+	virtual void getStats(				// compute tree statistics
+		ANNkdStats&		st);			// the statistics (modified)
+};								
+
+//----------------------------------------------------------------------
+//	Box decomposition tree (bd-tree)
+//		The bd-tree is inherited from a kd-tree.  The main difference
+//		in the bd-tree and the kd-tree is a new type of internal node
+//		called a shrinking node (in the kd-tree there is only one type
+//		of internal node, a splitting node).  The shrinking node
+//		makes it possible to generate balanced trees in which the
+//		cells have bounded aspect ratio, by allowing the decomposition
+//		to zoom in on regions of dense point concentration.  Although
+//		this is a nice idea in theory, few point distributions are so
+//		densely clustered that this is really needed.
+//----------------------------------------------------------------------
+
+class DLL_API ANNbd_tree: public ANNkd_tree {
+public:
+	ANNbd_tree(							// build skeleton tree
+		int				n,				// number of points
+		int				dd,				// dimension
+		int				bs = 1)			// bucket size
+		: ANNkd_tree(n, dd, bs) {}		// build base kd-tree
+
+	ANNbd_tree(							// build from point array
+		ANNpointArray	pa,				// point array
+		int				n,				// number of points
+		int				dd,				// dimension
+		int				bs = 1,			// bucket size
+		ANNsplitRule	split  = ANN_KD_SUGGEST,	// splitting rule
+		ANNshrinkRule	shrink = ANN_BD_SUGGEST);	// shrinking rule
+
+	ANNbd_tree(							// build from dump file
+		std::istream&	in);			// input stream for dump file
+};
+
+//----------------------------------------------------------------------
+//	Other functions
+//	annMaxPtsVisit		Sets a limit on the maximum number of points
+//						to visit in the search.
+//  annClose			Can be called when all use of ANN is finished.
+//						It clears up a minor memory leak.
+//----------------------------------------------------------------------
+
+DLL_API void annMaxPtsVisit(	// max. pts to visit in search
+	int				maxPts);	// the limit
+
+DLL_API void annClose();		// called to end use of ANN
+
+#endif
diff --git a/Contrib/ANN/include/ANN/ANNperf.h b/Contrib/ANN/include/ANN/ANNperf.h
new file mode 100755
index 0000000..b18c816
--- /dev/null
+++ b/Contrib/ANN/include/ANN/ANNperf.h
@@ -0,0 +1,226 @@
+//----------------------------------------------------------------------
+//	File:			ANNperf.h
+//	Programmer:		Sunil Arya and David Mount
+//	Last modified:	03/04/98 (Release 0.1)
+//	Description:	Include file for ANN performance stats
+//
+//	Some of the code for statistics gathering has been adapted
+//	from the SmplStat.h package in the g++ library.
+//----------------------------------------------------------------------
+// Copyright (c) 1997-1998 University of Maryland and Sunil Arya and David
+// Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the 
+// Approximate Nearest Neighbor Library (ANN).
+// 
+// Permission to use, copy, and distribute this software and its 
+// documentation is hereby granted free of charge, provided that 
+// (1) it is not a component of a commercial product, and 
+// (2) this notice appears in all copies of the software and
+//     related documentation. 
+// 
+// The University of Maryland (U.M.) and the authors make no representations
+// about the suitability or fitness of this software for any purpose.  It is
+// provided "as is" without express or implied warranty.
+//----------------------------------------------------------------------
+//      History:
+//      Revision 0.1  03/04/98
+//          Initial release
+//      Revision 1.0  04/01/05
+//          Added ANN_ prefix to avoid name conflicts.
+//----------------------------------------------------------------------
+
+#ifndef ANNperf_H
+#define ANNperf_H
+
+//----------------------------------------------------------------------
+//	basic includes
+//----------------------------------------------------------------------
+
+#include <ANN/ANN.h>					// basic ANN includes
+
+//----------------------------------------------------------------------
+// kd-tree stats object
+//	This object is used for collecting information about a kd-tree
+//	or bd-tree.
+//----------------------------------------------------------------------
+
+class ANNkdStats {			// stats on kd-tree
+public:
+	int		dim;			// dimension of space
+	int		n_pts;			// no. of points
+	int		bkt_size;		// bucket size
+	int		n_lf;			// no. of leaves (including trivial)
+	int		n_tl;			// no. of trivial leaves (no points)
+	int		n_spl;			// no. of splitting nodes
+	int		n_shr;			// no. of shrinking nodes (for bd-trees)
+	int		depth;			// depth of tree
+	float	sum_ar;			// sum of leaf aspect ratios
+	float	avg_ar;			// average leaf aspect ratio
+ //
+							// reset stats
+	void reset(int d=0, int n=0, int bs=0)
+	{
+		dim = d; n_pts = n; bkt_size = bs;
+		n_lf = n_tl = n_spl = n_shr = depth = 0;
+		sum_ar = avg_ar = 0.0;
+	}
+
+	ANNkdStats()			// basic constructor
+	{ reset(); }
+
+	void merge(const ANNkdStats &st);	// merge stats from child 
+};
+
+//----------------------------------------------------------------------
+//  ANNsampStat
+//	A sample stat collects numeric (double) samples and returns some
+//	simple statistics.  Its main functions are:
+//
+//		reset()		Reset to no samples.
+//		+= x		Include sample x.
+//		samples()	Return number of samples.
+//		mean()		Return mean of samples.
+//		stdDev()	Return standard deviation
+//		min()		Return minimum of samples.
+//		max()		Return maximum of samples.
+//----------------------------------------------------------------------
+class DLL_API ANNsampStat {
+	int				n;				// number of samples
+	double			sum;			// sum
+	double			sum2;			// sum of squares
+	double			minVal, maxVal;	// min and max
+public :
+	void reset()				// reset everything
+	{  
+		n = 0;
+		sum = sum2 = 0;
+		minVal = ANN_DBL_MAX;
+		maxVal = -ANN_DBL_MAX; 
+	}
+
+	ANNsampStat() { reset(); }		// constructor
+
+	void operator+=(double x)		// add sample
+	{
+		n++;  sum += x;  sum2 += x*x;
+		if (x < minVal) minVal = x;
+		if (x > maxVal) maxVal = x;
+	}
+
+	int samples() { return n; }		// number of samples
+
+	double mean() { return sum/n; } // mean
+
+									// standard deviation
+	double stdDev() { return sqrt((sum2 - (sum*sum)/n)/(n-1));}
+
+	double min() { return minVal; } // minimum
+	double max() { return maxVal; } // maximum
+};
+
+//----------------------------------------------------------------------
+//		Operation count updates
+//----------------------------------------------------------------------
+
+#ifdef ANN_PERF
+  #define ANN_FLOP(n)	{ann_Nfloat_ops += (n);}
+  #define ANN_LEAF(n)	{ann_Nvisit_lfs += (n);}
+  #define ANN_SPL(n)	{ann_Nvisit_spl += (n);}
+  #define ANN_SHR(n)	{ann_Nvisit_shr += (n);}
+  #define ANN_PTS(n)	{ann_Nvisit_pts += (n);}
+  #define ANN_COORD(n)	{ann_Ncoord_hts += (n);}
+#else
+  #define ANN_FLOP(n)
+  #define ANN_LEAF(n)
+  #define ANN_SPL(n)
+  #define ANN_SHR(n)
+  #define ANN_PTS(n)
+  #define ANN_COORD(n)
+#endif
+
+//----------------------------------------------------------------------
+//	Performance statistics
+//	The following data and routines are used for computing performance
+//	statistics for nearest neighbor searching.  Because these routines
+//	can slow the code down, they can be activated and deactiviated by
+//	defining the ANN_PERF variable, by compiling with the option:
+//	-DANN_PERF
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+//	Global counters for performance measurement
+//
+//	visit_lfs	The number of leaf nodes visited in the
+//				tree.
+//
+//	visit_spl	The number of splitting nodes visited in the
+//				tree.
+//
+//	visit_shr	The number of shrinking nodes visited in the
+//				tree.
+//
+//	visit_pts	The number of points visited in all the
+//				leaf nodes visited. Equivalently, this
+//				is the number of points for which distance
+//				calculations are performed.
+//
+//	coord_hts	The number of times a coordinate of a 
+//				data point is accessed. This is generally
+//				less than visit_pts*d if partial distance
+//				calculation is used.  This count is low
+//				in the sense that if a coordinate is hit
+//				many times in the same routine we may
+//				count it only once.
+//
+//	float_ops	The number of floating point operations.
+//				This includes all operations in the heap
+//				as well as distance calculations to boxes.
+//
+//	average_err	The average error of each query (the
+//				error of the reported point to the true
+//				nearest neighbor).  For k nearest neighbors
+//				the error is computed k times.
+//
+//	rank_err	The rank error of each query (the difference
+//				in the rank of the reported point and its
+//				true rank).
+//
+//	data_pts	The number of data points.  This is not
+//				a counter, but used in stats computation.
+//----------------------------------------------------------------------
+
+extern int			ann_Ndata_pts;	// number of data points
+extern int			ann_Nvisit_lfs;	// number of leaf nodes visited
+extern int			ann_Nvisit_spl;	// number of splitting nodes visited
+extern int			ann_Nvisit_shr;	// number of shrinking nodes visited
+extern int			ann_Nvisit_pts;	// visited points for one query
+extern int			ann_Ncoord_hts;	// coordinate hits for one query
+extern int			ann_Nfloat_ops;	// floating ops for one query
+extern ANNsampStat	ann_visit_lfs;	// stats on leaf nodes visits
+extern ANNsampStat	ann_visit_spl;	// stats on splitting nodes visits
+extern ANNsampStat	ann_visit_shr;	// stats on shrinking nodes visits
+extern ANNsampStat	ann_visit_nds;	// stats on total nodes visits
+extern ANNsampStat	ann_visit_pts;	// stats on points visited
+extern ANNsampStat	ann_coord_hts;	// stats on coordinate hits
+extern ANNsampStat	ann_float_ops;	// stats on floating ops
+//----------------------------------------------------------------------
+//  The following need to be part of the public interface, because
+//  they are accessed outside the DLL in ann_test.cpp.
+//----------------------------------------------------------------------
+DLL_API extern ANNsampStat ann_average_err;	// average error
+DLL_API extern ANNsampStat ann_rank_err;	// rank error
+
+//----------------------------------------------------------------------
+//	Declaration of externally accessible routines for statistics
+//----------------------------------------------------------------------
+
+DLL_API void annResetStats(int data_size);	// reset stats for a set of queries
+
+DLL_API void annResetCounts();				// reset counts for one queries
+
+DLL_API void annUpdateStats();				// update stats with current counts
+
+DLL_API void annPrintStats(ANNbool validate); // print statistics for a run
+
+#endif
diff --git a/Contrib/ANN/include/ANN/ANNx.h b/Contrib/ANN/include/ANN/ANNx.h
new file mode 100755
index 0000000..38b07b7
--- /dev/null
+++ b/Contrib/ANN/include/ANN/ANNx.h
@@ -0,0 +1,170 @@
+//----------------------------------------------------------------------
+//	File:			ANNx.h
+//	Programmer: 	Sunil Arya and David Mount
+//	Last modified:	03/04/98 (Release 0.1)
+//	Description:	Internal include file for ANN
+//
+//	These declarations are of use in manipulating some of
+//	the internal data objects appearing in ANN, but are not
+//	needed for applications just using the nearest neighbor
+//	search.
+//
+//	Typical users of ANN should not need to access this file.
+//----------------------------------------------------------------------
+// Copyright (c) 1997-1998 University of Maryland and Sunil Arya and David
+// Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the 
+// Approximate Nearest Neighbor Library (ANN).
+// 
+// Permission to use, copy, and distribute this software and its 
+// documentation is hereby granted free of charge, provided that 
+// (1) it is not a component of a commercial product, and 
+// (2) this notice appears in all copies of the software and
+//   related documentation. 
+// 
+// The University of Maryland (U.M.) and the authors make no representations
+// about the suitability or fitness of this software for any purpose.  It is
+// provided "as is" without express or implied warranty.
+//----------------------------------------------------------------------
+//	History:
+//	Revision 0.1  03/04/98
+//	    Initial release
+//	Revision 1.0  04/01/05
+//	    Changed LO, HI, IN, OUT to ANN_LO, ANN_HI, etc.
+//----------------------------------------------------------------------
+
+#ifndef ANNx_H
+#define ANNx_H
+
+#include <iomanip>				// I/O manipulators
+#include <ANN/ANN.h>			// ANN includes
+
+//----------------------------------------------------------------------
+//	Global constants and types
+//----------------------------------------------------------------------
+enum	{ANN_LO=0, ANN_HI=1};	// splitting indices
+enum	{ANN_IN=0, ANN_OUT=1};	// shrinking indices
+								// what to do in case of error
+enum ANNerr {ANNwarn = 0, ANNabort = 1};
+
+//----------------------------------------------------------------------
+//	Maximum number of points to visit
+//	We have an option for terminating the search early if the
+//	number of points visited exceeds some threshold.  If the
+//	threshold is 0 (its default)  this means there is no limit
+//	and the algorithm applies its normal termination condition.
+//----------------------------------------------------------------------
+
+extern int		ANNmaxPtsVisited;	// maximum number of pts visited
+extern int		ANNptsVisited;		// number of pts visited in search
+
+//----------------------------------------------------------------------
+//	Global function declarations
+//----------------------------------------------------------------------
+
+void annError(					// ANN error routine
+	char			*msg,		// error message
+	ANNerr			level);		// level of error
+
+void annPrintPt(				// print a point
+	ANNpoint		pt,			// the point
+	int				dim,		// the dimension
+	std::ostream	&out);		// output stream
+
+//----------------------------------------------------------------------
+//	Orthogonal (axis aligned) rectangle
+//	Orthogonal rectangles are represented by two points, one
+//	for the lower left corner (min coordinates) and the other
+//	for the upper right corner (max coordinates).
+//
+//	The constructor initializes from either a pair of coordinates,
+//	pair of points, or another rectangle.  Note that all constructors
+//	allocate new point storage. The destructor deallocates this
+//	storage.
+//
+//	BEWARE: Orthogonal rectangles should be passed ONLY BY REFERENCE.
+//	(C++'s default copy constructor will not allocate new point
+//	storage, then on return the destructor free's storage, and then
+//	you get into big trouble in the calling procedure.)
+//----------------------------------------------------------------------
+
+class ANNorthRect {
+public:
+	ANNpoint		lo;			// rectangle lower bounds
+	ANNpoint		hi;			// rectangle upper bounds
+//
+	ANNorthRect(				// basic constructor
+	int				dd,			// dimension of space
+	ANNcoord		l=0,		// default is empty
+	ANNcoord		h=0)
+	{  lo = annAllocPt(dd, l);  hi = annAllocPt(dd, h); }
+
+	ANNorthRect(				// (almost a) copy constructor
+	int				dd,			// dimension
+	const			ANNorthRect &r) // rectangle to copy
+	{  lo = annCopyPt(dd, r.lo);  hi = annCopyPt(dd, r.hi);  }
+
+	ANNorthRect(				// construct from points
+	int				dd,			// dimension
+	ANNpoint		l,			// low point
+	ANNpoint		h)			// hight point
+	{  lo = annCopyPt(dd, l);  hi = annCopyPt(dd, h);  }
+
+	~ANNorthRect()				// destructor
+    {  annDeallocPt(lo);  annDeallocPt(hi);  }
+
+	ANNbool inside(int dim, ANNpoint p);// is point p inside rectangle?
+};
+
+void annAssignRect(				// assign one rect to another
+	int				dim,		// dimension (both must be same)
+	ANNorthRect		&dest,		// destination (modified)
+	const ANNorthRect &source);	// source
+
+//----------------------------------------------------------------------
+//	Orthogonal (axis aligned) halfspace
+//	An orthogonal halfspace is represented by an integer cutting
+//	dimension cd, coordinate cutting value, cv, and side, sd, which is
+//	either +1 or -1. Our convention is that point q lies in the (closed)
+//	halfspace if (q[cd] - cv)*sd >= 0.
+//----------------------------------------------------------------------
+
+class ANNorthHalfSpace {
+public:
+	int				cd;			// cutting dimension
+	ANNcoord		cv;			// cutting value
+	int				sd;			// which side
+//
+	ANNorthHalfSpace()			// default constructor
+	{  cd = 0; cv = 0;  sd = 0;  }
+
+	ANNorthHalfSpace(			// basic constructor
+	int				cdd,		// dimension of space
+	ANNcoord		cvv,		// cutting value
+	int				sdd)		// side
+	{  cd = cdd;  cv = cvv;  sd = sdd;  }
+
+	ANNbool in(ANNpoint q) const	// is q inside halfspace?
+	{  return  (ANNbool) ((q[cd] - cv)*sd >= 0);  }
+
+	ANNbool out(ANNpoint q) const	// is q outside halfspace?
+	{  return  (ANNbool) ((q[cd] - cv)*sd < 0);  }
+
+	ANNdist dist(ANNpoint q) const	// (squared) distance from q
+	{  return  (ANNdist) ANN_POW(q[cd] - cv);  }
+
+	void setLowerBound(int d, ANNpoint p)// set to lower bound at p[i]
+	{  cd = d;  cv = p[d];  sd = +1;  }
+
+	void setUpperBound(int d, ANNpoint p)// set to upper bound at p[i]
+	{  cd = d;  cv = p[d];  sd = -1;  }
+
+	void project(ANNpoint &q)		// project q (modified) onto halfspace
+	{  if (out(q)) q[cd] = cv;  }
+};
+
+								// array of halfspaces
+typedef ANNorthHalfSpace *ANNorthHSArray;
+
+#endif
diff --git a/Contrib/ANN/src/ANN.cpp b/Contrib/ANN/src/ANN.cpp
new file mode 100755
index 0000000..79d1215
--- /dev/null
+++ b/Contrib/ANN/src/ANN.cpp
@@ -0,0 +1,199 @@
+//----------------------------------------------------------------------
+// File:			ANN.cpp
+// Programmer:		Sunil Arya and David Mount
+// Description:		Methods for ANN.h and ANNx.h
+// Last modified:	01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//	Revision 1.0  04/01/05
+//		Added performance counting to annDist()
+//----------------------------------------------------------------------
+
+#include <ANN/ANNx.h>					// all ANN includes
+#include <ANN/ANNperf.h>				// ANN performance 
+#include <stdlib.h> // for gmsh
+
+using namespace std;					// make std:: accessible
+
+//----------------------------------------------------------------------
+//	Point methods
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+//	Distance utility.
+//		(Note: In the nearest neighbor search, most distances are
+//		computed using partial distance calculations, not this
+//		procedure.)
+//----------------------------------------------------------------------
+
+ANNdist annDist(						// interpoint squared distance
+	int					dim,
+	ANNpoint			p,
+	ANNpoint			q)
+{
+	register int d;
+	register ANNcoord diff;
+	register ANNcoord dist;
+
+	dist = 0;
+	for (d = 0; d < dim; d++) {
+		diff = p[d] - q[d];
+		dist = ANN_SUM(dist, ANN_POW(diff));
+	}
+	ANN_FLOP(3*dim)					// performance counts
+	ANN_PTS(1)
+	ANN_COORD(dim)
+	return dist;
+}
+
+//----------------------------------------------------------------------
+//	annPrintPoint() prints a point to a given output stream.
+//----------------------------------------------------------------------
+
+void annPrintPt(						// print a point
+	ANNpoint			pt,				// the point
+	int					dim,			// the dimension
+	std::ostream		&out)			// output stream
+{
+	for (int j = 0; j < dim; j++) {
+		out << pt[j];
+		if (j < dim-1) out << " ";
+	}
+}
+
+//----------------------------------------------------------------------
+//	Point allocation/deallocation:
+//
+//		Because points (somewhat like strings in C) are stored
+//		as pointers.  Consequently, creating and destroying
+//		copies of points may require storage allocation.  These
+//		procedures do this.
+//
+//		annAllocPt() and annDeallocPt() allocate a deallocate
+//		storage for a single point, and return a pointer to it.
+//
+//		annAllocPts() allocates an array of points as well a place
+//		to store their coordinates, and initializes the points to
+//		point to their respective coordinates.  It allocates point
+//		storage in a contiguous block large enough to store all the
+//		points.  It performs no initialization.
+//
+//		annDeallocPts() should only be used on point arrays allocated
+//		by annAllocPts since it assumes that points are allocated in
+//		a block.
+//
+//		annCopyPt() copies a point taking care to allocate storage
+//		for the new point.
+//
+//		annAssignRect() assigns the coordinates of one rectangle to
+//		another.  The two rectangles must have the same dimension
+//		(and it is not possible to test this here).
+//----------------------------------------------------------------------
+
+ANNpoint annAllocPt(int dim, ANNcoord c)		// allocate 1 point
+{
+	ANNpoint p = new ANNcoord[dim];
+	for (int i = 0; i < dim; i++) p[i] = c;
+	return p;
+}
+   
+ANNpointArray annAllocPts(int n, int dim)		// allocate n pts in dim
+{
+	ANNpointArray pa = new ANNpoint[n];			// allocate points
+	ANNpoint	  p  = new ANNcoord[n*dim];		// allocate space for coords
+	for (int i = 0; i < n; i++) {
+		pa[i] = &(p[i*dim]);
+	}
+	return pa;
+}
+
+void annDeallocPt(ANNpoint &p)					// deallocate 1 point
+{
+	delete [] p;
+	p = NULL;
+}
+   
+void annDeallocPts(ANNpointArray &pa)			// deallocate points
+{
+	delete [] pa[0];							// dealloc coordinate storage
+	delete [] pa;								// dealloc points
+	pa = NULL;
+}
+   
+ANNpoint annCopyPt(int dim, ANNpoint source)	// copy point
+{
+	ANNpoint p = new ANNcoord[dim];
+	for (int i = 0; i < dim; i++) p[i] = source[i];
+	return p;
+}
+   
+												// assign one rect to another
+void annAssignRect(int dim, ANNorthRect &dest, const ANNorthRect &source)
+{
+	for (int i = 0; i < dim; i++) {
+		dest.lo[i] = source.lo[i];
+		dest.hi[i] = source.hi[i];
+	}
+}
+
+												// is point inside rectangle?
+ANNbool ANNorthRect::inside(int dim, ANNpoint p)
+{
+	for (int i = 0; i < dim; i++) {
+		if (p[i] < lo[i] || p[i] > hi[i]) return ANNfalse;
+	}
+	return ANNtrue;
+}
+
+//----------------------------------------------------------------------
+//	Error handler
+//----------------------------------------------------------------------
+
+void annError(char *msg, ANNerr level)
+{
+	if (level == ANNabort) {
+		cerr << "ANN: ERROR------->" << msg << "<-------------ERROR\n";
+		exit(1);
+	}
+	else {
+		cerr << "ANN: WARNING----->" << msg << "<-------------WARNING\n";
+	}
+}
+
+//----------------------------------------------------------------------
+//	Limit on number of points visited
+//		We have an option for terminating the search early if the
+//		number of points visited exceeds some threshold.  If the
+//		threshold is 0 (its default)  this means there is no limit
+//		and the algorithm applies its normal termination condition.
+//		This is for applications where there are real time constraints
+//		on the running time of the algorithm.
+//----------------------------------------------------------------------
+
+int	ANNmaxPtsVisited = 0;	// maximum number of pts visited
+int	ANNptsVisited;			// number of pts visited in search
+
+//----------------------------------------------------------------------
+//	Global function declarations
+//----------------------------------------------------------------------
+
+void annMaxPtsVisit(			// set limit on max. pts to visit in search
+	int					maxPts)			// the limit
+{
+	ANNmaxPtsVisited = maxPts;
+}
diff --git a/Contrib/ANN/src/Makefile b/Contrib/ANN/src/Makefile
new file mode 100755
index 0000000..78c86a4
--- /dev/null
+++ b/Contrib/ANN/src/Makefile
@@ -0,0 +1,60 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information. 
+# You should have received a copy of these files along with MAdLib. 
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../../../variables
+
+LIB = ../../../lib/libMAdANN${LIBEXT}
+
+INC = ${DASH}I../../../Common ${DASH}I../include
+
+ALLFLAGS = ${OPTIM} ${CXXFLAGS} ${FLAGS} ${INC} ${SYSINCLUDE}
+
+SRC = ANN.cpp\
+      bd_fix_rad_search.cpp\
+      bd_pr_search.cpp\
+      bd_search.cpp\
+      bd_tree.cpp\
+      brute.cpp\
+      kd_dump.cpp\
+      kd_fix_rad_search.cpp\
+      kd_pr_search.cpp\
+      kd_search.cpp\
+      kd_split.cpp\
+      kd_tree.cpp\
+      kd_util.cpp\
+      perf.cpp
+
+OBJ = ${SRC:.cpp=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cpp
+
+${LIB}: ${OBJ} 
+	${AR} ${ARFLAGS}${LIB} ${OBJ} 
+	${RANLIB} ${LIB}
+
+cpobj: ${OBJ} 
+	cp -f ${OBJ} ../../../lib/
+
+.cpp${OBJEXT}:
+	${CXX} ${ALLFLAGS} ${DASH}c $<
+
+clean:
+	${RM} *.o *.obj
+
+depend:
+	(sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+         ${CXX} -MM ${ALLFLAGS} ${SRC} | sed 's/.o:/$${OBJEXT}:/g' \
+        ) > Makefile.new
+	cp Makefile Makefile.bak
+	cp Makefile.new Makefile
+	rm -f Makefile.new
+
diff --git a/Contrib/ANN/src/bd_fix_rad_search.cpp b/Contrib/ANN/src/bd_fix_rad_search.cpp
new file mode 100755
index 0000000..dea3f6b
--- /dev/null
+++ b/Contrib/ANN/src/bd_fix_rad_search.cpp
@@ -0,0 +1,61 @@
+//----------------------------------------------------------------------
+// File:			bd_fix_rad_search.cpp
+// Programmer:		David Mount
+// Description:		Standard bd-tree search
+// Last modified:	05/03/05 (Version 1.1)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 1.1  05/03/05
+//		Initial release
+//----------------------------------------------------------------------
+
+#include "bd_tree.h"					// bd-tree declarations
+#include "kd_fix_rad_search.h"			// kd-tree FR search declarations
+
+//----------------------------------------------------------------------
+//	Approximate searching for bd-trees.
+//		See the file kd_FR_search.cpp for general information on the
+//		approximate nearest neighbor search algorithm.  Here we
+//		include the extensions for shrinking nodes.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+//	bd_shrink::ann_FR_search - search a shrinking node
+//----------------------------------------------------------------------
+
+void ANNbd_shrink::ann_FR_search(ANNdist box_dist)
+{
+												// check dist calc term cond.
+	if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return;
+
+	ANNdist inner_dist = 0;						// distance to inner box
+	for (int i = 0; i < n_bnds; i++) {			// is query point in the box?
+		if (bnds[i].out(ANNkdFRQ)) {			// outside this bounding side?
+												// add to inner distance
+			inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNkdFRQ));
+		}
+	}
+	if (inner_dist <= box_dist) {				// if inner box is closer
+		child[ANN_IN]->ann_FR_search(inner_dist);// search inner child first
+		child[ANN_OUT]->ann_FR_search(box_dist);// ...then outer child
+	}
+	else {										// if outer box is closer
+		child[ANN_OUT]->ann_FR_search(box_dist);// search outer child first
+		child[ANN_IN]->ann_FR_search(inner_dist);// ...then outer child
+	}
+	ANN_FLOP(3*n_bnds)							// increment floating ops
+	ANN_SHR(1)									// one more shrinking node
+}
diff --git a/Contrib/ANN/src/bd_pr_search.cpp b/Contrib/ANN/src/bd_pr_search.cpp
new file mode 100755
index 0000000..d16d632
--- /dev/null
+++ b/Contrib/ANN/src/bd_pr_search.cpp
@@ -0,0 +1,62 @@
+//----------------------------------------------------------------------
+// File:			bd_pr_search.cpp
+// Programmer:		David Mount
+// Description:		Priority search for bd-trees
+// Last modified:	01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+//History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//----------------------------------------------------------------------
+
+#include "bd_tree.h"					// bd-tree declarations
+#include "kd_pr_search.h"				// kd priority search declarations
+
+//----------------------------------------------------------------------
+//	Approximate priority searching for bd-trees.
+//		See the file kd_pr_search.cc for general information on the
+//		approximate nearest neighbor priority search algorithm.  Here
+//		we include the extensions for shrinking nodes.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+//	bd_shrink::ann_search - search a shrinking node
+//----------------------------------------------------------------------
+
+void ANNbd_shrink::ann_pri_search(ANNdist box_dist)
+{
+	ANNdist inner_dist = 0;						// distance to inner box
+	for (int i = 0; i < n_bnds; i++) {			// is query point in the box?
+		if (bnds[i].out(ANNprQ)) {				// outside this bounding side?
+												// add to inner distance
+			inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNprQ));
+		}
+	}
+	if (inner_dist <= box_dist) {				// if inner box is closer
+		if (child[ANN_OUT] != KD_TRIVIAL)		// enqueue outer if not trivial
+			ANNprBoxPQ->insert(box_dist,child[ANN_OUT]);
+												// continue with inner child
+		child[ANN_IN]->ann_pri_search(inner_dist);
+	}
+	else {										// if outer box is closer
+		if (child[ANN_IN] != KD_TRIVIAL)		// enqueue inner if not trivial
+			ANNprBoxPQ->insert(inner_dist,child[ANN_IN]);
+												// continue with outer child
+		child[ANN_OUT]->ann_pri_search(box_dist);
+	}
+	ANN_FLOP(3*n_bnds)							// increment floating ops
+	ANN_SHR(1)									// one more shrinking node
+}
diff --git a/Contrib/ANN/src/bd_search.cpp b/Contrib/ANN/src/bd_search.cpp
new file mode 100755
index 0000000..f057018
--- /dev/null
+++ b/Contrib/ANN/src/bd_search.cpp
@@ -0,0 +1,61 @@
+//----------------------------------------------------------------------
+// File:			bd_search.cpp
+// Programmer:		David Mount
+// Description:		Standard bd-tree search
+// Last modified:	01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//----------------------------------------------------------------------
+
+#include "bd_tree.h"					// bd-tree declarations
+#include "kd_search.h"					// kd-tree search declarations
+
+//----------------------------------------------------------------------
+//	Approximate searching for bd-trees.
+//		See the file kd_search.cpp for general information on the
+//		approximate nearest neighbor search algorithm.  Here we
+//		include the extensions for shrinking nodes.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+//	bd_shrink::ann_search - search a shrinking node
+//----------------------------------------------------------------------
+
+void ANNbd_shrink::ann_search(ANNdist box_dist)
+{
+												// check dist calc term cond.
+	if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return;
+
+	ANNdist inner_dist = 0;						// distance to inner box
+	for (int i = 0; i < n_bnds; i++) {			// is query point in the box?
+		if (bnds[i].out(ANNkdQ)) {				// outside this bounding side?
+												// add to inner distance
+			inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNkdQ));
+		}
+	}
+	if (inner_dist <= box_dist) {				// if inner box is closer
+		child[ANN_IN]->ann_search(inner_dist);	// search inner child first
+		child[ANN_OUT]->ann_search(box_dist);	// ...then outer child
+	}
+	else {										// if outer box is closer
+		child[ANN_OUT]->ann_search(box_dist);	// search outer child first
+		child[ANN_IN]->ann_search(inner_dist);	// ...then outer child
+	}
+	ANN_FLOP(3*n_bnds)							// increment floating ops
+	ANN_SHR(1)									// one more shrinking node
+}
diff --git a/Contrib/ANN/src/bd_tree.cpp b/Contrib/ANN/src/bd_tree.cpp
new file mode 100755
index 0000000..0977dea
--- /dev/null
+++ b/Contrib/ANN/src/bd_tree.cpp
@@ -0,0 +1,417 @@
+//----------------------------------------------------------------------
+// File:			bd_tree.cpp
+// Programmer:		David Mount
+// Description:		Basic methods for bd-trees.
+// Last modified:	01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//	Revision l.0  04/01/05
+//		Fixed centroid shrink threshold condition to depend on the
+//			dimension.
+//		Moved dump routine to kd_dump.cpp.
+//----------------------------------------------------------------------
+
+#include "bd_tree.h"					// bd-tree declarations
+#include "kd_util.h"					// kd-tree utilities
+#include "kd_split.h"					// kd-tree splitting rules
+
+#include <ANN/ANNperf.h>				// performance evaluation
+
+//----------------------------------------------------------------------
+//	Printing a bd-tree 
+//		These routines print a bd-tree.   See the analogous procedure
+//		in kd_tree.cpp for more information.
+//----------------------------------------------------------------------
+
+void ANNbd_shrink::print(				// print shrinking node
+		int level,						// depth of node in tree
+		ostream &out)					// output stream
+{
+	child[ANN_OUT]->print(level+1, out);		// print out-child
+
+	out << "    ";
+	for (int i = 0; i < level; i++)				// print indentation
+		out << "..";
+	out << "Shrink";
+	for (int j = 0; j < n_bnds; j++) {			// print sides, 2 per line
+		if (j % 2 == 0) {
+			out << "\n";						// newline and indentation
+			for (int i = 0; i < level+2; i++) out << "  ";
+		}
+		out << "  ([" << bnds[j].cd << "]"
+			 << (bnds[j].sd > 0 ? ">=" : "< ")
+			 << bnds[j].cv << ")";
+	}
+	out << "\n";
+
+	child[ANN_IN]->print(level+1, out);			// print in-child
+}
+
+//----------------------------------------------------------------------
+//	kd_tree statistics utility (for performance evaluation)
+//		This routine computes various statistics information for
+//		shrinking nodes.  See file kd_tree.cpp for more information.
+//----------------------------------------------------------------------
+
+void ANNbd_shrink::getStats(					// get subtree statistics
+	int					dim,					// dimension of space
+	ANNkdStats			&st,					// stats (modified)
+	ANNorthRect			&bnd_box)				// bounding box
+{
+	ANNkdStats ch_stats;						// stats for children
+	ANNorthRect inner_box(dim);					// inner box of shrink
+
+	annBnds2Box(bnd_box,						// enclosing box
+				dim,							// dimension
+				n_bnds,							// number of bounds
+				bnds,							// bounds array
+				inner_box);						// inner box (modified)
+												// get stats for inner child
+	ch_stats.reset();							// reset
+	child[ANN_IN]->getStats(dim, ch_stats, inner_box);
+	st.merge(ch_stats);							// merge them
+												// get stats for outer child
+	ch_stats.reset();							// reset
+	child[ANN_OUT]->getStats(dim, ch_stats, bnd_box);
+	st.merge(ch_stats);							// merge them
+
+	st.depth++;									// increment depth
+	st.n_shr++;									// increment number of shrinks
+}
+
+//----------------------------------------------------------------------
+// bd-tree constructor
+//		This is the main constructor for bd-trees given a set of points.
+//		It first builds a skeleton kd-tree as a basis, then computes the
+//		bounding box of the data points, and then invokes rbd_tree() to
+//		actually build the tree, passing it the appropriate splitting
+//		and shrinking information.
+//----------------------------------------------------------------------
+
+ANNkd_ptr rbd_tree(						// recursive construction of bd-tree
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices to store in subtree
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	int					bsp,			// bucket space
+	ANNorthRect			&bnd_box,		// bounding box for current node
+	ANNkd_splitter		splitter,		// splitting routine
+	ANNshrinkRule		shrink);		// shrinking rule
+
+ANNbd_tree::ANNbd_tree(					// construct from point array
+	ANNpointArray		pa,				// point array (with at least n pts)
+	int					n,				// number of points
+	int					dd,				// dimension
+	int					bs,				// bucket size
+	ANNsplitRule		split,			// splitting rule
+	ANNshrinkRule		shrink)			// shrinking rule
+	: ANNkd_tree(n, dd, bs)				// build skeleton base tree
+{
+	pts = pa;							// where the points are
+	if (n == 0) return;					// no points--no sweat
+
+	ANNorthRect bnd_box(dd);			// bounding box for points
+										// construct bounding rectangle
+	annEnclRect(pa, pidx, n, dd, bnd_box);
+										// copy to tree structure
+	bnd_box_lo = annCopyPt(dd, bnd_box.lo);
+	bnd_box_hi = annCopyPt(dd, bnd_box.hi);
+
+	switch (split) {					// build by rule
+	case ANN_KD_STD:					// standard kd-splitting rule
+		root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, kd_split, shrink);
+		break;
+	case ANN_KD_MIDPT:					// midpoint split
+		root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, midpt_split, shrink);
+		break;
+	case ANN_KD_SUGGEST:				// best (in our opinion)
+	case ANN_KD_SL_MIDPT:				// sliding midpoint split
+		root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, sl_midpt_split, shrink);
+		break;
+	case ANN_KD_FAIR:					// fair split
+		root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, fair_split, shrink);
+		break;
+	case ANN_KD_SL_FAIR:				// sliding fair split
+		root = rbd_tree(pa, pidx, n, dd, bs,
+						bnd_box, sl_fair_split, shrink);
+		break;
+	default:
+		annError("Illegal splitting method", ANNabort);
+	}
+}
+
+//----------------------------------------------------------------------
+//	Shrinking rules
+//----------------------------------------------------------------------
+
+enum ANNdecomp {SPLIT, SHRINK};			// decomposition methods
+
+//----------------------------------------------------------------------
+//	trySimpleShrink - Attempt a simple shrink
+//
+//		We compute the tight bounding box of the points, and compute
+//		the 2*dim ``gaps'' between the sides of the tight box and the
+//		bounding box.  If any of the gaps is large enough relative to
+//		the longest side of the tight bounding box, then we shrink
+//		all sides whose gaps are large enough.  (The reason for
+//		comparing against the tight bounding box, is that after
+//		shrinking the longest box size will decrease, and if we use
+//		the standard bounding box, we may decide to shrink twice in
+//		a row.  Since the tight box is fixed, we cannot shrink twice
+//		consecutively.)
+//----------------------------------------------------------------------
+const float BD_GAP_THRESH = 0.5;		// gap threshold (must be < 1)
+const int   BD_CT_THRESH  = 2;			// min number of shrink sides
+
+ANNdecomp trySimpleShrink(				// try a simple shrink
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices to store in subtree
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	const ANNorthRect	&bnd_box,		// current bounding box
+	ANNorthRect			&inner_box)		// inner box if shrinking (returned)
+{
+	int i;
+												// compute tight bounding box
+	annEnclRect(pa, pidx, n, dim, inner_box);
+
+	ANNcoord max_length = 0;					// find longest box side
+	for (i = 0; i < dim; i++) {
+		ANNcoord length = inner_box.hi[i] - inner_box.lo[i];
+		if (length > max_length) {
+			max_length = length;
+		}
+	}
+
+	int shrink_ct = 0;							// number of sides we shrunk
+	for (i = 0; i < dim; i++) {					// select which sides to shrink
+												// gap between boxes
+		ANNcoord gap_hi = bnd_box.hi[i] - inner_box.hi[i];
+												// big enough gap to shrink?
+		if (gap_hi < max_length*BD_GAP_THRESH)
+			inner_box.hi[i] = bnd_box.hi[i];	// no - expand
+		else shrink_ct++;						// yes - shrink this side
+
+												// repeat for high side
+		ANNcoord gap_lo = inner_box.lo[i] - bnd_box.lo[i];
+		if (gap_lo < max_length*BD_GAP_THRESH)
+			inner_box.lo[i] = bnd_box.lo[i];	// no - expand
+		else shrink_ct++;						// yes - shrink this side
+	}
+
+	if (shrink_ct >= BD_CT_THRESH)				// did we shrink enough sides?
+		 return SHRINK;
+	else return SPLIT;
+}
+
+//----------------------------------------------------------------------
+//	tryCentroidShrink - Attempt a centroid shrink
+//
+//	We repeatedly apply the splitting rule, always to the larger subset
+//	of points, until the number of points decreases by the constant
+//	fraction BD_FRACTION.  If this takes more than dim*BD_MAX_SPLIT_FAC
+//	splits for this to happen, then we shrink to the final inner box
+//	Otherwise we split.
+//----------------------------------------------------------------------
+
+const float	BD_MAX_SPLIT_FAC = 0.5;		// maximum number of splits allowed
+const float	BD_FRACTION = 0.5;			// ...to reduce points by this fraction
+										// ...This must be < 1.
+
+ANNdecomp tryCentroidShrink(			// try a centroid shrink
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices to store in subtree
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	const ANNorthRect	&bnd_box,		// current bounding box
+	ANNkd_splitter		splitter,		// splitting procedure
+	ANNorthRect			&inner_box)		// inner box if shrinking (returned)
+{
+	int n_sub = n;						// number of points in subset
+	int n_goal = (int) (n*BD_FRACTION); // number of point in goal
+	int n_splits = 0;					// number of splits needed
+										// initialize inner box to bounding box
+	annAssignRect(dim, inner_box, bnd_box);
+
+	while (n_sub > n_goal) {			// keep splitting until goal reached
+		int cd;							// cut dim from splitter (ignored)
+		ANNcoord cv;					// cut value from splitter (ignored)
+		int n_lo;						// number of points on low side
+										// invoke splitting procedure
+		(*splitter)(pa, pidx, inner_box, n_sub, dim, cd, cv, n_lo);
+		n_splits++;						// increment split count
+
+		if (n_lo >= n_sub/2) {			// most points on low side
+			inner_box.hi[cd] = cv;		// collapse high side
+			n_sub = n_lo;				// recurse on lower points
+		}
+		else {							// most points on high side
+			inner_box.lo[cd] = cv;		// collapse low side
+			pidx += n_lo;				// recurse on higher points
+			n_sub -= n_lo;
+		}
+	}
+    if (n_splits > dim*BD_MAX_SPLIT_FAC)// took too many splits
+		return SHRINK;					// shrink to final subset
+	else
+		return SPLIT;
+}
+
+//----------------------------------------------------------------------
+//	selectDecomp - select which decomposition to use
+//----------------------------------------------------------------------
+
+ANNdecomp selectDecomp(			// select decomposition method
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices to store in subtree
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	const ANNorthRect	&bnd_box,		// current bounding box
+	ANNkd_splitter		splitter,		// splitting procedure
+	ANNshrinkRule		shrink,			// shrinking rule
+	ANNorthRect			&inner_box)		// inner box if shrinking (returned)
+{
+	ANNdecomp decomp = SPLIT;			// decomposition
+
+	switch (shrink) {					// check shrinking rule
+	case ANN_BD_NONE:					// no shrinking allowed
+		decomp = SPLIT;
+		break;
+	case ANN_BD_SUGGEST:				// author's suggestion
+	case ANN_BD_SIMPLE:					// simple shrink
+		decomp = trySimpleShrink(
+				pa, pidx,				// points and indices
+				n, dim,					// number of points and dimension
+				bnd_box,				// current bounding box
+				inner_box);				// inner box if shrinking (returned)
+		break;
+	case ANN_BD_CENTROID:				// centroid shrink
+		decomp = tryCentroidShrink(
+				pa, pidx,				// points and indices
+				n, dim,					// number of points and dimension
+				bnd_box,				// current bounding box
+				splitter,				// splitting procedure
+				inner_box);				// inner box if shrinking (returned)
+		break;
+	default:
+		annError("Illegal shrinking rule", ANNabort);
+	}
+	return decomp;
+}
+
+//----------------------------------------------------------------------
+//	rbd_tree - recursive procedure to build a bd-tree
+//
+//		This is analogous to rkd_tree, but for bd-trees.  See the
+//		procedure rkd_tree() in kd_split.cpp for more information.
+//
+//		If the number of points falls below the bucket size, then a
+//		leaf node is created for the points.  Otherwise we invoke the
+//		procedure selectDecomp() which determines whether we are to
+//		split or shrink.  If splitting is chosen, then we essentially
+//		do exactly as rkd_tree() would, and invoke the specified
+//		splitting procedure to the points.  Otherwise, the selection
+//		procedure returns a bounding box, from which we extract the
+//		appropriate shrinking bounds, and create a shrinking node.
+//		Finally the points are subdivided, and the procedure is
+//		invoked recursively on the two subsets to form the children.
+//----------------------------------------------------------------------
+
+ANNkd_ptr rbd_tree(				// recursive construction of bd-tree
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices to store in subtree
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	int					bsp,			// bucket space
+	ANNorthRect			&bnd_box,		// bounding box for current node
+	ANNkd_splitter		splitter,		// splitting routine
+	ANNshrinkRule		shrink)			// shrinking rule
+{
+	ANNdecomp decomp;					// decomposition method
+
+	ANNorthRect inner_box(dim);			// inner box (if shrinking)
+
+	if (n <= bsp) {						// n small, make a leaf node
+		if (n == 0)						// empty leaf node
+			return KD_TRIVIAL;			// return (canonical) empty leaf
+		else							// construct the node and return
+			return new ANNkd_leaf(n, pidx); 
+	}
+	
+	decomp = selectDecomp(				// select decomposition method
+				pa, pidx,				// points and indices
+				n, dim,					// number of points and dimension
+				bnd_box,				// current bounding box
+				splitter, shrink,		// splitting/shrinking methods
+				inner_box);				// inner box if shrinking (returned)
+	
+	if (decomp == SPLIT) {				// split selected
+		int cd;							// cutting dimension
+		ANNcoord cv;					// cutting value
+		int n_lo;						// number on low side of cut
+										// invoke splitting procedure
+		(*splitter)(pa, pidx, bnd_box, n, dim, cd, cv, n_lo);
+
+		ANNcoord lv = bnd_box.lo[cd];	// save bounds for cutting dimension
+		ANNcoord hv = bnd_box.hi[cd];
+
+		bnd_box.hi[cd] = cv;			// modify bounds for left subtree
+		ANNkd_ptr lo = rbd_tree(		// build left subtree
+				pa, pidx, n_lo,			// ...from pidx[0..n_lo-1]
+				dim, bsp, bnd_box, splitter, shrink);
+		bnd_box.hi[cd] = hv;			// restore bounds
+
+		bnd_box.lo[cd] = cv;			// modify bounds for right subtree
+		ANNkd_ptr hi = rbd_tree(		// build right subtree
+				pa, pidx + n_lo, n-n_lo,// ...from pidx[n_lo..n-1]
+				dim, bsp, bnd_box, splitter, shrink);
+		bnd_box.lo[cd] = lv;			// restore bounds
+										// create the splitting node
+		return new ANNkd_split(cd, cv, lv, hv, lo, hi);
+	}
+	else {								// shrink selected
+		int n_in;						// number of points in box
+		int n_bnds;						// number of bounding sides
+
+		annBoxSplit(					// split points around inner box
+				pa,						// points to split
+				pidx,					// point indices
+				n,						// number of points
+				dim,					// dimension
+				inner_box,				// inner box
+				n_in);					// number of points inside (returned)
+
+		ANNkd_ptr in = rbd_tree(		// build inner subtree pidx[0..n_in-1]
+				pa, pidx, n_in, dim, bsp, inner_box, splitter, shrink);
+		ANNkd_ptr out = rbd_tree(		// build outer subtree pidx[n_in..n]
+				pa, pidx+n_in, n - n_in, dim, bsp, bnd_box, splitter, shrink);
+
+		ANNorthHSArray bnds = NULL;		// bounds (alloc in Box2Bnds and
+										// ...freed in bd_shrink destroyer)
+
+		annBox2Bnds(					// convert inner box to bounds
+				inner_box,				// inner box
+				bnd_box,				// enclosing box
+				dim,					// dimension
+				n_bnds,					// number of bounds (returned)
+				bnds);					// bounds array (modified)
+
+										// return shrinking node
+		return new ANNbd_shrink(n_bnds, bnds, in, out);
+	}
+} 
diff --git a/Contrib/ANN/src/bd_tree.h b/Contrib/ANN/src/bd_tree.h
new file mode 100755
index 0000000..408889a
--- /dev/null
+++ b/Contrib/ANN/src/bd_tree.h
@@ -0,0 +1,100 @@
+//----------------------------------------------------------------------
+// File:			bd_tree.h
+// Programmer:		David Mount
+// Description:		Declarations for standard bd-tree routines
+// Last modified:	01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//	Revision 1.0  04/01/05
+//		Changed IN, OUT to ANN_IN, ANN_OUT
+//----------------------------------------------------------------------
+
+#ifndef ANN_bd_tree_H
+#define ANN_bd_tree_H
+
+#include <ANN/ANNx.h>					// all ANN includes
+#include "kd_tree.h"					// kd-tree includes
+
+//----------------------------------------------------------------------
+//	bd-tree shrinking node.
+//		The main addition in the bd-tree is the shrinking node, which
+//		is declared here.
+//
+//		Shrinking nodes are defined by list of orthogonal halfspaces.
+//		These halfspaces define a (possibly unbounded) orthogonal
+//		rectangle.  There are two children, in and out.  Points that
+//		lie within this rectangle are stored in the in-child, and the
+//		other points are stored in the out-child.
+//
+//		We use a list of orthogonal halfspaces rather than an
+//		orthogonal rectangle object because typically the number of
+//		sides of the shrinking box will be much smaller than the
+//		worst case bound of 2*dim.
+//
+//		BEWARE: Note that constructor just copies the pointer to the
+//		bounding array, but the destructor deallocates it.  This is
+//		rather poor practice, but happens to be convenient.  The list
+//		is allocated in the bd-tree building procedure rbd_tree() just
+//		prior to construction, and is used for no other purposes.
+//
+//		WARNING: In the near neighbor searching code it is assumed that
+//		the list of bounding halfspaces is irredundant, meaning that there
+//		are no two distinct halfspaces in the list with the same outward
+//		pointing normals.
+//----------------------------------------------------------------------
+
+class ANNbd_shrink : public ANNkd_node	// splitting node of a kd-tree
+{
+	int					n_bnds;			// number of bounding halfspaces
+	ANNorthHSArray		bnds;			// list of bounding halfspaces
+	ANNkd_ptr			child[2];		// in and out children
+public:
+	ANNbd_shrink(						// constructor
+		int				nb,				// number of bounding halfspaces
+		ANNorthHSArray	bds,			// list of bounding halfspaces
+		ANNkd_ptr ic=NULL, ANNkd_ptr oc=NULL)	// children
+		{
+			n_bnds			= nb;				// cutting dimension
+			bnds			= bds;				// assign bounds
+			child[ANN_IN]	= ic;				// set children
+			child[ANN_OUT]	= oc;
+		}
+
+	~ANNbd_shrink()						// destructor
+		{
+			if (child[ANN_IN]!= NULL && child[ANN_IN]!=  KD_TRIVIAL) 
+				delete child[ANN_IN];
+			if (child[ANN_OUT]!= NULL&& child[ANN_OUT]!= KD_TRIVIAL) 
+				delete child[ANN_OUT];
+			if (bnds != NULL)
+				delete [] bnds;			// delete bounds
+		}
+
+	virtual void getStats(						// get tree statistics
+				int dim,						// dimension of space
+				ANNkdStats &st,					// statistics
+				ANNorthRect &bnd_box);			// bounding box
+	virtual void print(int level, ostream &out);// print node
+	virtual void dump(ostream &out);			// dump node
+
+	virtual void ann_search(ANNdist);			// standard search
+	virtual void ann_pri_search(ANNdist);		// priority search
+	virtual void ann_FR_search(ANNdist); 		// fixed-radius search
+};
+
+#endif
diff --git a/Contrib/ANN/src/brute.cpp b/Contrib/ANN/src/brute.cpp
new file mode 100755
index 0000000..d7cba2c
--- /dev/null
+++ b/Contrib/ANN/src/brute.cpp
@@ -0,0 +1,109 @@
+//----------------------------------------------------------------------
+// File:			brute.cpp
+// Programmer:		Sunil Arya and David Mount
+// Description:		Brute-force nearest neighbors
+// Last modified:	05/03/05 (Version 1.1)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//	Revision 1.1  05/03/05
+//		Added fixed-radius kNN search
+//----------------------------------------------------------------------
+
+#include <ANN/ANNx.h>					// all ANN includes
+#include "pr_queue_k.h"					// k element priority queue
+
+//----------------------------------------------------------------------
+//		Brute-force search simply stores a pointer to the list of
+//		data points and searches linearly for the nearest neighbor.
+//		The k nearest neighbors are stored in a k-element priority
+//		queue (which is implemented in a pretty dumb way as well).
+//
+//		If ANN_ALLOW_SELF_MATCH is ANNfalse then data points at distance
+//		zero are not considered.
+//
+//		Note that the error bound eps is passed in, but it is ignored.
+//		These routines compute exact nearest neighbors (which is needed
+//		for validation purposes in ann_test.cpp).
+//----------------------------------------------------------------------
+
+ANNbruteForce::ANNbruteForce(			// constructor from point array
+	ANNpointArray		pa,				// point array
+	int					n,				// number of points
+	int					dd)				// dimension
+{
+	dim = dd;  n_pts = n;  pts = pa;
+}
+
+ANNbruteForce::~ANNbruteForce() { }		// destructor (empty)
+
+void ANNbruteForce::annkSearch(			// approx k near neighbor search
+	ANNpoint			q,				// query point
+	int					k,				// number of near neighbors to return
+	ANNidxArray			nn_idx,			// nearest neighbor indices (returned)
+	ANNdistArray		dd,				// dist to near neighbors (returned)
+	double				eps)			// error bound (ignored)
+{
+	ANNmin_k mk(k);						// construct a k-limited priority queue
+	int i;
+
+	if (k > n_pts) {					// too many near neighbors?
+		annError("Requesting more near neighbors than data points", ANNabort);
+	}
+										// run every point through queue
+	for (i = 0; i < n_pts; i++) {
+										// compute distance to point
+		ANNdist sqDist = annDist(dim, pts[i], q);
+		if (ANN_ALLOW_SELF_MATCH || sqDist != 0)
+			mk.insert(sqDist, i);
+	}
+	for (i = 0; i < k; i++) {			// extract the k closest points
+		dd[i] = mk.ith_smallest_key(i);
+		nn_idx[i] = mk.ith_smallest_info(i);
+	}
+}
+
+int ANNbruteForce::annkFRSearch(		// approx fixed-radius kNN search
+	ANNpoint			q,				// query point
+	ANNdist				sqRad,			// squared radius
+	int					k,				// number of near neighbors to return
+	ANNidxArray			nn_idx,			// nearest neighbor array (returned)
+	ANNdistArray		dd,				// dist to near neighbors (returned)
+	double				eps)			// error bound
+{
+	ANNmin_k mk(k);						// construct a k-limited priority queue
+	int i;
+	int pts_in_range = 0;				// number of points in query range
+										// run every point through queue
+	for (i = 0; i < n_pts; i++) {
+										// compute distance to point
+		ANNdist sqDist = annDist(dim, pts[i], q);
+		if (sqDist <= sqRad &&			// within radius bound
+			(ANN_ALLOW_SELF_MATCH || sqDist != 0)) { // ...and no self match
+			mk.insert(sqDist, i);
+			pts_in_range++;
+		}
+	}
+	for (i = 0; i < k; i++) {			// extract the k closest points
+		if (dd != NULL)
+			dd[i] = mk.ith_smallest_key(i);
+		if (nn_idx != NULL)
+			nn_idx[i] = mk.ith_smallest_info(i);
+	}
+
+	return pts_in_range;
+}
diff --git a/Contrib/ANN/src/kd_dump.cpp b/Contrib/ANN/src/kd_dump.cpp
new file mode 100755
index 0000000..361e639
--- /dev/null
+++ b/Contrib/ANN/src/kd_dump.cpp
@@ -0,0 +1,446 @@
+//----------------------------------------------------------------------
+// File:			kd_dump.cc
+// Programmer:		David Mount
+// Description:		Dump and Load for kd- and bd-trees
+// Last modified:	01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//	Revision 1.0  04/01/05
+//		Moved dump out of kd_tree.cc into this file.
+//		Added kd-tree load constructor.
+//----------------------------------------------------------------------
+// This file contains routines for dumping kd-trees and bd-trees and
+// reloading them. (It is an abuse of policy to include both kd- and
+// bd-tree routines in the same file, sorry.  There should be no problem
+// in deleting the bd- versions of the routines if they are not
+// desired.)
+//----------------------------------------------------------------------
+
+#include "kd_tree.h"					// kd-tree declarations
+#include "bd_tree.h"					// bd-tree declarations
+#include <string.h> // for gmsh
+#include <stdlib.h> // for gmsh
+
+using namespace std;					// make std:: available
+
+//----------------------------------------------------------------------
+//		Constants
+//----------------------------------------------------------------------
+
+const int		STRING_LEN		= 500;	// maximum string length
+const double	EPSILON			= 1E-5; // small number for float comparison
+
+enum ANNtreeType {KD_TREE, BD_TREE};	// tree types (used in loading)
+
+//----------------------------------------------------------------------
+//		Procedure declarations
+//----------------------------------------------------------------------
+
+static ANNkd_ptr annReadDump(			// read dump file
+	istream				&in,					// input stream
+	ANNtreeType			tree_type,				// type of tree expected
+	ANNpointArray		&the_pts,				// new points (if applic)
+	ANNidxArray			&the_pidx,				// point indices (returned)
+	int					&the_dim,				// dimension (returned)
+	int					&the_n_pts,				// number of points (returned)
+	int					&the_bkt_size,			// bucket size (returned)
+	ANNpoint			&the_bnd_box_lo,		// low bounding point
+	ANNpoint			&the_bnd_box_hi);		// high bounding point
+
+static ANNkd_ptr annReadTree(			// read tree-part of dump file
+	istream				&in,					// input stream
+	ANNtreeType			tree_type,				// type of tree expected
+	ANNidxArray			the_pidx,				// point indices (modified)
+	int					&next_idx);				// next index (modified)
+
+//----------------------------------------------------------------------
+//	ANN kd- and bd-tree Dump Format
+//		The dump file begins with a header containing the version of
+//		ANN, an optional section containing the points, followed by
+//		a description of the tree.	The tree is printed in preorder.
+//
+//		Format:
+//		#ANN <version number> <comments> [END_OF_LINE]
+//		points <dim> <n_pts>			(point coordinates: this is optional)
+//		0 <xxx> <xxx> ... <xxx>			(point indices and coordinates)
+//		1 <xxx> <xxx> ... <xxx>
+//		  ...
+//		tree <dim> <n_pts> <bkt_size>
+//		<xxx> <xxx> ... <xxx>			(lower end of bounding box)
+//		<xxx> <xxx> ... <xxx>			(upper end of bounding box)
+//				If the tree is null, then a single line "null" is
+//				output.	 Otherwise the nodes of the tree are printed
+//				one per line in preorder.  Leaves and splitting nodes 
+//				have the following formats:
+//		Leaf node:
+//				leaf <n_pts> <bkt[0]> <bkt[1]> ... <bkt[n-1]>
+//		Splitting nodes:
+//				split <cut_dim> <cut_val> <lo_bound> <hi_bound>
+//
+//		For bd-trees:
+//
+//		Shrinking nodes:
+//				shrink <n_bnds>
+//						<cut_dim> <cut_val> <side>
+//						<cut_dim> <cut_val> <side>
+//						... (repeated n_bnds times)
+//----------------------------------------------------------------------
+
+void ANNkd_tree::Dump(					// dump entire tree
+		ANNbool with_pts,				// print points as well?
+		ostream &out)					// output stream
+{
+	out << "#ANN " << ANNversion << "\n";
+	out.precision(ANNcoordPrec);		// use full precision in dumping
+	if (with_pts) {						// print point coordinates
+		out << "points " << dim << " " << n_pts << "\n";
+		for (int i = 0; i < n_pts; i++) {
+			out << i << " ";
+			annPrintPt(pts[i], dim, out);
+			out << "\n";
+		}
+	}
+	out << "tree "						// print tree elements
+		<< dim << " "
+		<< n_pts << " "
+		<< bkt_size << "\n";
+
+	annPrintPt(bnd_box_lo, dim, out);	// print lower bound
+	out << "\n";
+	annPrintPt(bnd_box_hi, dim, out);	// print upper bound
+	out << "\n";
+
+	if (root == NULL)					// empty tree?
+		out << "null\n";
+	else {
+		root->dump(out);				// invoke printing at root
+	}
+	out.precision(0);					// restore default precision
+}
+
+void ANNkd_split::dump(					// dump a splitting node
+		ostream &out)					// output stream
+{
+	out << "split " << cut_dim << " " << cut_val << " ";
+	out << cd_bnds[ANN_LO] << " " << cd_bnds[ANN_HI] << "\n";
+
+	child[ANN_LO]->dump(out);			// print low child
+	child[ANN_HI]->dump(out);			// print high child
+}
+
+void ANNkd_leaf::dump(					// dump a leaf node
+		ostream &out)					// output stream
+{
+	if (this == KD_TRIVIAL) {			// canonical trivial leaf node
+		out << "leaf 0\n";				// leaf no points
+	}
+	else{
+		out << "leaf " << n_pts;
+		for (int j = 0; j < n_pts; j++) {
+			out << " " << bkt[j];
+		}
+		out << "\n";
+	}
+}
+
+void ANNbd_shrink::dump(				// dump a shrinking node
+		ostream &out)					// output stream
+{
+	out << "shrink " << n_bnds << "\n";
+	for (int j = 0; j < n_bnds; j++) {
+		out << bnds[j].cd << " " << bnds[j].cv << " " << bnds[j].sd << "\n";
+	}
+	child[ANN_IN]->dump(out);			// print in-child
+	child[ANN_OUT]->dump(out);			// print out-child
+}
+
+//----------------------------------------------------------------------
+// Load kd-tree from dump file
+//		This rebuilds a kd-tree which was dumped to a file.	 The dump
+//		file contains all the basic tree information according to a
+//		preorder traversal.	 We assume that the dump file also contains
+//		point data.	 (This is to guarantee the consistency of the tree.)
+//		If not, then an error is generated.
+//
+//		Indirectly, this procedure allocates space for points, point
+//		indices, all nodes in the tree, and the bounding box for the
+//		tree.  When the tree is destroyed, all but the points are
+//		deallocated.
+//
+//		This routine calls annReadDump to do all the work.
+//----------------------------------------------------------------------
+
+ANNkd_tree::ANNkd_tree(					// build from dump file
+	istream				&in)					// input stream for dump file
+{
+	int the_dim;								// local dimension
+	int the_n_pts;								// local number of points
+	int the_bkt_size;							// local number of points
+	ANNpoint the_bnd_box_lo;					// low bounding point
+	ANNpoint the_bnd_box_hi;					// high bounding point
+	ANNpointArray the_pts;						// point storage
+	ANNidxArray the_pidx;						// point index storage
+	ANNkd_ptr the_root;							// root of the tree
+
+	the_root = annReadDump(						// read the dump file
+		in,										// input stream
+		KD_TREE,								// expecting a kd-tree
+		the_pts,								// point array (returned)
+		the_pidx,								// point indices (returned)
+		the_dim, the_n_pts, the_bkt_size,		// basic tree info (returned)
+		the_bnd_box_lo, the_bnd_box_hi);		// bounding box info (returned)
+
+												// create a skeletal tree
+	SkeletonTree(the_n_pts, the_dim, the_bkt_size, the_pts, the_pidx);
+
+	bnd_box_lo = the_bnd_box_lo;
+	bnd_box_hi = the_bnd_box_hi;
+
+	root = the_root;							// set the root
+}
+
+ANNbd_tree::ANNbd_tree(					// build bd-tree from dump file
+	istream				&in) : ANNkd_tree()		// input stream for dump file
+{
+	int the_dim;								// local dimension
+	int the_n_pts;								// local number of points
+	int the_bkt_size;							// local number of points
+	ANNpoint the_bnd_box_lo;					// low bounding point
+	ANNpoint the_bnd_box_hi;					// high bounding point
+	ANNpointArray the_pts;						// point storage
+	ANNidxArray the_pidx;						// point index storage
+	ANNkd_ptr the_root;							// root of the tree
+
+	the_root = annReadDump(						// read the dump file
+		in,										// input stream
+		BD_TREE,								// expecting a bd-tree
+		the_pts,								// point array (returned)
+		the_pidx,								// point indices (returned)
+		the_dim, the_n_pts, the_bkt_size,		// basic tree info (returned)
+		the_bnd_box_lo, the_bnd_box_hi);		// bounding box info (returned)
+
+												// create a skeletal tree
+	SkeletonTree(the_n_pts, the_dim, the_bkt_size, the_pts, the_pidx);
+	bnd_box_lo = the_bnd_box_lo;
+	bnd_box_hi = the_bnd_box_hi;
+
+	root = the_root;							// set the root
+}
+
+//----------------------------------------------------------------------
+//	annReadDump - read a dump file
+//
+//		This procedure reads a dump file, constructs a kd-tree
+//		and returns all the essential information needed to actually
+//		construct the tree.	 Because this procedure is used for
+//		constructing both kd-trees and bd-trees, the second argument
+//		is used to indicate which type of tree we are expecting.
+//----------------------------------------------------------------------
+
+static ANNkd_ptr annReadDump(
+	istream				&in,					// input stream
+	ANNtreeType			tree_type,				// type of tree expected
+	ANNpointArray		&the_pts,				// new points (returned)
+	ANNidxArray			&the_pidx,				// point indices (returned)
+	int					&the_dim,				// dimension (returned)
+	int					&the_n_pts,				// number of points (returned)
+	int					&the_bkt_size,			// bucket size (returned)
+	ANNpoint			&the_bnd_box_lo,		// low bounding point (ret'd)
+	ANNpoint			&the_bnd_box_hi)		// high bounding point (ret'd)
+{
+	int j;
+	char str[STRING_LEN];						// storage for string
+	char version[STRING_LEN];					// ANN version number
+	ANNkd_ptr the_root = NULL;
+
+	//------------------------------------------------------------------
+	//	Input file header
+	//------------------------------------------------------------------
+	in >> str;									// input header
+	if (strcmp(str, "#ANN") != 0) {				// incorrect header
+		annError("Incorrect header for dump file", ANNabort);
+	}
+	in.getline(version, STRING_LEN);			// get version (ignore)
+
+	//------------------------------------------------------------------
+	//	Input the points
+	//			An array the_pts is allocated and points are read from
+	//			the dump file.
+	//------------------------------------------------------------------
+	in >> str;									// get major heading
+	if (strcmp(str, "points") == 0) {			// points section
+		in >> the_dim;							// input dimension
+		in >> the_n_pts;						// number of points
+												// allocate point storage
+		the_pts = annAllocPts(the_n_pts, the_dim);
+		for (int i = 0; i < the_n_pts; i++) {	// input point coordinates
+			ANNidx idx;							// point index
+			in >> idx;							// input point index
+			if (idx < 0 || idx >= the_n_pts) {
+				annError("Point index is out of range", ANNabort);
+			}
+			for (j = 0; j < the_dim; j++) {
+				in >> the_pts[idx][j];			// read point coordinates
+			}
+		}
+		in >> str;								// get next major heading
+	}
+	else {										// no points were input
+		annError("Points must be supplied in the dump file", ANNabort);
+	}
+
+	//------------------------------------------------------------------
+	//	Input the tree
+	//			After the basic header information, we invoke annReadTree
+	//			to do all the heavy work.  We create our own array of
+	//			point indices (so we can pass them to annReadTree())
+	//			but we do not deallocate them.	They will be deallocated
+	//			when the tree is destroyed.
+	//------------------------------------------------------------------
+	if (strcmp(str, "tree") == 0) {				// tree section
+		in >> the_dim;							// read dimension
+		in >> the_n_pts;						// number of points
+		in >> the_bkt_size;						// bucket size
+		the_bnd_box_lo = annAllocPt(the_dim);	// allocate bounding box pts
+		the_bnd_box_hi = annAllocPt(the_dim);
+
+		for (j = 0; j < the_dim; j++) {			// read bounding box low
+			in >> the_bnd_box_lo[j];
+		}
+		for (j = 0; j < the_dim; j++) {			// read bounding box low
+			in >> the_bnd_box_hi[j];
+		}
+		the_pidx = new ANNidx[the_n_pts];		// allocate point index array
+		int next_idx = 0;						// number of indices filled
+												// read the tree and indices
+		the_root = annReadTree(in, tree_type, the_pidx, next_idx);
+		if (next_idx != the_n_pts) {			// didn't see all the points?
+			annError("Didn't see as many points as expected", ANNwarn);
+		}
+	}
+	else {
+		annError("Illegal dump format.	Expecting section heading", ANNabort);
+	}
+	return the_root;
+}
+
+//----------------------------------------------------------------------
+// annReadTree - input tree and return pointer
+//
+//		annReadTree reads in a node of the tree, makes any recursive
+//		calls as needed to input the children of this node (if internal).
+//		It returns a pointer to the node that was created.	An array
+//		of point indices is given along with a pointer to the next
+//		available location in the array.  As leaves are read, their
+//		point indices are stored here, and the point buckets point
+//		to the first entry in the array.
+//
+//		Recall that these are the formats.	The tree is given in
+//		preorder.
+//
+//		Leaf node:
+//				leaf <n_pts> <bkt[0]> <bkt[1]> ... <bkt[n-1]>
+//		Splitting nodes:
+//				split <cut_dim> <cut_val> <lo_bound> <hi_bound>
+//
+//		For bd-trees:
+//
+//		Shrinking nodes:
+//				shrink <n_bnds>
+//						<cut_dim> <cut_val> <side>
+//						<cut_dim> <cut_val> <side>
+//						... (repeated n_bnds times)
+//----------------------------------------------------------------------
+
+static ANNkd_ptr annReadTree(
+	istream				&in,					// input stream
+	ANNtreeType			tree_type,				// type of tree expected
+	ANNidxArray			the_pidx,				// point indices (modified)
+	int					&next_idx)				// next index (modified)
+{
+	char tag[STRING_LEN];						// tag (leaf, split, shrink)
+	int n_pts;									// number of points in leaf
+	int cd;										// cut dimension
+	ANNcoord cv;								// cut value
+	ANNcoord lb;								// low bound
+	ANNcoord hb;								// high bound
+	int n_bnds;									// number of bounding sides
+	int sd;										// which side
+
+	in >> tag;									// input node tag
+
+	if (strcmp(tag, "null") == 0) {				// null tree
+		return NULL;
+	}
+	//------------------------------------------------------------------
+	//	Read a leaf
+	//------------------------------------------------------------------
+	if (strcmp(tag, "leaf") == 0) {				// leaf node
+
+		in >> n_pts;							// input number of points
+		int old_idx = next_idx;					// save next_idx
+		if (n_pts == 0) {						// trivial leaf
+			return KD_TRIVIAL;
+		}
+		else {
+			for (int i = 0; i < n_pts; i++) {	// input point indices
+				in >> the_pidx[next_idx++];		// store in array of indices
+			}
+		}
+		return new ANNkd_leaf(n_pts, &the_pidx[old_idx]);
+	}
+	//------------------------------------------------------------------
+	//	Read a splitting node
+	//------------------------------------------------------------------
+	else if (strcmp(tag, "split") == 0) {		// splitting node
+
+		in >> cd >> cv >> lb >> hb;
+
+												// read low and high subtrees
+		ANNkd_ptr lc = annReadTree(in, tree_type, the_pidx, next_idx);
+		ANNkd_ptr hc = annReadTree(in, tree_type, the_pidx, next_idx);
+												// create new node and return
+		return new ANNkd_split(cd, cv, lb, hb, lc, hc);
+	}
+	//------------------------------------------------------------------
+	//	Read a shrinking node (bd-tree only)
+	//------------------------------------------------------------------
+	else if (strcmp(tag, "shrink") == 0) {		// shrinking node
+		if (tree_type != BD_TREE) {
+			annError("Shrinking node not allowed in kd-tree", ANNabort);
+		}
+
+		in >> n_bnds;							// number of bounding sides
+												// allocate bounds array
+		ANNorthHSArray bds = new ANNorthHalfSpace[n_bnds];
+		for (int i = 0; i < n_bnds; i++) {
+			in >> cd >> cv >> sd;				// input bounding halfspace
+												// copy to array
+			bds[i] = ANNorthHalfSpace(cd, cv, sd);
+		}
+												// read inner and outer subtrees
+		ANNkd_ptr ic = annReadTree(in, tree_type, the_pidx, next_idx);
+		ANNkd_ptr oc = annReadTree(in, tree_type, the_pidx, next_idx);
+												// create new node and return
+		return new ANNbd_shrink(n_bnds, bds, ic, oc);
+	}
+	else {
+		annError("Illegal node type in dump file", ANNabort);
+		exit(0);								// to keep the compiler happy
+	}
+}
diff --git a/Contrib/ANN/src/kd_fix_rad_search.cpp b/Contrib/ANN/src/kd_fix_rad_search.cpp
new file mode 100755
index 0000000..87eb757
--- /dev/null
+++ b/Contrib/ANN/src/kd_fix_rad_search.cpp
@@ -0,0 +1,183 @@
+//----------------------------------------------------------------------
+// File:			kd_fix_rad_search.cpp
+// Programmer:		Sunil Arya and David Mount
+// Description:		Standard kd-tree fixed-radius kNN search
+// Last modified:	05/03/05 (Version 1.1)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 1.1  05/03/05
+//		Initial release
+//----------------------------------------------------------------------
+
+#include "kd_fix_rad_search.h"			// kd fixed-radius search decls
+
+//----------------------------------------------------------------------
+//	Approximate fixed-radius k nearest neighbor search
+//		The squared radius is provided, and this procedure finds the
+//		k nearest neighbors within the radius, and returns the total
+//		number of points lying within the radius.
+//
+//		The method used for searching the kd-tree is a variation of the
+//		nearest neighbor search used in kd_search.cpp, except that the
+//		radius of the search ball is known.  We refer the reader to that
+//		file for the explanation of the recursive search procedure.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+//		To keep argument lists short, a number of global variables
+//		are maintained which are common to all the recursive calls.
+//		These are given below.
+//----------------------------------------------------------------------
+
+int				ANNkdFRDim;				// dimension of space
+ANNpoint		ANNkdFRQ;				// query point
+ANNdist			ANNkdFRSqRad;			// squared radius search bound
+double			ANNkdFRMaxErr;			// max tolerable squared error
+ANNpointArray	ANNkdFRPts;				// the points
+ANNmin_k*		ANNkdFRPointMK;			// set of k closest points
+int				ANNkdFRPtsVisited;		// total points visited
+int				ANNkdFRPtsInRange;		// number of points in the range
+
+//----------------------------------------------------------------------
+//	annkFRSearch - fixed radius search for k nearest neighbors
+//----------------------------------------------------------------------
+
+int ANNkd_tree::annkFRSearch(
+	ANNpoint			q,				// the query point
+	ANNdist				sqRad,			// squared radius search bound
+	int					k,				// number of near neighbors to return
+	ANNidxArray			nn_idx,			// nearest neighbor indices (returned)
+	ANNdistArray		dd,				// the approximate nearest neighbor
+	double				eps)			// the error bound
+{
+	ANNkdFRDim = dim;					// copy arguments to static equivs
+	ANNkdFRQ = q;
+	ANNkdFRSqRad = sqRad;
+	ANNkdFRPts = pts;
+	ANNkdFRPtsVisited = 0;				// initialize count of points visited
+	ANNkdFRPtsInRange = 0;				// ...and points in the range
+
+	ANNkdFRMaxErr = ANN_POW(1.0 + eps);
+	ANN_FLOP(2)							// increment floating op count
+
+	ANNkdFRPointMK = new ANNmin_k(k);	// create set for closest k points
+										// search starting at the root
+	root->ann_FR_search(annBoxDistance(q, bnd_box_lo, bnd_box_hi, dim));
+
+	for (int i = 0; i < k; i++) {		// extract the k-th closest points
+		if (dd != NULL)
+			dd[i] = ANNkdFRPointMK->ith_smallest_key(i);
+		if (nn_idx != NULL)
+			nn_idx[i] = ANNkdFRPointMK->ith_smallest_info(i);
+	}
+
+	delete ANNkdFRPointMK;				// deallocate closest point set
+	return ANNkdFRPtsInRange;			// return final point count
+}
+
+//----------------------------------------------------------------------
+//	kd_split::ann_FR_search - search a splitting node
+//		Note: This routine is similar in structure to the standard kNN
+//		search.  It visits the subtree that is closer to the query point
+//		first.  For fixed-radius search, there is no benefit in visiting
+//		one subtree before the other, but we maintain the same basic
+//		code structure for the sake of uniformity.
+//----------------------------------------------------------------------
+
+void ANNkd_split::ann_FR_search(ANNdist box_dist)
+{
+										// check dist calc term condition
+	if (ANNmaxPtsVisited != 0 && ANNkdFRPtsVisited > ANNmaxPtsVisited) return;
+
+										// distance to cutting plane
+	ANNcoord cut_diff = ANNkdFRQ[cut_dim] - cut_val;
+
+	if (cut_diff < 0) {					// left of cutting plane
+		child[ANN_LO]->ann_FR_search(box_dist);// visit closer child first
+
+		ANNcoord box_diff = cd_bnds[ANN_LO] - ANNkdFRQ[cut_dim];
+		if (box_diff < 0)				// within bounds - ignore
+			box_diff = 0;
+										// distance to further box
+		box_dist = (ANNdist) ANN_SUM(box_dist,
+				ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
+
+										// visit further child if in range
+		if (box_dist * ANNkdFRMaxErr <= ANNkdFRSqRad)
+			child[ANN_HI]->ann_FR_search(box_dist);
+
+	}
+	else {								// right of cutting plane
+		child[ANN_HI]->ann_FR_search(box_dist);// visit closer child first
+
+		ANNcoord box_diff = ANNkdFRQ[cut_dim] - cd_bnds[ANN_HI];
+		if (box_diff < 0)				// within bounds - ignore
+			box_diff = 0;
+										// distance to further box
+		box_dist = (ANNdist) ANN_SUM(box_dist,
+				ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
+
+										// visit further child if close enough
+		if (box_dist * ANNkdFRMaxErr <= ANNkdFRSqRad)
+			child[ANN_LO]->ann_FR_search(box_dist);
+
+	}
+	ANN_FLOP(13)						// increment floating ops
+	ANN_SPL(1)							// one more splitting node visited
+}
+
+//----------------------------------------------------------------------
+//	kd_leaf::ann_FR_search - search points in a leaf node
+//		Note: The unreadability of this code is the result of
+//		some fine tuning to replace indexing by pointer operations.
+//----------------------------------------------------------------------
+
+void ANNkd_leaf::ann_FR_search(ANNdist box_dist)
+{
+	register ANNdist dist;				// distance to data point
+	register ANNcoord* pp;				// data coordinate pointer
+	register ANNcoord* qq;				// query coordinate pointer
+	register ANNcoord t;
+	register int d;
+
+	for (int i = 0; i < n_pts; i++) {	// check points in bucket
+
+		pp = ANNkdFRPts[bkt[i]];		// first coord of next data point
+		qq = ANNkdFRQ;					// first coord of query point
+		dist = 0;
+
+		for(d = 0; d < ANNkdFRDim; d++) {
+			ANN_COORD(1)				// one more coordinate hit
+			ANN_FLOP(5)					// increment floating ops
+
+			t = *(qq++) - *(pp++);		// compute length and adv coordinate
+										// exceeds dist to k-th smallest?
+			if( (dist = ANN_SUM(dist, ANN_POW(t))) > ANNkdFRSqRad) {
+				break;
+			}
+		}
+
+		if (d >= ANNkdFRDim &&					// among the k best?
+		   (ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem
+												// add it to the list
+			ANNkdFRPointMK->insert(dist, bkt[i]);
+			ANNkdFRPtsInRange++;				// increment point count
+		}
+	}
+	ANN_LEAF(1)							// one more leaf node visited
+	ANN_PTS(n_pts)						// increment points visited
+	ANNkdFRPtsVisited += n_pts;			// increment number of points visited
+}
diff --git a/Contrib/ANN/src/kd_fix_rad_search.h b/Contrib/ANN/src/kd_fix_rad_search.h
new file mode 100755
index 0000000..7bae230
--- /dev/null
+++ b/Contrib/ANN/src/kd_fix_rad_search.h
@@ -0,0 +1,44 @@
+//----------------------------------------------------------------------
+// File:			kd_fix_rad_search.h
+// Programmer:		Sunil Arya and David Mount
+// Description:		Standard kd-tree fixed-radius kNN search
+// Last modified:	??/??/?? (Version 1.1)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 1.1  ??/??/??
+//		Initial release
+//----------------------------------------------------------------------
+
+#ifndef ANN_kd_fix_rad_search_H
+#define ANN_kd_fix_rad_search_H
+
+#include "kd_tree.h"					// kd-tree declarations
+#include "kd_util.h"					// kd-tree utilities
+#include "pr_queue_k.h"					// k-element priority queue
+
+#include <ANN/ANNperf.h>				// performance evaluation
+
+//----------------------------------------------------------------------
+//	Global variables
+//		These are active for the life of each call to
+//		annRangeSearch().  They are set to save the number of
+//		variables that need to be passed among the various search
+//		procedures.
+//----------------------------------------------------------------------
+
+extern ANNpoint			ANNkdFRQ;			// query point (static copy)
+
+#endif
diff --git a/Contrib/ANN/src/kd_pr_search.cpp b/Contrib/ANN/src/kd_pr_search.cpp
new file mode 100755
index 0000000..edb0479
--- /dev/null
+++ b/Contrib/ANN/src/kd_pr_search.cpp
@@ -0,0 +1,219 @@
+//----------------------------------------------------------------------
+// File:			kd_pr_search.cpp
+// Programmer:		Sunil Arya and David Mount
+// Description:		Priority search for kd-trees
+// Last modified:	01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//----------------------------------------------------------------------
+
+#include "kd_pr_search.h"				// kd priority search declarations
+
+//----------------------------------------------------------------------
+//	Approximate nearest neighbor searching by priority search.
+//		The kd-tree is searched for an approximate nearest neighbor.
+//		The point is returned through one of the arguments, and the
+//		distance returned is the SQUARED distance to this point.
+//
+//		The method used for searching the kd-tree is called priority
+//		search.  (It is described in Arya and Mount, ``Algorithms for
+//		fast vector quantization,'' Proc. of DCC '93: Data Compression
+//		Conference}, eds. J. A. Storer and M. Cohn, IEEE Press, 1993,
+//		381--390.)
+//
+//		The cell of the kd-tree containing the query point is located,
+//		and cells are visited in increasing order of distance from the
+//		query point.  This is done by placing each subtree which has
+//		NOT been visited in a priority queue, according to the closest
+//		distance of the corresponding enclosing rectangle from the
+//		query point.  The search stops when the distance to the nearest
+//		remaining rectangle exceeds the distance to the nearest point
+//		seen by a factor of more than 1/(1+eps). (Implying that any
+//		point found subsequently in the search cannot be closer by more
+//		than this factor.)
+//
+//		The main entry point is annkPriSearch() which sets things up and
+//		then call the recursive routine ann_pri_search().  This is a
+//		recursive routine which performs the processing for one node in
+//		the kd-tree.  There are two versions of this virtual procedure,
+//		one for splitting nodes and one for leaves. When a splitting node
+//		is visited, we determine which child to continue the search on
+//		(the closer one), and insert the other child into the priority
+//		queue.  When a leaf is visited, we compute the distances to the
+//		points in the buckets, and update information on the closest
+//		points.
+//
+//		Some trickery is used to incrementally update the distance from
+//		a kd-tree rectangle to the query point.  This comes about from
+//		the fact that which each successive split, only one component
+//		(along the dimension that is split) of the squared distance to
+//		the child rectangle is different from the squared distance to
+//		the parent rectangle.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+//		To keep argument lists short, a number of global variables
+//		are maintained which are common to all the recursive calls.
+//		These are given below.
+//----------------------------------------------------------------------
+
+double			ANNprEps;				// the error bound
+int				ANNprDim;				// dimension of space
+ANNpoint		ANNprQ;					// query point
+double			ANNprMaxErr;			// max tolerable squared error
+ANNpointArray	ANNprPts;				// the points
+ANNpr_queue		*ANNprBoxPQ;			// priority queue for boxes
+ANNmin_k		*ANNprPointMK;			// set of k closest points
+
+//----------------------------------------------------------------------
+//	annkPriSearch - priority search for k nearest neighbors
+//----------------------------------------------------------------------
+
+void ANNkd_tree::annkPriSearch(
+	ANNpoint			q,				// query point
+	int					k,				// number of near neighbors to return
+	ANNidxArray			nn_idx,			// nearest neighbor indices (returned)
+	ANNdistArray		dd,				// dist to near neighbors (returned)
+	double				eps)			// error bound (ignored)
+{
+										// max tolerable squared error
+	ANNprMaxErr = ANN_POW(1.0 + eps);
+	ANN_FLOP(2)							// increment floating ops
+
+	ANNprDim = dim;						// copy arguments to static equivs
+	ANNprQ = q;
+	ANNprPts = pts;
+	ANNptsVisited = 0;					// initialize count of points visited
+
+	ANNprPointMK = new ANNmin_k(k);		// create set for closest k points
+
+										// distance to root box
+	ANNdist box_dist = annBoxDistance(q,
+				bnd_box_lo, bnd_box_hi, dim);
+
+	ANNprBoxPQ = new ANNpr_queue(n_pts);// create priority queue for boxes
+	ANNprBoxPQ->insert(box_dist, root); // insert root in priority queue
+
+	while (ANNprBoxPQ->non_empty() &&
+		(!(ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited))) {
+		ANNkd_ptr np;					// next box from prior queue
+
+										// extract closest box from queue
+		ANNprBoxPQ->extr_min(box_dist, (void *&) np);
+
+		ANN_FLOP(2)						// increment floating ops
+		if (box_dist*ANNprMaxErr >= ANNprPointMK->max_key())
+			break;
+
+		np->ann_pri_search(box_dist);	// search this subtree.
+	}
+
+	for (int i = 0; i < k; i++) {		// extract the k-th closest points
+		dd[i] = ANNprPointMK->ith_smallest_key(i);
+		nn_idx[i] = ANNprPointMK->ith_smallest_info(i);
+	}
+
+	delete ANNprPointMK;				// deallocate closest point set
+	delete ANNprBoxPQ;					// deallocate priority queue
+}
+
+//----------------------------------------------------------------------
+//	kd_split::ann_pri_search - search a splitting node
+//----------------------------------------------------------------------
+
+void ANNkd_split::ann_pri_search(ANNdist box_dist)
+{
+	ANNdist new_dist;					// distance to child visited later
+										// distance to cutting plane
+	ANNcoord cut_diff = ANNprQ[cut_dim] - cut_val;
+
+	if (cut_diff < 0) {					// left of cutting plane
+		ANNcoord box_diff = cd_bnds[ANN_LO] - ANNprQ[cut_dim];
+		if (box_diff < 0)				// within bounds - ignore
+			box_diff = 0;
+										// distance to further box
+		new_dist = (ANNdist) ANN_SUM(box_dist,
+				ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
+
+		if (child[ANN_HI] != KD_TRIVIAL)// enqueue if not trivial
+			ANNprBoxPQ->insert(new_dist, child[ANN_HI]);
+										// continue with closer child
+		child[ANN_LO]->ann_pri_search(box_dist);
+	}
+	else {								// right of cutting plane
+		ANNcoord box_diff = ANNprQ[cut_dim] - cd_bnds[ANN_HI];
+		if (box_diff < 0)				// within bounds - ignore
+			box_diff = 0;
+										// distance to further box
+		new_dist = (ANNdist) ANN_SUM(box_dist,
+				ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
+
+		if (child[ANN_LO] != KD_TRIVIAL)// enqueue if not trivial
+			ANNprBoxPQ->insert(new_dist, child[ANN_LO]);
+										// continue with closer child
+		child[ANN_HI]->ann_pri_search(box_dist);
+	}
+	ANN_SPL(1)							// one more splitting node visited
+	ANN_FLOP(8)							// increment floating ops
+}
+
+//----------------------------------------------------------------------
+//	kd_leaf::ann_pri_search - search points in a leaf node
+//
+//		This is virtually identical to the ann_search for standard search.
+//----------------------------------------------------------------------
+
+void ANNkd_leaf::ann_pri_search(ANNdist box_dist)
+{
+	register ANNdist dist;				// distance to data point
+	register ANNcoord* pp;				// data coordinate pointer
+	register ANNcoord* qq;				// query coordinate pointer
+	register ANNdist min_dist;			// distance to k-th closest point
+	register ANNcoord t;
+	register int d;
+
+	min_dist = ANNprPointMK->max_key(); // k-th smallest distance so far
+
+	for (int i = 0; i < n_pts; i++) {	// check points in bucket
+
+		pp = ANNprPts[bkt[i]];			// first coord of next data point
+		qq = ANNprQ;					// first coord of query point
+		dist = 0;
+
+		for(d = 0; d < ANNprDim; d++) {
+			ANN_COORD(1)				// one more coordinate hit
+			ANN_FLOP(4)					// increment floating ops
+
+			t = *(qq++) - *(pp++);		// compute length and adv coordinate
+										// exceeds dist to k-th smallest?
+			if( (dist = ANN_SUM(dist, ANN_POW(t))) > min_dist) {
+				break;
+			}
+		}
+
+		if (d >= ANNprDim &&					// among the k best?
+		   (ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem
+												// add it to the list
+			ANNprPointMK->insert(dist, bkt[i]);
+			min_dist = ANNprPointMK->max_key();
+		}
+	}
+	ANN_LEAF(1)							// one more leaf node visited
+	ANN_PTS(n_pts)						// increment points visited
+	ANNptsVisited += n_pts;				// increment number of points visited
+}
diff --git a/Contrib/ANN/src/kd_pr_search.h b/Contrib/ANN/src/kd_pr_search.h
new file mode 100755
index 0000000..39e0484
--- /dev/null
+++ b/Contrib/ANN/src/kd_pr_search.h
@@ -0,0 +1,49 @@
+//----------------------------------------------------------------------
+// File:			kd_pr_search.h
+// Programmer:		Sunil Arya and David Mount
+// Description:		Priority kd-tree search
+// Last modified:	01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//----------------------------------------------------------------------
+
+#ifndef ANN_kd_pr_search_H
+#define ANN_kd_pr_search_H
+
+#include "kd_tree.h"					// kd-tree declarations
+#include "kd_util.h"					// kd-tree utilities
+#include "pr_queue.h"					// priority queue declarations
+#include "pr_queue_k.h"					// k-element priority queue
+
+#include <ANN/ANNperf.h>				// performance evaluation
+
+//----------------------------------------------------------------------
+//	Global variables
+//		Active for the life of each call to Appx_Near_Neigh() or
+//		Appx_k_Near_Neigh().
+//----------------------------------------------------------------------
+
+extern double			ANNprEps;		// the error bound
+extern int				ANNprDim;		// dimension of space
+extern ANNpoint			ANNprQ;			// query point
+extern double			ANNprMaxErr;	// max tolerable squared error
+extern ANNpointArray	ANNprPts;		// the points
+extern ANNpr_queue		*ANNprBoxPQ;	// priority queue for boxes
+extern ANNmin_k			*ANNprPointMK;	// set of k closest points
+
+#endif
diff --git a/Contrib/ANN/src/kd_search.cpp b/Contrib/ANN/src/kd_search.cpp
new file mode 100755
index 0000000..5004ef7
--- /dev/null
+++ b/Contrib/ANN/src/kd_search.cpp
@@ -0,0 +1,210 @@
+//----------------------------------------------------------------------
+// File:			kd_search.cpp
+// Programmer:		Sunil Arya and David Mount
+// Description:		Standard kd-tree search
+// Last modified:	01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//	Revision 1.0  04/01/05
+//		Changed names LO, HI to ANN_LO, ANN_HI
+//----------------------------------------------------------------------
+
+#include "kd_search.h"					// kd-search declarations
+
+//----------------------------------------------------------------------
+//	Approximate nearest neighbor searching by kd-tree search
+//		The kd-tree is searched for an approximate nearest neighbor.
+//		The point is returned through one of the arguments, and the
+//		distance returned is the squared distance to this point.
+//
+//		The method used for searching the kd-tree is an approximate
+//		adaptation of the search algorithm described by Friedman,
+//		Bentley, and Finkel, ``An algorithm for finding best matches
+//		in logarithmic expected time,'' ACM Transactions on Mathematical
+//		Software, 3(3):209-226, 1977).
+//
+//		The algorithm operates recursively.  When first encountering a
+//		node of the kd-tree we first visit the child which is closest to
+//		the query point.  On return, we decide whether we want to visit
+//		the other child.  If the box containing the other child exceeds
+//		1/(1+eps) times the current best distance, then we skip it (since
+//		any point found in this child cannot be closer to the query point
+//		by more than this factor.)  Otherwise, we visit it recursively.
+//		The distance between a box and the query point is computed exactly
+//		(not approximated as is often done in kd-tree), using incremental
+//		distance updates, as described by Arya and Mount in ``Algorithms
+//		for fast vector quantization,'' Proc.  of DCC '93: Data Compression
+//		Conference, eds. J. A. Storer and M. Cohn, IEEE Press, 1993,
+//		381-390.
+//
+//		The main entry points is annkSearch() which sets things up and
+//		then call the recursive routine ann_search().  This is a recursive
+//		routine which performs the processing for one node in the kd-tree.
+//		There are two versions of this virtual procedure, one for splitting
+//		nodes and one for leaves.  When a splitting node is visited, we
+//		determine which child to visit first (the closer one), and visit
+//		the other child on return.  When a leaf is visited, we compute
+//		the distances to the points in the buckets, and update information
+//		on the closest points.
+//
+//		Some trickery is used to incrementally update the distance from
+//		a kd-tree rectangle to the query point.  This comes about from
+//		the fact that which each successive split, only one component
+//		(along the dimension that is split) of the squared distance to
+//		the child rectangle is different from the squared distance to
+//		the parent rectangle.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+//		To keep argument lists short, a number of global variables
+//		are maintained which are common to all the recursive calls.
+//		These are given below.
+//----------------------------------------------------------------------
+
+int				ANNkdDim;				// dimension of space
+ANNpoint		ANNkdQ;					// query point
+double			ANNkdMaxErr;			// max tolerable squared error
+ANNpointArray	ANNkdPts;				// the points
+ANNmin_k		*ANNkdPointMK;			// set of k closest points
+
+//----------------------------------------------------------------------
+//	annkSearch - search for the k nearest neighbors
+//----------------------------------------------------------------------
+
+void ANNkd_tree::annkSearch(
+	ANNpoint			q,				// the query point
+	int					k,				// number of near neighbors to return
+	ANNidxArray			nn_idx,			// nearest neighbor indices (returned)
+	ANNdistArray		dd,				// the approximate nearest neighbor
+	double				eps)			// the error bound
+{
+
+	ANNkdDim = dim;						// copy arguments to static equivs
+	ANNkdQ = q;
+	ANNkdPts = pts;
+	ANNptsVisited = 0;					// initialize count of points visited
+
+	if (k > n_pts) {					// too many near neighbors?
+		annError("Requesting more near neighbors than data points", ANNabort);
+	}
+
+	ANNkdMaxErr = ANN_POW(1.0 + eps);
+	ANN_FLOP(2)							// increment floating op count
+
+	ANNkdPointMK = new ANNmin_k(k);		// create set for closest k points
+										// search starting at the root
+	root->ann_search(annBoxDistance(q, bnd_box_lo, bnd_box_hi, dim));
+
+	for (int i = 0; i < k; i++) {		// extract the k-th closest points
+		dd[i] = ANNkdPointMK->ith_smallest_key(i);
+		nn_idx[i] = ANNkdPointMK->ith_smallest_info(i);
+	}
+	delete ANNkdPointMK;				// deallocate closest point set
+}
+
+//----------------------------------------------------------------------
+//	kd_split::ann_search - search a splitting node
+//----------------------------------------------------------------------
+
+void ANNkd_split::ann_search(ANNdist box_dist)
+{
+										// check dist calc term condition
+	if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return;
+
+										// distance to cutting plane
+	ANNcoord cut_diff = ANNkdQ[cut_dim] - cut_val;
+
+	if (cut_diff < 0) {					// left of cutting plane
+		child[ANN_LO]->ann_search(box_dist);// visit closer child first
+
+		ANNcoord box_diff = cd_bnds[ANN_LO] - ANNkdQ[cut_dim];
+		if (box_diff < 0)				// within bounds - ignore
+			box_diff = 0;
+										// distance to further box
+		box_dist = (ANNdist) ANN_SUM(box_dist,
+				ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
+
+										// visit further child if close enough
+		if (box_dist * ANNkdMaxErr < ANNkdPointMK->max_key())
+			child[ANN_HI]->ann_search(box_dist);
+
+	}
+	else {								// right of cutting plane
+		child[ANN_HI]->ann_search(box_dist);// visit closer child first
+
+		ANNcoord box_diff = ANNkdQ[cut_dim] - cd_bnds[ANN_HI];
+		if (box_diff < 0)				// within bounds - ignore
+			box_diff = 0;
+										// distance to further box
+		box_dist = (ANNdist) ANN_SUM(box_dist,
+				ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
+
+										// visit further child if close enough
+		if (box_dist * ANNkdMaxErr < ANNkdPointMK->max_key())
+			child[ANN_LO]->ann_search(box_dist);
+
+	}
+	ANN_FLOP(10)						// increment floating ops
+	ANN_SPL(1)							// one more splitting node visited
+}
+
+//----------------------------------------------------------------------
+//	kd_leaf::ann_search - search points in a leaf node
+//		Note: The unreadability of this code is the result of
+//		some fine tuning to replace indexing by pointer operations.
+//----------------------------------------------------------------------
+
+void ANNkd_leaf::ann_search(ANNdist box_dist)
+{
+	register ANNdist dist;				// distance to data point
+	register ANNcoord* pp;				// data coordinate pointer
+	register ANNcoord* qq;				// query coordinate pointer
+	register ANNdist min_dist;			// distance to k-th closest point
+	register ANNcoord t;
+	register int d;
+
+	min_dist = ANNkdPointMK->max_key(); // k-th smallest distance so far
+
+	for (int i = 0; i < n_pts; i++) {	// check points in bucket
+
+		pp = ANNkdPts[bkt[i]];			// first coord of next data point
+		qq = ANNkdQ;					// first coord of query point
+		dist = 0;
+
+		for(d = 0; d < ANNkdDim; d++) {
+			ANN_COORD(1)				// one more coordinate hit
+			ANN_FLOP(4)					// increment floating ops
+
+			t = *(qq++) - *(pp++);		// compute length and adv coordinate
+										// exceeds dist to k-th smallest?
+			if( (dist = ANN_SUM(dist, ANN_POW(t))) > min_dist) {
+				break;
+			}
+		}
+
+		if (d >= ANNkdDim &&					// among the k best?
+		   (ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem
+												// add it to the list
+			ANNkdPointMK->insert(dist, bkt[i]);
+			min_dist = ANNkdPointMK->max_key();
+		}
+	}
+	ANN_LEAF(1)							// one more leaf node visited
+	ANN_PTS(n_pts)						// increment points visited
+	ANNptsVisited += n_pts;				// increment number of points visited
+}
diff --git a/Contrib/ANN/src/kd_search.h b/Contrib/ANN/src/kd_search.h
new file mode 100755
index 0000000..1adcdd4
--- /dev/null
+++ b/Contrib/ANN/src/kd_search.h
@@ -0,0 +1,48 @@
+//----------------------------------------------------------------------
+// File:			kd_search.h
+// Programmer:		Sunil Arya and David Mount
+// Description:		Standard kd-tree search
+// Last modified:	01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//----------------------------------------------------------------------
+
+#ifndef ANN_kd_search_H
+#define ANN_kd_search_H
+
+#include "kd_tree.h"					// kd-tree declarations
+#include "kd_util.h"					// kd-tree utilities
+#include "pr_queue_k.h"					// k-element priority queue
+
+#include <ANN/ANNperf.h>				// performance evaluation
+
+//----------------------------------------------------------------------
+//	More global variables
+//		These are active for the life of each call to annkSearch(). They
+//		are set to save the number of variables that need to be passed
+//		among the various search procedures.
+//----------------------------------------------------------------------
+
+extern int				ANNkdDim;		// dimension of space (static copy)
+extern ANNpoint			ANNkdQ;			// query point (static copy)
+extern double			ANNkdMaxErr;	// max tolerable squared error
+extern ANNpointArray	ANNkdPts;		// the points (static copy)
+extern ANNmin_k			*ANNkdPointMK;	// set of k closest points
+extern int				ANNptsVisited;	// number of points visited
+
+#endif
diff --git a/Contrib/ANN/src/kd_split.cpp b/Contrib/ANN/src/kd_split.cpp
new file mode 100755
index 0000000..8d5b3d8
--- /dev/null
+++ b/Contrib/ANN/src/kd_split.cpp
@@ -0,0 +1,428 @@
+//----------------------------------------------------------------------
+// File:			kd_split.cpp
+// Programmer:		Sunil Arya and David Mount
+// Description:		Methods for splitting kd-trees
+// Last modified:	01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//	Revision 1.0  04/01/05
+//----------------------------------------------------------------------
+
+#include "kd_tree.h"					// kd-tree definitions
+#include "kd_util.h"					// kd-tree utilities
+#include "kd_split.h"					// splitting functions
+
+//----------------------------------------------------------------------
+//	Constants
+//----------------------------------------------------------------------
+
+const double ERR = 0.001;				// a small value
+const double FS_ASPECT_RATIO = 3.0;		// maximum allowed aspect ratio
+										// in fair split. Must be >= 2.
+
+//----------------------------------------------------------------------
+//	kd_split - Bentley's standard splitting routine for kd-trees
+//		Find the dimension of the greatest spread, and split
+//		just before the median point along this dimension.
+//----------------------------------------------------------------------
+
+void kd_split(
+	ANNpointArray		pa,				// point array (permuted on return)
+	ANNidxArray			pidx,			// point indices
+	const ANNorthRect	&bnds,			// bounding rectangle for cell
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	int					&cut_dim,		// cutting dimension (returned)
+	ANNcoord			&cut_val,		// cutting value (returned)
+	int					&n_lo)			// num of points on low side (returned)
+{
+										// find dimension of maximum spread
+	cut_dim = annMaxSpread(pa, pidx, n, dim);
+	n_lo = n/2;							// median rank
+										// split about median
+	annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo);
+}
+
+//----------------------------------------------------------------------
+//	midpt_split - midpoint splitting rule for box-decomposition trees
+//
+//		This is the simplest splitting rule that guarantees boxes
+//		of bounded aspect ratio.  It simply cuts the box with the
+//		longest side through its midpoint.  If there are ties, it
+//		selects the dimension with the maximum point spread.
+//
+//		WARNING: This routine (while simple) doesn't seem to work
+//		well in practice in high dimensions, because it tends to
+//		generate a large number of trivial and/or unbalanced splits.
+//		Either kd_split(), sl_midpt_split(), or fair_split() are
+//		recommended, instead.
+//----------------------------------------------------------------------
+
+void midpt_split(
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices (permuted on return)
+	const ANNorthRect	&bnds,			// bounding rectangle for cell
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	int					&cut_dim,		// cutting dimension (returned)
+	ANNcoord			&cut_val,		// cutting value (returned)
+	int					&n_lo)			// num of points on low side (returned)
+{
+	int d;
+
+	ANNcoord max_length = bnds.hi[0] - bnds.lo[0];
+	for (d = 1; d < dim; d++) {			// find length of longest box side
+		ANNcoord length = bnds.hi[d] - bnds.lo[d];
+		if (length > max_length) {
+			max_length = length;
+		}
+	}
+	ANNcoord max_spread = -1;			// find long side with most spread
+	for (d = 0; d < dim; d++) {
+										// is it among longest?
+		if (double(bnds.hi[d] - bnds.lo[d]) >= (1-ERR)*max_length) {
+										// compute its spread
+			ANNcoord spr = annSpread(pa, pidx, n, d);
+			if (spr > max_spread) {		// is it max so far?
+				max_spread = spr;
+				cut_dim = d;
+			}
+		}
+	}
+										// split along cut_dim at midpoint
+	cut_val = (bnds.lo[cut_dim] + bnds.hi[cut_dim]) / 2;
+										// permute points accordingly
+	int br1, br2;
+	annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
+	//------------------------------------------------------------------
+	//	On return:		pa[0..br1-1] < cut_val
+	//					pa[br1..br2-1] == cut_val
+	//					pa[br2..n-1] > cut_val
+	//
+	//	We can set n_lo to any value in the range [br1..br2].
+	//	We choose split so that points are most evenly divided.
+	//------------------------------------------------------------------
+	if (br1 > n/2) n_lo = br1;
+	else if (br2 < n/2) n_lo = br2;
+	else n_lo = n/2;
+}
+
+//----------------------------------------------------------------------
+//	sl_midpt_split - sliding midpoint splitting rule
+//
+//		This is a modification of midpt_split, which has the nonsensical
+//		name "sliding midpoint".  The idea is that we try to use the
+//		midpoint rule, by bisecting the longest side.  If there are
+//		ties, the dimension with the maximum spread is selected.  If,
+//		however, the midpoint split produces a trivial split (no points
+//		on one side of the splitting plane) then we slide the splitting
+//		(maintaining its orientation) until it produces a nontrivial
+//		split. For example, if the splitting plane is along the x-axis,
+//		and all the data points have x-coordinate less than the x-bisector,
+//		then the split is taken along the maximum x-coordinate of the
+//		data points.
+//
+//		Intuitively, this rule cannot generate trivial splits, and
+//		hence avoids midpt_split's tendency to produce trees with
+//		a very large number of nodes.
+//
+//----------------------------------------------------------------------
+
+void sl_midpt_split(
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices (permuted on return)
+	const ANNorthRect	&bnds,			// bounding rectangle for cell
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	int					&cut_dim,		// cutting dimension (returned)
+	ANNcoord			&cut_val,		// cutting value (returned)
+	int					&n_lo)			// num of points on low side (returned)
+{
+	int d;
+
+	ANNcoord max_length = bnds.hi[0] - bnds.lo[0];
+	for (d = 1; d < dim; d++) {			// find length of longest box side
+		ANNcoord length = bnds.hi[d] - bnds.lo[d];
+		if (length > max_length) {
+			max_length = length;
+		}
+	}
+	ANNcoord max_spread = -1;			// find long side with most spread
+	for (d = 0; d < dim; d++) {
+										// is it among longest?
+		if ((bnds.hi[d] - bnds.lo[d]) >= (1-ERR)*max_length) {
+										// compute its spread
+			ANNcoord spr = annSpread(pa, pidx, n, d);
+			if (spr > max_spread) {		// is it max so far?
+				max_spread = spr;
+				cut_dim = d;
+			}
+		}
+	}
+										// ideal split at midpoint
+	ANNcoord ideal_cut_val = (bnds.lo[cut_dim] + bnds.hi[cut_dim])/2;
+
+	ANNcoord min, max;
+	annMinMax(pa, pidx, n, cut_dim, min, max);	// find min/max coordinates
+
+	if (ideal_cut_val < min)			// slide to min or max as needed
+		cut_val = min;
+	else if (ideal_cut_val > max)
+		cut_val = max;
+	else
+		cut_val = ideal_cut_val;
+
+										// permute points accordingly
+	int br1, br2;
+	annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
+	//------------------------------------------------------------------
+	//	On return:		pa[0..br1-1] < cut_val
+	//					pa[br1..br2-1] == cut_val
+	//					pa[br2..n-1] > cut_val
+	//
+	//	We can set n_lo to any value in the range [br1..br2] to satisfy
+	//	the exit conditions of the procedure.
+	//
+	//	if ideal_cut_val < min (implying br2 >= 1),
+	//			then we select n_lo = 1 (so there is one point on left) and
+	//	if ideal_cut_val > max (implying br1 <= n-1),
+	//			then we select n_lo = n-1 (so there is one point on right).
+	//	Otherwise, we select n_lo as close to n/2 as possible within
+	//			[br1..br2].
+	//------------------------------------------------------------------
+	if (ideal_cut_val < min) n_lo = 1;
+	else if (ideal_cut_val > max) n_lo = n-1;
+	else if (br1 > n/2) n_lo = br1;
+	else if (br2 < n/2) n_lo = br2;
+	else n_lo = n/2;
+}
+
+//----------------------------------------------------------------------
+//	fair_split - fair-split splitting rule
+//
+//		This is a compromise between the kd-tree splitting rule (which
+//		always splits data points at their median) and the midpoint
+//		splitting rule (which always splits a box through its center.
+//		The goal of this procedure is to achieve both nicely balanced
+//		splits, and boxes of bounded aspect ratio.
+//
+//		A constant FS_ASPECT_RATIO is defined. Given a box, those sides
+//		which can be split so that the ratio of the longest to shortest
+//		side does not exceed ASPECT_RATIO are identified.  Among these
+//		sides, we select the one in which the points have the largest
+//		spread. We then split the points in a manner which most evenly
+//		distributes the points on either side of the splitting plane,
+//		subject to maintaining the bound on the ratio of long to short
+//		sides. To determine that the aspect ratio will be preserved,
+//		we determine the longest side (other than this side), and
+//		determine how narrowly we can cut this side, without causing the
+//		aspect ratio bound to be exceeded (small_piece).
+//
+//		This procedure is more robust than either kd_split or midpt_split,
+//		but is more complicated as well.  When point distribution is
+//		extremely skewed, this degenerates to midpt_split (actually
+//		1/3 point split), and when the points are most evenly distributed,
+//		this degenerates to kd-split.
+//----------------------------------------------------------------------
+
+void fair_split(
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices (permuted on return)
+	const ANNorthRect	&bnds,			// bounding rectangle for cell
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	int					&cut_dim,		// cutting dimension (returned)
+	ANNcoord			&cut_val,		// cutting value (returned)
+	int					&n_lo)			// num of points on low side (returned)
+{
+	int d;
+	ANNcoord max_length = bnds.hi[0] - bnds.lo[0];
+	cut_dim = 0;
+	for (d = 1; d < dim; d++) {			// find length of longest box side
+		ANNcoord length = bnds.hi[d] - bnds.lo[d];
+		if (length > max_length) {
+			max_length = length;
+			cut_dim = d;
+		}
+	}
+
+	ANNcoord max_spread = 0;			// find legal cut with max spread
+	cut_dim = 0;
+	for (d = 0; d < dim; d++) {
+		ANNcoord length = bnds.hi[d] - bnds.lo[d];
+										// is this side midpoint splitable
+										// without violating aspect ratio?
+		if (((double) max_length)*2.0/((double) length) <= FS_ASPECT_RATIO) {
+										// compute spread along this dim
+			ANNcoord spr = annSpread(pa, pidx, n, d);
+			if (spr > max_spread) {		// best spread so far
+				max_spread = spr;
+				cut_dim = d;			// this is dimension to cut
+			}
+		}
+	}
+
+	max_length = 0;						// find longest side other than cut_dim
+	for (d = 0; d < dim; d++) {
+		ANNcoord length = bnds.hi[d] - bnds.lo[d];
+		if (d != cut_dim && length > max_length)
+			max_length = length;
+	}
+										// consider most extreme splits
+	ANNcoord small_piece = max_length / FS_ASPECT_RATIO;
+	ANNcoord lo_cut = bnds.lo[cut_dim] + small_piece;// lowest legal cut
+	ANNcoord hi_cut = bnds.hi[cut_dim] - small_piece;// highest legal cut
+
+	int br1, br2;
+										// is median below lo_cut ?
+	if (annSplitBalance(pa, pidx, n, cut_dim, lo_cut) >= 0) {
+		cut_val = lo_cut;				// cut at lo_cut
+		annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
+		n_lo = br1;
+	}
+										// is median above hi_cut?
+	else if (annSplitBalance(pa, pidx, n, cut_dim, hi_cut) <= 0) {
+		cut_val = hi_cut;				// cut at hi_cut
+		annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
+		n_lo = br2;
+	}
+	else {								// median cut preserves asp ratio
+		n_lo = n/2;						// split about median
+		annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo);
+	}
+}
+
+//----------------------------------------------------------------------
+//	sl_fair_split - sliding fair split splitting rule
+//
+//		Sliding fair split is a splitting rule that combines the
+//		strengths of both fair split with sliding midpoint split.
+//		Fair split tends to produce balanced splits when the points
+//		are roughly uniformly distributed, but it can produce many
+//		trivial splits when points are highly clustered.  Sliding
+//		midpoint never produces trivial splits, and shrinks boxes
+//		nicely if points are highly clustered, but it may produce
+//		rather unbalanced splits when points are unclustered but not
+//		quite uniform.
+//
+//		Sliding fair split is based on the theory that there are two
+//		types of splits that are "good": balanced splits that produce
+//		fat boxes, and unbalanced splits provided the cell with fewer
+//		points is fat.
+//
+//		This splitting rule operates by first computing the longest
+//		side of the current bounding box.  Then it asks which sides
+//		could be split (at the midpoint) and still satisfy the aspect
+//		ratio bound with respect to this side.	Among these, it selects
+//		the side with the largest spread (as fair split would).	 It
+//		then considers the most extreme cuts that would be allowed by
+//		the aspect ratio bound.	 This is done by dividing the longest
+//		side of the box by the aspect ratio bound.	If the median cut
+//		lies between these extreme cuts, then we use the median cut.
+//		If not, then consider the extreme cut that is closer to the
+//		median.	 If all the points lie to one side of this cut, then
+//		we slide the cut until it hits the first point.	 This may
+//		violate the aspect ratio bound, but will never generate empty
+//		cells.	However the sibling of every such skinny cell is fat,
+//		and hence packing arguments still apply.
+//
+//----------------------------------------------------------------------
+
+void sl_fair_split(
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices (permuted on return)
+	const ANNorthRect	&bnds,			// bounding rectangle for cell
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	int					&cut_dim,		// cutting dimension (returned)
+	ANNcoord			&cut_val,		// cutting value (returned)
+	int					&n_lo)			// num of points on low side (returned)
+{
+	int d;
+	ANNcoord min, max;					// min/max coordinates
+	int br1, br2;						// split break points
+
+	ANNcoord max_length = bnds.hi[0] - bnds.lo[0];
+	cut_dim = 0;
+	for (d = 1; d < dim; d++) {			// find length of longest box side
+		ANNcoord length = bnds.hi[d] - bnds.lo[d];
+		if (length	> max_length) {
+			max_length = length;
+			cut_dim = d;
+		}
+	}
+
+	ANNcoord max_spread = 0;			// find legal cut with max spread
+	cut_dim = 0;
+	for (d = 0; d < dim; d++) {
+		ANNcoord length = bnds.hi[d] - bnds.lo[d];
+										// is this side midpoint splitable
+										// without violating aspect ratio?
+		if (((double) max_length)*2.0/((double) length) <= FS_ASPECT_RATIO) {
+										// compute spread along this dim
+			ANNcoord spr = annSpread(pa, pidx, n, d);
+			if (spr > max_spread) {		// best spread so far
+				max_spread = spr;
+				cut_dim = d;			// this is dimension to cut
+			}
+		}
+	}
+
+	max_length = 0;						// find longest side other than cut_dim
+	for (d = 0; d < dim; d++) {
+		ANNcoord length = bnds.hi[d] - bnds.lo[d];
+		if (d != cut_dim && length > max_length)
+			max_length = length;
+	}
+										// consider most extreme splits
+	ANNcoord small_piece = max_length / FS_ASPECT_RATIO;
+	ANNcoord lo_cut = bnds.lo[cut_dim] + small_piece;// lowest legal cut
+	ANNcoord hi_cut = bnds.hi[cut_dim] - small_piece;// highest legal cut
+										// find min and max along cut_dim
+	annMinMax(pa, pidx, n, cut_dim, min, max);
+										// is median below lo_cut?
+	if (annSplitBalance(pa, pidx, n, cut_dim, lo_cut) >= 0) {
+		if (max > lo_cut) {				// are any points above lo_cut?
+			cut_val = lo_cut;			// cut at lo_cut
+			annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
+			n_lo = br1;					// balance if there are ties
+		}
+		else {							// all points below lo_cut
+			cut_val = max;				// cut at max value
+			annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
+			n_lo = n-1;
+		}
+	}
+										// is median above hi_cut?
+	else if (annSplitBalance(pa, pidx, n, cut_dim, hi_cut) <= 0) {
+		if (min < hi_cut) {				// are any points below hi_cut?
+			cut_val = hi_cut;			// cut at hi_cut
+			annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
+			n_lo = br2;					// balance if there are ties
+		}
+		else {							// all points above hi_cut
+			cut_val = min;				// cut at min value
+			annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
+			n_lo = 1;
+		}
+	}
+	else {								// median cut is good enough
+		n_lo = n/2;						// split about median
+		annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo);
+	}
+}
diff --git a/Contrib/ANN/src/kd_split.h b/Contrib/ANN/src/kd_split.h
new file mode 100755
index 0000000..ef80461
--- /dev/null
+++ b/Contrib/ANN/src/kd_split.h
@@ -0,0 +1,85 @@
+//----------------------------------------------------------------------
+// File:			kd_split.h
+// Programmer:		Sunil Arya and David Mount
+// Description:		Methods for splitting kd-trees
+// Last modified:	01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//----------------------------------------------------------------------
+
+#ifndef ANN_KD_SPLIT_H
+#define ANN_KD_SPLIT_H
+
+#include "kd_tree.h"					// kd-tree definitions
+
+//----------------------------------------------------------------------
+//	External entry points
+//		These are all splitting procedures for kd-trees.
+//----------------------------------------------------------------------
+
+void kd_split(							// standard (optimized) kd-splitter
+	ANNpointArray		pa,				// point array (unaltered)
+	ANNidxArray			pidx,			// point indices (permuted on return)
+	const ANNorthRect	&bnds,			// bounding rectangle for cell
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	int					&cut_dim,		// cutting dimension (returned)
+	ANNcoord			&cut_val,		// cutting value (returned)
+	int					&n_lo);			// num of points on low side (returned)
+
+void midpt_split(						// midpoint kd-splitter
+	ANNpointArray		pa,				// point array (unaltered)
+	ANNidxArray			pidx,			// point indices (permuted on return)
+	const ANNorthRect	&bnds,			// bounding rectangle for cell
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	int					&cut_dim,		// cutting dimension (returned)
+	ANNcoord			&cut_val,		// cutting value (returned)
+	int					&n_lo);			// num of points on low side (returned)
+
+void sl_midpt_split(					// sliding midpoint kd-splitter
+	ANNpointArray		pa,				// point array (unaltered)
+	ANNidxArray			pidx,			// point indices (permuted on return)
+	const ANNorthRect	&bnds,			// bounding rectangle for cell
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	int					&cut_dim,		// cutting dimension (returned)
+	ANNcoord			&cut_val,		// cutting value (returned)
+	int					&n_lo);			// num of points on low side (returned)
+
+void fair_split(						// fair-split kd-splitter
+	ANNpointArray		pa,				// point array (unaltered)
+	ANNidxArray			pidx,			// point indices (permuted on return)
+	const ANNorthRect	&bnds,			// bounding rectangle for cell
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	int					&cut_dim,		// cutting dimension (returned)
+	ANNcoord			&cut_val,		// cutting value (returned)
+	int					&n_lo);			// num of points on low side (returned)
+
+void sl_fair_split(						// sliding fair-split kd-splitter
+	ANNpointArray		pa,				// point array (unaltered)
+	ANNidxArray			pidx,			// point indices (permuted on return)
+	const ANNorthRect	&bnds,			// bounding rectangle for cell
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	int					&cut_dim,		// cutting dimension (returned)
+	ANNcoord			&cut_val,		// cutting value (returned)
+	int					&n_lo);			// num of points on low side (returned)
+
+#endif
diff --git a/Contrib/ANN/src/kd_tree.cpp b/Contrib/ANN/src/kd_tree.cpp
new file mode 100755
index 0000000..2828fd2
--- /dev/null
+++ b/Contrib/ANN/src/kd_tree.cpp
@@ -0,0 +1,405 @@
+//----------------------------------------------------------------------
+// File:			kd_tree.cpp
+// Programmer:		Sunil Arya and David Mount
+// Description:		Basic methods for kd-trees.
+// Last modified:	01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//	Revision 1.0  04/01/05
+//		Increased aspect ratio bound (ANN_AR_TOOBIG) from 100 to 1000.
+//		Fixed leaf counts to count trivial leaves.
+//		Added optional pa, pi arguments to Skeleton kd_tree constructor
+//			for use in load constructor.
+//		Added annClose() to eliminate KD_TRIVIAL memory leak.
+//----------------------------------------------------------------------
+
+#include "kd_tree.h"					// kd-tree declarations
+#include "kd_split.h"					// kd-tree splitting rules
+#include "kd_util.h"					// kd-tree utilities
+#include <ANN/ANNperf.h>				// performance evaluation
+
+//----------------------------------------------------------------------
+//	Global data
+//
+//	For some splitting rules, especially with small bucket sizes,
+//	it is possible to generate a large number of empty leaf nodes.
+//	To save storage we allocate a single trivial leaf node which
+//	contains no points.  For messy coding reasons it is convenient
+//	to have it reference a trivial point index.
+//
+//	KD_TRIVIAL is allocated when the first kd-tree is created.  It
+//	must *never* deallocated (since it may be shared by more than
+//	one tree).
+//----------------------------------------------------------------------
+static int				IDX_TRIVIAL[] = {0};	// trivial point index
+ANNkd_leaf				*KD_TRIVIAL = NULL;		// trivial leaf node
+
+//----------------------------------------------------------------------
+//	Printing the kd-tree 
+//		These routines print a kd-tree in reverse inorder (high then
+//		root then low).  (This is so that if you look at the output
+//		from the right side it appear from left to right in standard
+//		inorder.)  When outputting leaves we output only the point
+//		indices rather than the point coordinates. There is an option
+//		to print the point coordinates separately.
+//
+//		The tree printing routine calls the printing routines on the
+//		individual nodes of the tree, passing in the level or depth
+//		in the tree.  The level in the tree is used to print indentation
+//		for readability.
+//----------------------------------------------------------------------
+
+void ANNkd_split::print(				// print splitting node
+		int level,						// depth of node in tree
+		ostream &out)					// output stream
+{
+	child[ANN_HI]->print(level+1, out);	// print high child
+	out << "    ";
+	for (int i = 0; i < level; i++)		// print indentation
+		out << "..";
+	out << "Split cd=" << cut_dim << " cv=" << cut_val;
+	out << " lbnd=" << cd_bnds[ANN_LO];
+	out << " hbnd=" << cd_bnds[ANN_HI];
+	out << "\n";
+	child[ANN_LO]->print(level+1, out);	// print low child
+}
+
+void ANNkd_leaf::print(					// print leaf node
+		int level,						// depth of node in tree
+		ostream &out)					// output stream
+{
+
+	out << "    ";
+	for (int i = 0; i < level; i++)		// print indentation
+		out << "..";
+
+	if (this == KD_TRIVIAL) {			// canonical trivial leaf node
+		out << "Leaf (trivial)\n";
+	}
+	else{
+		out << "Leaf n=" << n_pts << " <";
+		for (int j = 0; j < n_pts; j++) {
+			out << bkt[j];
+			if (j < n_pts-1) out << ",";
+		}
+		out << ">\n";
+	}
+}
+
+void ANNkd_tree::Print(					// print entire tree
+		ANNbool with_pts,				// print points as well?
+		ostream &out)					// output stream
+{
+	out << "ANN Version " << ANNversion << "\n";
+	if (with_pts) {						// print point coordinates
+		out << "    Points:\n";
+		for (int i = 0; i < n_pts; i++) {
+			out << "\t" << i << ": ";
+			annPrintPt(pts[i], dim, out);
+			out << "\n";
+		}
+	}
+	if (root == NULL)					// empty tree?
+		out << "    Null tree.\n";
+	else {
+		root->print(0, out);			// invoke printing at root
+	}
+}
+
+//----------------------------------------------------------------------
+//	kd_tree statistics (for performance evaluation)
+//		This routine compute various statistics information for
+//		a kd-tree.  It is used by the implementors for performance
+//		evaluation of the data structure.
+//----------------------------------------------------------------------
+
+#define MAX(a,b)		((a) > (b) ? (a) : (b))
+
+void ANNkdStats::merge(const ANNkdStats &st)	// merge stats from child 
+{
+	n_lf += st.n_lf;			n_tl += st.n_tl;
+	n_spl += st.n_spl;			n_shr += st.n_shr;
+	depth = MAX(depth, st.depth);
+	sum_ar += st.sum_ar;
+}
+
+//----------------------------------------------------------------------
+//	Update statistics for nodes
+//----------------------------------------------------------------------
+
+const double ANN_AR_TOOBIG = 1000;				// too big an aspect ratio
+
+void ANNkd_leaf::getStats(						// get subtree statistics
+	int					dim,					// dimension of space
+	ANNkdStats			&st,					// stats (modified)
+	ANNorthRect			&bnd_box)				// bounding box
+{
+	st.reset();
+	st.n_lf = 1;								// count this leaf
+	if (this == KD_TRIVIAL) st.n_tl = 1;		// count trivial leaf
+	double ar = annAspectRatio(dim, bnd_box);	// aspect ratio of leaf
+												// incr sum (ignore outliers)
+	st.sum_ar += float(ar < ANN_AR_TOOBIG ? ar : ANN_AR_TOOBIG);
+}
+
+void ANNkd_split::getStats(						// get subtree statistics
+	int					dim,					// dimension of space
+	ANNkdStats			&st,					// stats (modified)
+	ANNorthRect			&bnd_box)				// bounding box
+{
+	ANNkdStats ch_stats;						// stats for children
+												// get stats for low child
+	ANNcoord hv = bnd_box.hi[cut_dim];			// save box bounds
+	bnd_box.hi[cut_dim] = cut_val;				// upper bound for low child
+	ch_stats.reset();							// reset
+	child[ANN_LO]->getStats(dim, ch_stats, bnd_box);
+	st.merge(ch_stats);							// merge them
+	bnd_box.hi[cut_dim] = hv;					// restore bound
+												// get stats for high child
+	ANNcoord lv = bnd_box.lo[cut_dim];			// save box bounds
+	bnd_box.lo[cut_dim] = cut_val;				// lower bound for high child
+	ch_stats.reset();							// reset
+	child[ANN_HI]->getStats(dim, ch_stats, bnd_box);
+	st.merge(ch_stats);							// merge them
+	bnd_box.lo[cut_dim] = lv;					// restore bound
+
+	st.depth++;									// increment depth
+	st.n_spl++;									// increment number of splits
+}
+
+//----------------------------------------------------------------------
+//	getStats
+//		Collects a number of statistics related to kd_tree or
+//		bd_tree.
+//----------------------------------------------------------------------
+
+void ANNkd_tree::getStats(						// get tree statistics
+	ANNkdStats			&st)					// stats (modified)
+{
+	st.reset(dim, n_pts, bkt_size);				// reset stats
+												// create bounding box
+	ANNorthRect bnd_box(dim, bnd_box_lo, bnd_box_hi);
+	if (root != NULL) {							// if nonempty tree
+		root->getStats(dim, st, bnd_box);		// get statistics
+		st.avg_ar = st.sum_ar / st.n_lf;		// average leaf asp ratio
+	}
+}
+
+//----------------------------------------------------------------------
+//	kd_tree destructor
+//		The destructor just frees the various elements that were
+//		allocated in the construction process.
+//----------------------------------------------------------------------
+
+ANNkd_tree::~ANNkd_tree()				// tree destructor
+{
+	if (root != NULL) delete root;
+	if (pidx != NULL) delete [] pidx;
+	if (bnd_box_lo != NULL) annDeallocPt(bnd_box_lo);
+	if (bnd_box_hi != NULL) annDeallocPt(bnd_box_hi);
+}
+
+//----------------------------------------------------------------------
+//	This is called with all use of ANN is finished.  It eliminates the
+//	minor memory leak caused by the allocation of KD_TRIVIAL.
+//----------------------------------------------------------------------
+void annClose()				// close use of ANN
+{
+	if (KD_TRIVIAL != NULL) {
+		delete KD_TRIVIAL;
+		KD_TRIVIAL = NULL;
+	}
+}
+
+//----------------------------------------------------------------------
+//	kd_tree constructors
+//		There is a skeleton kd-tree constructor which sets up a
+//		trivial empty tree.	 The last optional argument allows
+//		the routine to be passed a point index array which is
+//		assumed to be of the proper size (n).  Otherwise, one is
+//		allocated and initialized to the identity.	Warning: In
+//		either case the destructor will deallocate this array.
+//
+//		As a kludge, we need to allocate KD_TRIVIAL if one has not
+//		already been allocated.	 (This is because I'm too dumb to
+//		figure out how to cause a pointer to be allocated at load
+//		time.)
+//----------------------------------------------------------------------
+
+void ANNkd_tree::SkeletonTree(			// construct skeleton tree
+		int n,							// number of points
+		int dd,							// dimension
+		int bs,							// bucket size
+		ANNpointArray pa,				// point array
+		ANNidxArray pi)					// point indices
+{
+	dim = dd;							// initialize basic elements
+	n_pts = n;
+	bkt_size = bs;
+	pts = pa;							// initialize points array
+
+	root = NULL;						// no associated tree yet
+
+	if (pi == NULL) {					// point indices provided?
+		pidx = new ANNidx[n];			// no, allocate space for point indices
+		for (int i = 0; i < n; i++) {
+			pidx[i] = i;				// initially identity
+		}
+	}
+	else {
+		pidx = pi;						// yes, use them
+	}
+
+	bnd_box_lo = bnd_box_hi = NULL;		// bounding box is nonexistent
+	if (KD_TRIVIAL == NULL)				// no trivial leaf node yet?
+		KD_TRIVIAL = new ANNkd_leaf(0, IDX_TRIVIAL);	// allocate it
+}
+
+ANNkd_tree::ANNkd_tree(					// basic constructor
+		int n,							// number of points
+		int dd,							// dimension
+		int bs)							// bucket size
+{  SkeletonTree(n, dd, bs);  }			// construct skeleton tree
+
+//----------------------------------------------------------------------
+//	rkd_tree - recursive procedure to build a kd-tree
+//
+//		Builds a kd-tree for points in pa as indexed through the
+//		array pidx[0..n-1] (typically a subarray of the array used in
+//		the top-level call).  This routine permutes the array pidx,
+//		but does not alter pa[].
+//
+//		The construction is based on a standard algorithm for constructing
+//		the kd-tree (see Friedman, Bentley, and Finkel, ``An algorithm for
+//		finding best matches in logarithmic expected time,'' ACM Transactions
+//		on Mathematical Software, 3(3):209-226, 1977).  The procedure
+//		operates by a simple divide-and-conquer strategy, which determines
+//		an appropriate orthogonal cutting plane (see below), and splits
+//		the points.  When the number of points falls below the bucket size,
+//		we simply store the points in a leaf node's bucket.
+//
+//		One of the arguments is a pointer to a splitting routine,
+//		whose prototype is:
+//		
+//				void split(
+//						ANNpointArray pa,  // complete point array
+//						ANNidxArray pidx,  // point array (permuted on return)
+//						ANNorthRect &bnds, // bounds of current cell
+//						int n,			   // number of points
+//						int dim,		   // dimension of space
+//						int &cut_dim,	   // cutting dimension
+//						ANNcoord &cut_val, // cutting value
+//						int &n_lo)		   // no. of points on low side of cut
+//
+//		This procedure selects a cutting dimension and cutting value,
+//		partitions pa about these values, and returns the number of
+//		points on the low side of the cut.
+//----------------------------------------------------------------------
+
+ANNkd_ptr rkd_tree(				// recursive construction of kd-tree
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices to store in subtree
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	int					bsp,			// bucket space
+	ANNorthRect			&bnd_box,		// bounding box for current node
+	ANNkd_splitter		splitter)		// splitting routine
+{
+	if (n <= bsp) {						// n small, make a leaf node
+		if (n == 0)						// empty leaf node
+			return KD_TRIVIAL;			// return (canonical) empty leaf
+		else							// construct the node and return
+			return new ANNkd_leaf(n, pidx); 
+	}
+	else {								// n large, make a splitting node
+		int cd;							// cutting dimension
+		ANNcoord cv;					// cutting value
+		int n_lo;						// number on low side of cut
+		ANNkd_node *lo, *hi;			// low and high children
+
+										// invoke splitting procedure
+		(*splitter)(pa, pidx, bnd_box, n, dim, cd, cv, n_lo);
+
+		ANNcoord lv = bnd_box.lo[cd];	// save bounds for cutting dimension
+		ANNcoord hv = bnd_box.hi[cd];
+
+		bnd_box.hi[cd] = cv;			// modify bounds for left subtree
+		lo = rkd_tree(					// build left subtree
+				pa, pidx, n_lo,			// ...from pidx[0..n_lo-1]
+				dim, bsp, bnd_box, splitter);
+		bnd_box.hi[cd] = hv;			// restore bounds
+
+		bnd_box.lo[cd] = cv;			// modify bounds for right subtree
+		hi = rkd_tree(					// build right subtree
+				pa, pidx + n_lo, n-n_lo,// ...from pidx[n_lo..n-1]
+				dim, bsp, bnd_box, splitter);
+		bnd_box.lo[cd] = lv;			// restore bounds
+
+										// create the splitting node
+		ANNkd_split *ptr = new ANNkd_split(cd, cv, lv, hv, lo, hi);
+
+		return ptr;						// return pointer to this node
+	}
+} 
+
+//----------------------------------------------------------------------
+// kd-tree constructor
+//		This is the main constructor for kd-trees given a set of points.
+//		It first builds a skeleton tree, then computes the bounding box
+//		of the data points, and then invokes rkd_tree() to actually
+//		build the tree, passing it the appropriate splitting routine.
+//----------------------------------------------------------------------
+
+ANNkd_tree::ANNkd_tree(					// construct from point array
+	ANNpointArray		pa,				// point array (with at least n pts)
+	int					n,				// number of points
+	int					dd,				// dimension
+	int					bs,				// bucket size
+	ANNsplitRule		split)			// splitting method
+{
+	SkeletonTree(n, dd, bs);			// set up the basic stuff
+	pts = pa;							// where the points are
+	if (n == 0) return;					// no points--no sweat
+
+	ANNorthRect bnd_box(dd);			// bounding box for points
+	annEnclRect(pa, pidx, n, dd, bnd_box);// construct bounding rectangle
+										// copy to tree structure
+	bnd_box_lo = annCopyPt(dd, bnd_box.lo);
+	bnd_box_hi = annCopyPt(dd, bnd_box.hi);
+
+	switch (split) {					// build by rule
+	case ANN_KD_STD:					// standard kd-splitting rule
+		root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, kd_split);
+		break;
+	case ANN_KD_MIDPT:					// midpoint split
+		root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, midpt_split);
+		break;
+	case ANN_KD_FAIR:					// fair split
+		root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, fair_split);
+		break;
+	case ANN_KD_SUGGEST:				// best (in our opinion)
+	case ANN_KD_SL_MIDPT:				// sliding midpoint split
+		root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, sl_midpt_split);
+		break;
+	case ANN_KD_SL_FAIR:				// sliding fair split
+		root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, sl_fair_split);
+		break;
+	default:
+		annError("Illegal splitting method", ANNabort);
+	}
+}
diff --git a/Contrib/ANN/src/kd_tree.h b/Contrib/ANN/src/kd_tree.h
new file mode 100755
index 0000000..81284b6
--- /dev/null
+++ b/Contrib/ANN/src/kd_tree.h
@@ -0,0 +1,197 @@
+//----------------------------------------------------------------------
+// File:			kd_tree.h
+// Programmer:		Sunil Arya and David Mount
+// Description:		Declarations for standard kd-tree routines
+// Last modified:	05/03/05 (Version 1.1)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//	Revision 1.1  05/03/05
+//		Added fixed radius kNN search
+//----------------------------------------------------------------------
+
+#ifndef ANN_kd_tree_H
+#define ANN_kd_tree_H
+
+#include <ANN/ANNx.h>					// all ANN includes
+
+using namespace std;					// make std:: available
+
+//----------------------------------------------------------------------
+//	Generic kd-tree node
+//
+//		Nodes in kd-trees are of two types, splitting nodes which contain
+//		splitting information (a splitting hyperplane orthogonal to one
+//		of the coordinate axes) and leaf nodes which contain point
+//		information (an array of points stored in a bucket).  This is
+//		handled by making a generic class kd_node, which is essentially an
+//		empty shell, and then deriving the leaf and splitting nodes from
+//		this.
+//----------------------------------------------------------------------
+
+class ANNkd_node{						// generic kd-tree node (empty shell)
+public:
+	virtual ~ANNkd_node() {}					// virtual distroyer
+
+	virtual void ann_search(ANNdist) = 0;		// tree search
+	virtual void ann_pri_search(ANNdist) = 0;	// priority search
+	virtual void ann_FR_search(ANNdist) = 0;	// fixed-radius search
+
+	virtual void getStats(						// get tree statistics
+				int dim,						// dimension of space
+				ANNkdStats &st,					// statistics
+				ANNorthRect &bnd_box) = 0;		// bounding box
+												// print node
+	virtual void print(int level, ostream &out) = 0;
+	virtual void dump(ostream &out) = 0;		// dump node
+
+	friend class ANNkd_tree;					// allow kd-tree to access us
+};
+
+//----------------------------------------------------------------------
+//	kd-splitting function:
+//		kd_splitter is a pointer to a splitting routine for preprocessing.
+//		Different splitting procedures result in different strategies
+//		for building the tree.
+//----------------------------------------------------------------------
+
+typedef void (*ANNkd_splitter)(			// splitting routine for kd-trees
+	ANNpointArray		pa,				// point array (unaltered)
+	ANNidxArray			pidx,			// point indices (permuted on return)
+	const ANNorthRect	&bnds,			// bounding rectangle for cell
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	int					&cut_dim,		// cutting dimension (returned)
+	ANNcoord			&cut_val,		// cutting value (returned)
+	int					&n_lo);			// num of points on low side (returned)
+
+//----------------------------------------------------------------------
+//	Leaf kd-tree node
+//		Leaf nodes of the kd-tree store the set of points associated
+//		with this bucket, stored as an array of point indices.  These
+//		are indices in the array points, which resides with the
+//		root of the kd-tree.  We also store the number of points
+//		that reside in this bucket.
+//----------------------------------------------------------------------
+
+class ANNkd_leaf: public ANNkd_node		// leaf node for kd-tree
+{
+	int					n_pts;			// no. points in bucket
+	ANNidxArray			bkt;			// bucket of points
+public:
+	ANNkd_leaf(							// constructor
+		int				n,				// number of points
+		ANNidxArray		b)				// bucket
+		{
+			n_pts		= n;			// number of points in bucket
+			bkt			= b;			// the bucket
+		}
+
+	~ANNkd_leaf() { }					// destructor (none)
+
+	virtual void getStats(						// get tree statistics
+				int dim,						// dimension of space
+				ANNkdStats &st,					// statistics
+				ANNorthRect &bnd_box);			// bounding box
+	virtual void print(int level, ostream &out);// print node
+	virtual void dump(ostream &out);			// dump node
+
+	virtual void ann_search(ANNdist);			// standard search
+	virtual void ann_pri_search(ANNdist);		// priority search
+	virtual void ann_FR_search(ANNdist);		// fixed-radius search
+};
+
+//----------------------------------------------------------------------
+//		KD_TRIVIAL is a special pointer to an empty leaf node. Since
+//		some splitting rules generate many (more than 50%) trivial
+//		leaves, we use this one shared node to save space.
+//
+//		The pointer is initialized to NULL, but whenever a kd-tree is
+//		created, we allocate this node, if it has not already been
+//		allocated. This node is *never* deallocated, so it produces
+//		a small memory leak.
+//----------------------------------------------------------------------
+
+extern ANNkd_leaf *KD_TRIVIAL;					// trivial (empty) leaf node
+
+//----------------------------------------------------------------------
+//	kd-tree splitting node.
+//		Splitting nodes contain a cutting dimension and a cutting value.
+//		These indicate the axis-parellel plane which subdivide the
+//		box for this node. The extent of the bounding box along the
+//		cutting dimension is maintained (this is used to speed up point
+//		to box distance calculations) [we do not store the entire bounding
+//		box since this may be wasteful of space in high dimensions].
+//		We also store pointers to the 2 children.
+//----------------------------------------------------------------------
+
+class ANNkd_split : public ANNkd_node	// splitting node of a kd-tree
+{
+	int					cut_dim;		// dim orthogonal to cutting plane
+	ANNcoord			cut_val;		// location of cutting plane
+	ANNcoord			cd_bnds[2];		// lower and upper bounds of
+										// rectangle along cut_dim
+	ANNkd_ptr			child[2];		// left and right children
+public:
+	ANNkd_split(						// constructor
+		int cd,							// cutting dimension
+		ANNcoord cv,					// cutting value
+		ANNcoord lv, ANNcoord hv,				// low and high values
+		ANNkd_ptr lc=NULL, ANNkd_ptr hc=NULL)	// children
+		{
+			cut_dim		= cd;					// cutting dimension
+			cut_val		= cv;					// cutting value
+			cd_bnds[ANN_LO] = lv;				// lower bound for rectangle
+			cd_bnds[ANN_HI] = hv;				// upper bound for rectangle
+			child[ANN_LO]	= lc;				// left child
+			child[ANN_HI]	= hc;				// right child
+		}
+
+	~ANNkd_split()						// destructor
+		{
+			if (child[ANN_LO]!= NULL && child[ANN_LO]!= KD_TRIVIAL)
+				delete child[ANN_LO];
+			if (child[ANN_HI]!= NULL && child[ANN_HI]!= KD_TRIVIAL)
+				delete child[ANN_HI];
+		}
+
+	virtual void getStats(						// get tree statistics
+				int dim,						// dimension of space
+				ANNkdStats &st,					// statistics
+				ANNorthRect &bnd_box);			// bounding box
+	virtual void print(int level, ostream &out);// print node
+	virtual void dump(ostream &out);			// dump node
+
+	virtual void ann_search(ANNdist);			// standard search
+	virtual void ann_pri_search(ANNdist);		// priority search
+	virtual void ann_FR_search(ANNdist);		// fixed-radius search
+};
+
+//----------------------------------------------------------------------
+//		External entry points
+//----------------------------------------------------------------------
+
+ANNkd_ptr rkd_tree(				// recursive construction of kd-tree
+	ANNpointArray		pa,				// point array (unaltered)
+	ANNidxArray			pidx,			// point indices to store in subtree
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	int					bsp,			// bucket space
+	ANNorthRect			&bnd_box,		// bounding box for current node
+	ANNkd_splitter		splitter);		// splitting routine
+
+#endif
diff --git a/Contrib/ANN/src/kd_util.cpp b/Contrib/ANN/src/kd_util.cpp
new file mode 100755
index 0000000..06d65b8
--- /dev/null
+++ b/Contrib/ANN/src/kd_util.cpp
@@ -0,0 +1,439 @@
+//----------------------------------------------------------------------
+// File:			kd_util.cpp
+// Programmer:		Sunil Arya and David Mount
+// Description:		Common utilities for kd-trees
+// Last modified:	01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//----------------------------------------------------------------------
+
+#include "kd_util.h"					// kd-utility declarations
+
+#include <ANN/ANNperf.h>				// performance evaluation
+
+//----------------------------------------------------------------------
+// The following routines are utility functions for manipulating
+// points sets, used in determining splitting planes for kd-tree
+// construction.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+//	NOTE: Virtually all point indexing is done through an index (i.e.
+//	permutation) array pidx.  Consequently, a reference to the d-th
+//	coordinate of the i-th point is pa[pidx[i]][d].  The macro PA(i,d)
+//	is a shorthand for this.
+//----------------------------------------------------------------------
+										// standard 2-d indirect indexing
+#define PA(i,d)			(pa[pidx[(i)]][(d)])
+										// accessing a single point
+#define PP(i)			(pa[pidx[(i)]])
+
+//----------------------------------------------------------------------
+//	annAspectRatio
+//		Compute the aspect ratio (ratio of longest to shortest side)
+//		of a rectangle.
+//----------------------------------------------------------------------
+
+double annAspectRatio(
+	int					dim,			// dimension
+	const ANNorthRect	&bnd_box)		// bounding cube
+{
+	ANNcoord length = bnd_box.hi[0] - bnd_box.lo[0];
+	ANNcoord min_length = length;				// min side length
+	ANNcoord max_length = length;				// max side length
+	for (int d = 0; d < dim; d++) {
+		length = bnd_box.hi[d] - bnd_box.lo[d];
+		if (length < min_length) min_length = length;
+		if (length > max_length) max_length = length;
+	}
+	return max_length/min_length;
+}
+
+//----------------------------------------------------------------------
+//	annEnclRect, annEnclCube
+//		These utilities compute the smallest rectangle and cube enclosing
+//		a set of points, respectively.
+//----------------------------------------------------------------------
+
+void annEnclRect(
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices
+	int					n,				// number of points
+	int					dim,			// dimension
+	ANNorthRect			&bnds)			// bounding cube (returned)
+{
+	for (int d = 0; d < dim; d++) {		// find smallest enclosing rectangle
+		ANNcoord lo_bnd = PA(0,d);		// lower bound on dimension d
+		ANNcoord hi_bnd = PA(0,d);		// upper bound on dimension d
+		for (int i = 0; i < n; i++) {
+			if (PA(i,d) < lo_bnd) lo_bnd = PA(i,d);
+			else if (PA(i,d) > hi_bnd) hi_bnd = PA(i,d);
+		}
+		bnds.lo[d] = lo_bnd;
+		bnds.hi[d] = hi_bnd;
+	}
+}
+
+void annEnclCube(						// compute smallest enclosing cube
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices
+	int					n,				// number of points
+	int					dim,			// dimension
+	ANNorthRect			&bnds)			// bounding cube (returned)
+{
+	int d;
+										// compute smallest enclosing rect
+	annEnclRect(pa, pidx, n, dim, bnds);
+
+	ANNcoord max_len = 0;				// max length of any side
+	for (d = 0; d < dim; d++) {			// determine max side length
+		ANNcoord len = bnds.hi[d] - bnds.lo[d];
+		if (len > max_len) {			// update max_len if longest
+			max_len = len;
+		}
+	}
+	for (d = 0; d < dim; d++) {			// grow sides to match max
+		ANNcoord len = bnds.hi[d] - bnds.lo[d];
+		ANNcoord half_diff = (max_len - len) / 2;
+		bnds.lo[d] -= half_diff;
+		bnds.hi[d] += half_diff;
+	}
+}
+
+//----------------------------------------------------------------------
+//	annBoxDistance - utility routine which computes distance from point to
+//		box (Note: most distances to boxes are computed using incremental
+//		distance updates, not this function.)
+//----------------------------------------------------------------------
+
+ANNdist annBoxDistance(			// compute distance from point to box
+	const ANNpoint		q,				// the point
+	const ANNpoint		lo,				// low point of box
+	const ANNpoint		hi,				// high point of box
+	int					dim)			// dimension of space
+{
+	register ANNdist dist = 0.0;		// sum of squared distances
+	register ANNdist t;
+
+	for (register int d = 0; d < dim; d++) {
+		if (q[d] < lo[d]) {				// q is left of box
+			t = ANNdist(lo[d]) - ANNdist(q[d]);
+			dist = ANN_SUM(dist, ANN_POW(t));
+		}
+		else if (q[d] > hi[d]) {		// q is right of box
+			t = ANNdist(q[d]) - ANNdist(hi[d]);
+			dist = ANN_SUM(dist, ANN_POW(t));
+		}
+	}
+	ANN_FLOP(4*dim)						// increment floating op count
+
+	return dist;
+}
+
+//----------------------------------------------------------------------
+//	annSpread - find spread along given dimension
+//	annMinMax - find min and max coordinates along given dimension
+//	annMaxSpread - find dimension of max spread
+//----------------------------------------------------------------------
+
+ANNcoord annSpread(				// compute point spread along dimension
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices
+	int					n,				// number of points
+	int					d)				// dimension to check
+{
+	ANNcoord min = PA(0,d);				// compute max and min coords
+	ANNcoord max = PA(0,d);
+	for (int i = 1; i < n; i++) {
+		ANNcoord c = PA(i,d);
+		if (c < min) min = c;
+		else if (c > max) max = c;
+	}
+	return (max - min);					// total spread is difference
+}
+
+void annMinMax(					// compute min and max coordinates along dim
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices
+	int					n,				// number of points
+	int					d,				// dimension to check
+	ANNcoord			&min,			// minimum value (returned)
+	ANNcoord			&max)			// maximum value (returned)
+{
+	min = PA(0,d);						// compute max and min coords
+	max = PA(0,d);
+	for (int i = 1; i < n; i++) {
+		ANNcoord c = PA(i,d);
+		if (c < min) min = c;
+		else if (c > max) max = c;
+	}
+}
+
+int annMaxSpread(						// compute dimension of max spread
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices
+	int					n,				// number of points
+	int					dim)			// dimension of space
+{
+	int max_dim = 0;					// dimension of max spread
+	ANNcoord max_spr = 0;				// amount of max spread
+
+	if (n == 0) return max_dim;			// no points, who cares?
+
+	for (int d = 0; d < dim; d++) {		// compute spread along each dim
+		ANNcoord spr = annSpread(pa, pidx, n, d);
+		if (spr > max_spr) {			// bigger than current max
+			max_spr = spr;
+			max_dim = d;
+		}
+	}
+	return max_dim;
+}
+
+//----------------------------------------------------------------------
+//	annMedianSplit - split point array about its median
+//		Splits a subarray of points pa[0..n] about an element of given
+//		rank (median: n_lo = n/2) with respect to dimension d.  It places
+//		the element of rank n_lo-1 correctly (because our splitting rule
+//		takes the mean of these two).  On exit, the array is permuted so
+//		that:
+//
+//		pa[0..n_lo-2][d] <= pa[n_lo-1][d] <= pa[n_lo][d] <= pa[n_lo+1..n-1][d].
+//
+//		The mean of pa[n_lo-1][d] and pa[n_lo][d] is returned as the
+//		splitting value.
+//
+//		All indexing is done indirectly through the index array pidx.
+//
+//		This function uses the well known selection algorithm due to
+//		C.A.R. Hoare.
+//----------------------------------------------------------------------
+
+										// swap two points in pa array
+#define PASWAP(a,b) { int tmp = pidx[a]; pidx[a] = pidx[b]; pidx[b] = tmp; }
+
+void annMedianSplit(
+	ANNpointArray		pa,				// points to split
+	ANNidxArray			pidx,			// point indices
+	int					n,				// number of points
+	int					d,				// dimension along which to split
+	ANNcoord			&cv,			// cutting value
+	int					n_lo)			// split into n_lo and n-n_lo
+{
+	int l = 0;							// left end of current subarray
+	int r = n-1;						// right end of current subarray
+	while (l < r) {
+		register int i = (r+l)/2;		// select middle as pivot
+		register int k;
+
+		if (PA(i,d) > PA(r,d))			// make sure last > pivot
+			PASWAP(i,r)
+		PASWAP(l,i);					// move pivot to first position
+
+		ANNcoord c = PA(l,d);			// pivot value
+		i = l;
+		k = r;
+		for(;;) {						// pivot about c
+			while (PA(++i,d) < c) ;
+			while (PA(--k,d) > c) ;
+			if (i < k) PASWAP(i,k) else break;
+		}
+		PASWAP(l,k);					// pivot winds up in location k
+
+		if (k > n_lo)	   r = k-1;		// recurse on proper subarray
+		else if (k < n_lo) l = k+1;
+		else break;						// got the median exactly
+	}
+	if (n_lo > 0) {						// search for next smaller item
+		ANNcoord c = PA(0,d);			// candidate for max
+		int k = 0;						// candidate's index
+		for (int i = 1; i < n_lo; i++) {
+			if (PA(i,d) > c) {
+				c = PA(i,d);
+				k = i;
+			}
+		}
+		PASWAP(n_lo-1, k);				// max among pa[0..n_lo-1] to pa[n_lo-1]
+	}
+										// cut value is midpoint value
+	cv = (PA(n_lo-1,d) + PA(n_lo,d))/2.0;
+}
+
+//----------------------------------------------------------------------
+//	annPlaneSplit - split point array about a cutting plane
+//		Split the points in an array about a given plane along a
+//		given cutting dimension.  On exit, br1 and br2 are set so
+//		that:
+//		
+//				pa[ 0 ..br1-1] <  cv
+//				pa[br1..br2-1] == cv
+//				pa[br2.. n -1] >  cv
+//
+//		All indexing is done indirectly through the index array pidx.
+//
+//----------------------------------------------------------------------
+
+void annPlaneSplit(				// split points by a plane
+	ANNpointArray		pa,				// points to split
+	ANNidxArray			pidx,			// point indices
+	int					n,				// number of points
+	int					d,				// dimension along which to split
+	ANNcoord			cv,				// cutting value
+	int					&br1,			// first break (values < cv)
+	int					&br2)			// second break (values == cv)
+{
+	int l = 0;
+	int r = n-1;
+	for(;;) {							// partition pa[0..n-1] about cv
+		while (l < n && PA(l,d) < cv) l++;
+		while (r >= 0 && PA(r,d) >= cv) r--;
+		if (l > r) break;
+		PASWAP(l,r);
+		l++; r--;
+	}
+	br1 = l;					// now: pa[0..br1-1] < cv <= pa[br1..n-1]
+	r = n-1;
+	for(;;) {							// partition pa[br1..n-1] about cv
+		while (l < n && PA(l,d) <= cv) l++;
+		while (r >= br1 && PA(r,d) > cv) r--;
+		if (l > r) break;
+		PASWAP(l,r);
+		l++; r--;
+	}
+	br2 = l;					// now: pa[br1..br2-1] == cv < pa[br2..n-1]
+}
+
+
+//----------------------------------------------------------------------
+//	annBoxSplit - split point array about a orthogonal rectangle
+//		Split the points in an array about a given orthogonal
+//		rectangle.  On exit, n_in is set to the number of points
+//		that are inside (or on the boundary of) the rectangle.
+//
+//		All indexing is done indirectly through the index array pidx.
+//
+//----------------------------------------------------------------------
+
+void annBoxSplit(				// split points by a box
+	ANNpointArray		pa,				// points to split
+	ANNidxArray			pidx,			// point indices
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	ANNorthRect			&box,			// the box
+	int					&n_in)			// number of points inside (returned)
+{
+	int l = 0;
+	int r = n-1;
+	for(;;) {							// partition pa[0..n-1] about box
+		while (l < n && box.inside(dim, PP(l))) l++;
+		while (r >= 0 && !box.inside(dim, PP(r))) r--;
+		if (l > r) break;
+		PASWAP(l,r);
+		l++; r--;
+	}
+	n_in = l;					// now: pa[0..n_in-1] inside and rest outside
+}
+
+//----------------------------------------------------------------------
+//	annSplitBalance - compute balance factor for a given plane split
+//		Balance factor is defined as the number of points lying
+//		below the splitting value minus n/2 (median).  Thus, a
+//		median split has balance 0, left of this is negative and
+//		right of this is positive.  (The points are unchanged.)
+//----------------------------------------------------------------------
+
+int annSplitBalance(			// determine balance factor of a split
+	ANNpointArray		pa,				// points to split
+	ANNidxArray			pidx,			// point indices
+	int					n,				// number of points
+	int					d,				// dimension along which to split
+	ANNcoord			cv)				// cutting value
+{
+	int n_lo = 0;
+	for(int i = 0; i < n; i++) {		// count number less than cv
+		if (PA(i,d) < cv) n_lo++;
+	}
+	return n_lo - n/2;
+}
+
+//----------------------------------------------------------------------
+//	annBox2Bnds - convert bounding box to list of bounds
+//		Given two boxes, an inner box enclosed within a bounding
+//		box, this routine determines all the sides for which the
+//		inner box is strictly contained with the bounding box,
+//		and adds an appropriate entry to a list of bounds.  Then
+//		we allocate storage for the final list of bounds, and return
+//		the resulting list and its size.
+//----------------------------------------------------------------------
+
+void annBox2Bnds(						// convert inner box to bounds
+	const ANNorthRect	&inner_box,		// inner box
+	const ANNorthRect	&bnd_box,		// enclosing box
+	int					dim,			// dimension of space
+	int					&n_bnds,		// number of bounds (returned)
+	ANNorthHSArray		&bnds)			// bounds array (returned)
+{
+	int i;
+	n_bnds = 0;									// count number of bounds
+	for (i = 0; i < dim; i++) {
+		if (inner_box.lo[i] > bnd_box.lo[i])	// low bound is inside
+				n_bnds++;
+		if (inner_box.hi[i] < bnd_box.hi[i])	// high bound is inside
+				n_bnds++;
+	}
+
+	bnds = new ANNorthHalfSpace[n_bnds];		// allocate appropriate size
+
+	int j = 0;
+	for (i = 0; i < dim; i++) {					// fill the array
+		if (inner_box.lo[i] > bnd_box.lo[i]) {
+				bnds[j].cd = i;
+				bnds[j].cv = inner_box.lo[i];
+				bnds[j].sd = +1;
+				j++;
+		}
+		if (inner_box.hi[i] < bnd_box.hi[i]) {
+				bnds[j].cd = i;
+				bnds[j].cv = inner_box.hi[i];
+				bnds[j].sd = -1;
+				j++;
+		}
+	}
+}
+
+//----------------------------------------------------------------------
+//	annBnds2Box - convert list of bounds to bounding box
+//		Given an enclosing box and a list of bounds, this routine
+//		computes the corresponding inner box.  It is assumed that
+//		the box points have been allocated already.
+//----------------------------------------------------------------------
+
+void annBnds2Box(
+	const ANNorthRect	&bnd_box,		// enclosing box
+	int					dim,			// dimension of space
+	int					n_bnds,			// number of bounds
+	ANNorthHSArray		bnds,			// bounds array
+	ANNorthRect			&inner_box)		// inner box (returned)
+{
+	annAssignRect(dim, inner_box, bnd_box);		// copy bounding box to inner
+
+	for (int i = 0; i < n_bnds; i++) {
+		bnds[i].project(inner_box.lo);			// project each endpoint
+		bnds[i].project(inner_box.hi);
+	}
+}
diff --git a/Contrib/ANN/src/kd_util.h b/Contrib/ANN/src/kd_util.h
new file mode 100755
index 0000000..6b43430
--- /dev/null
+++ b/Contrib/ANN/src/kd_util.h
@@ -0,0 +1,124 @@
+//----------------------------------------------------------------------
+// File:			kd_util.h
+// Programmer:		Sunil Arya and David Mount
+// Description:		Common utilities for kd- trees
+// Last modified:	01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//----------------------------------------------------------------------
+
+#ifndef ANN_kd_util_H
+#define ANN_kd_util_H
+
+#include "kd_tree.h"					// kd-tree declarations
+
+//----------------------------------------------------------------------
+//	externally accessible functions
+//----------------------------------------------------------------------
+
+double annAspectRatio(			// compute aspect ratio of box
+	int					dim,			// dimension
+	const ANNorthRect	&bnd_box);		// bounding cube
+
+void annEnclRect(				// compute smallest enclosing rectangle
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices
+	int					n,				// number of points
+	int					dim,			// dimension
+	ANNorthRect &bnds);					// bounding cube (returned)
+
+void annEnclCube(				// compute smallest enclosing cube
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices
+	int					n,				// number of points
+	int					dim,			// dimension
+	ANNorthRect &bnds);					// bounding cube (returned)
+
+ANNdist annBoxDistance(			// compute distance from point to box
+	const ANNpoint		q,				// the point
+	const ANNpoint		lo,				// low point of box
+	const ANNpoint		hi,				// high point of box
+	int					dim);			// dimension of space
+
+ANNcoord annSpread(				// compute point spread along dimension
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices
+	int					n,				// number of points
+	int					d);				// dimension to check
+
+void annMinMax(					// compute min and max coordinates along dim
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices
+	int					n,				// number of points
+	int					d,				// dimension to check
+	ANNcoord&			min,			// minimum value (returned)
+	ANNcoord&			max);			// maximum value (returned)
+
+int annMaxSpread(				// compute dimension of max spread
+	ANNpointArray		pa,				// point array
+	ANNidxArray			pidx,			// point indices
+	int					n,				// number of points
+	int					dim);			// dimension of space
+
+void annMedianSplit(			// split points along median value
+	ANNpointArray		pa,				// points to split
+	ANNidxArray			pidx,			// point indices
+	int					n,				// number of points
+	int					d,				// dimension along which to split
+	ANNcoord			&cv,			// cutting value
+	int					n_lo);			// split into n_lo and n-n_lo
+
+void annPlaneSplit(				// split points by a plane
+	ANNpointArray		pa,				// points to split
+	ANNidxArray			pidx,			// point indices
+	int					n,				// number of points
+	int					d,				// dimension along which to split
+	ANNcoord			cv,				// cutting value
+	int					&br1,			// first break (values < cv)
+	int					&br2);			// second break (values == cv)
+
+void annBoxSplit(				// split points by a box
+	ANNpointArray		pa,				// points to split
+	ANNidxArray			pidx,			// point indices
+	int					n,				// number of points
+	int					dim,			// dimension of space
+	ANNorthRect			&box,			// the box
+	int					&n_in);			// number of points inside (returned)
+
+int annSplitBalance(			// determine balance factor of a split
+	ANNpointArray		pa,				// points to split
+	ANNidxArray			pidx,			// point indices
+	int					n,				// number of points
+	int					d,				// dimension along which to split
+	ANNcoord			cv);			// cutting value
+
+void annBox2Bnds(				// convert inner box to bounds
+	const ANNorthRect	&inner_box,		// inner box
+	const ANNorthRect	&bnd_box,		// enclosing box
+	int					dim,			// dimension of space
+	int					&n_bnds,		// number of bounds (returned)
+	ANNorthHSArray		&bnds);			// bounds array (returned)
+
+void annBnds2Box(				// convert bounds to inner box
+	const ANNorthRect	&bnd_box,		// enclosing box
+	int					dim,			// dimension of space
+	int					n_bnds,			// number of bounds
+	ANNorthHSArray		bnds,			// bounds array
+	ANNorthRect			&inner_box);	// inner box (returned)
+
+#endif
diff --git a/Contrib/ANN/src/perf.cpp b/Contrib/ANN/src/perf.cpp
new file mode 100755
index 0000000..91bb044
--- /dev/null
+++ b/Contrib/ANN/src/perf.cpp
@@ -0,0 +1,134 @@
+//----------------------------------------------------------------------
+// File:			perf.cpp
+// Programmer:		Sunil Arya and David Mount
+// Description:		Methods for performance stats
+// Last modified:	01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//	Revision 1.0  04/01/05
+//		Changed names to avoid namespace conflicts.
+//		Added flush after printing performance stats to fix bug
+//			in Microsoft Windows version.
+//----------------------------------------------------------------------
+
+#include <ANN/ANN.h>					// basic ANN includes
+#include <ANN/ANNperf.h>				// performance includes
+
+using namespace std;					// make std:: available
+
+//----------------------------------------------------------------------
+//	Performance statistics
+//		The following data and routines are used for computing
+//		performance statistics for nearest neighbor searching.
+//		Because these routines can slow the code down, they can be
+//		activated and deactiviated by defining the PERF variable,
+//		by compiling with the option: -DPERF
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+//	Global counters for performance measurement
+//----------------------------------------------------------------------
+
+int				ann_Ndata_pts  = 0;		// number of data points
+int				ann_Nvisit_lfs = 0;		// number of leaf nodes visited
+int				ann_Nvisit_spl = 0;		// number of splitting nodes visited
+int				ann_Nvisit_shr = 0;		// number of shrinking nodes visited
+int				ann_Nvisit_pts = 0;		// visited points for one query
+int				ann_Ncoord_hts = 0;		// coordinate hits for one query
+int				ann_Nfloat_ops = 0;		// floating ops for one query
+ANNsampStat		ann_visit_lfs;			// stats on leaf nodes visits
+ANNsampStat		ann_visit_spl;			// stats on splitting nodes visits
+ANNsampStat		ann_visit_shr;			// stats on shrinking nodes visits
+ANNsampStat		ann_visit_nds;			// stats on total nodes visits
+ANNsampStat		ann_visit_pts;			// stats on points visited
+ANNsampStat		ann_coord_hts;			// stats on coordinate hits
+ANNsampStat		ann_float_ops;			// stats on floating ops
+//
+ANNsampStat		ann_average_err;		// average error
+ANNsampStat		ann_rank_err;			// rank error
+
+//----------------------------------------------------------------------
+//	Routines for statistics.
+//----------------------------------------------------------------------
+
+DLL_API void annResetStats(int data_size) // reset stats for a set of queries
+{
+	ann_Ndata_pts  = data_size;
+	ann_visit_lfs.reset();
+	ann_visit_spl.reset();
+	ann_visit_shr.reset();
+	ann_visit_nds.reset();
+	ann_visit_pts.reset();
+	ann_coord_hts.reset();
+	ann_float_ops.reset();
+	ann_average_err.reset();
+	ann_rank_err.reset();
+}
+
+DLL_API void annResetCounts()				// reset counts for one query
+{
+	ann_Nvisit_lfs = 0;
+	ann_Nvisit_spl = 0;
+	ann_Nvisit_shr = 0;
+	ann_Nvisit_pts = 0;
+	ann_Ncoord_hts = 0;
+	ann_Nfloat_ops = 0;
+}
+
+DLL_API void annUpdateStats()				// update stats with current counts
+{
+	ann_visit_lfs += ann_Nvisit_lfs;
+	ann_visit_nds += ann_Nvisit_spl + ann_Nvisit_lfs;
+	ann_visit_spl += ann_Nvisit_spl;
+	ann_visit_shr += ann_Nvisit_shr;
+	ann_visit_pts += ann_Nvisit_pts;
+	ann_coord_hts += ann_Ncoord_hts;
+	ann_float_ops += ann_Nfloat_ops;
+}
+
+										// print a single statistic
+void print_one_stat(char *title, ANNsampStat s, double div)
+{
+	cout << title << "= [ ";
+	cout.width(9); cout << s.mean()/div			<< " : ";
+	cout.width(9); cout << s.stdDev()/div		<< " ]<";
+	cout.width(9); cout << s.min()/div			<< " , ";
+	cout.width(9); cout << s.max()/div			<< " >\n";
+}
+
+DLL_API void annPrintStats(				// print statistics for a run
+	ANNbool validate)					// true if average errors desired
+{
+	cout.precision(4);					// set floating precision
+	cout << "  (Performance stats: "
+		 << " [      mean :    stddev ]<      min ,       max >\n";
+	print_one_stat("    leaf_nodes       ", ann_visit_lfs, 1);
+	print_one_stat("    splitting_nodes  ", ann_visit_spl, 1);
+	print_one_stat("    shrinking_nodes  ", ann_visit_shr, 1);
+	print_one_stat("    total_nodes      ", ann_visit_nds, 1);
+	print_one_stat("    points_visited   ", ann_visit_pts, 1);
+	print_one_stat("    coord_hits/pt    ", ann_coord_hts, ann_Ndata_pts);
+	print_one_stat("    floating_ops_(K) ", ann_float_ops, 1000);
+	if (validate) {
+		print_one_stat("    average_error    ", ann_average_err, 1);
+		print_one_stat("    rank_error       ", ann_rank_err, 1);
+	}
+	cout.precision(0);					// restore the default
+	cout << "  )\n";
+	cout.flush();
+}
diff --git a/Contrib/ANN/src/pr_queue.h b/Contrib/ANN/src/pr_queue.h
new file mode 100755
index 0000000..3f4b75c
--- /dev/null
+++ b/Contrib/ANN/src/pr_queue.h
@@ -0,0 +1,125 @@
+//----------------------------------------------------------------------
+// File:			pr_queue.h
+// Programmer:		Sunil Arya and David Mount
+// Description:		Include file for priority queue and related
+// 					structures.
+// Last modified:	01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//----------------------------------------------------------------------
+
+#ifndef PR_QUEUE_H
+#define PR_QUEUE_H
+
+#include <ANN/ANNx.h>					// all ANN includes
+#include <ANN/ANNperf.h>				// performance evaluation
+
+//----------------------------------------------------------------------
+//	Basic types.
+//----------------------------------------------------------------------
+typedef void			*PQinfo;		// info field is generic pointer
+typedef ANNdist			PQkey;			// key field is distance
+
+//----------------------------------------------------------------------
+//	Priority queue
+//		A priority queue is a list of items, along with associated
+//		priorities.  The basic operations are insert and extract_minimum.
+//
+//		The priority queue is maintained using a standard binary heap.
+//		(Implementation note: Indexing is performed from [1..max] rather
+//		than the C standard of [0..max-1].  This simplifies parent/child
+//		computations.)  User information consists of a void pointer,
+//		and the user is responsible for casting this quantity into whatever
+//		useful form is desired.
+//
+//		Because the priority queue is so central to the efficiency of
+//		query processing, all the code is inline.
+//----------------------------------------------------------------------
+
+class ANNpr_queue {
+
+	struct pq_node {					// node in priority queue
+		PQkey			key;			// key value
+		PQinfo			info;			// info field
+	};
+	int			n;						// number of items in queue
+	int			max_size;				// maximum queue size
+	pq_node		*pq;					// the priority queue (array of nodes)
+
+public:
+	ANNpr_queue(int max)				// constructor (given max size)
+		{
+			n = 0;						// initially empty
+			max_size = max;				// maximum number of items
+			pq = new pq_node[max+1];	// queue is array [1..max] of nodes
+		}
+
+	~ANNpr_queue()						// destructor
+		{ delete [] pq; }
+
+	ANNbool empty()						// is queue empty?
+		{ if (n==0) return ANNtrue; else return ANNfalse; }
+
+	ANNbool non_empty()					// is queue nonempty?
+		{ if (n==0) return ANNfalse; else return ANNtrue; }
+
+	void reset()						// make existing queue empty
+		{ n = 0; }
+
+	inline void insert(					// insert item (inlined for speed)
+		PQkey kv,						// key value
+		PQinfo inf)						// item info
+		{
+			if (++n > max_size) annError("Priority queue overflow.", ANNabort);
+			register int r = n;
+			while (r > 1) {				// sift up new item
+				register int p = r/2;
+				ANN_FLOP(1)				// increment floating ops
+				if (pq[p].key <= kv)	// in proper order
+					break;
+				pq[r] = pq[p];			// else swap with parent
+				r = p;
+			}
+			pq[r].key = kv;				// insert new item at final location
+			pq[r].info = inf;
+		}
+
+	inline void extr_min(				// extract minimum (inlined for speed)
+		PQkey &kv,						// key (returned)
+		PQinfo &inf)					// item info (returned)
+		{
+			kv = pq[1].key;				// key of min item
+			inf = pq[1].info;			// information of min item
+			register PQkey kn = pq[n--].key;// last item in queue
+			register int p = 1;			// p points to item out of position
+			register int r = p<<1;		// left child of p
+			while (r <= n) {			// while r is still within the heap
+				ANN_FLOP(2)				// increment floating ops
+										// set r to smaller child of p
+				if (r < n  && pq[r].key > pq[r+1].key) r++;
+				if (kn <= pq[r].key)	// in proper order
+					break;
+				pq[p] = pq[r];			// else swap with child
+				p = r;					// advance pointers
+				r = p<<1;
+			}
+			pq[p] = pq[n+1];			// insert last item in proper place
+		}
+};
+
+#endif
diff --git a/Contrib/ANN/src/pr_queue_k.h b/Contrib/ANN/src/pr_queue_k.h
new file mode 100755
index 0000000..c2f01c3
--- /dev/null
+++ b/Contrib/ANN/src/pr_queue_k.h
@@ -0,0 +1,118 @@
+//----------------------------------------------------------------------
+// File:			pr_queue_k.h
+// Programmer:		Sunil Arya and David Mount
+// Description:		Include file for priority queue with k items.
+// Last modified:	01/04/05 (Version 1.0)
+//----------------------------------------------------------------------
+// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
+// David Mount.  All Rights Reserved.
+// 
+// This software and related documentation is part of the Approximate
+// Nearest Neighbor Library (ANN).  This software is provided under
+// the provisions of the Lesser GNU Public License (LGPL).  See the
+// file ../ReadMe.txt for further information.
+// 
+// The University of Maryland (U.M.) and the authors make no
+// representations about the suitability or fitness of this software for
+// any purpose.  It is provided "as is" without express or implied
+// warranty.
+//----------------------------------------------------------------------
+// History:
+//	Revision 0.1  03/04/98
+//		Initial release
+//----------------------------------------------------------------------
+
+#ifndef PR_QUEUE_K_H
+#define PR_QUEUE_K_H
+
+#include <ANN/ANNx.h>					// all ANN includes
+#include <ANN/ANNperf.h>				// performance evaluation
+
+//----------------------------------------------------------------------
+//	Basic types
+//----------------------------------------------------------------------
+typedef ANNdist			PQKkey;			// key field is distance
+typedef int				PQKinfo;		// info field is int
+
+//----------------------------------------------------------------------
+//	Constants
+//		The NULL key value is used to initialize the priority queue, and
+//		so it should be larger than any valid distance, so that it will
+//		be replaced as legal distance values are inserted.  The NULL
+//		info value must be a nonvalid array index, we use ANN_NULL_IDX,
+//		which is guaranteed to be negative.
+//----------------------------------------------------------------------
+
+const PQKkey	PQ_NULL_KEY  =  ANN_DIST_INF;	// nonexistent key value
+const PQKinfo	PQ_NULL_INFO =  ANN_NULL_IDX;	// nonexistent info value
+
+//----------------------------------------------------------------------
+//	ANNmin_k
+//		An ANNmin_k structure is one which maintains the smallest
+//		k values (of type PQKkey) and associated information (of type
+//		PQKinfo).  The special info and key values PQ_NULL_INFO and
+//		PQ_NULL_KEY means that thise entry is empty.
+//
+//		It is currently implemented using an array with k items.
+//		Items are stored in increasing sorted order, and insertions
+//		are made through standard insertion sort.  (This is quite
+//		inefficient, but current applications call for small values
+//		of k and relatively few insertions.)
+//		
+//		Note that the list contains k+1 entries, but the last entry
+//		is used as a simple placeholder and is otherwise ignored.
+//----------------------------------------------------------------------
+
+class ANNmin_k {
+	struct mk_node {					// node in min_k structure
+		PQKkey			key;			// key value
+		PQKinfo			info;			// info field (user defined)
+	};
+
+	int			k;						// max number of keys to store
+	int			n;						// number of keys currently active
+	mk_node		*mk;					// the list itself
+
+public:
+	ANNmin_k(int max)					// constructor (given max size)
+		{
+			n = 0;						// initially no items
+			k = max;					// maximum number of items
+			mk = new mk_node[max+1];	// sorted array of keys
+		}
+
+	~ANNmin_k()							// destructor
+		{ delete [] mk; }
+	
+	PQKkey ANNmin_key()					// return minimum key
+		{ return (n > 0 ? mk[0].key : PQ_NULL_KEY); }
+	
+	PQKkey max_key()					// return maximum key
+		{ return (n == k ? mk[k-1].key : PQ_NULL_KEY); }
+	
+	PQKkey ith_smallest_key(int i)		// ith smallest key (i in [0..n-1])
+		{ return (i < n ? mk[i].key : PQ_NULL_KEY); }
+	
+	PQKinfo ith_smallest_info(int i)	// info for ith smallest (i in [0..n-1])
+		{ return (i < n ? mk[i].info : PQ_NULL_INFO); }
+
+	inline void insert(					// insert item (inlined for speed)
+		PQKkey kv,						// key value
+		PQKinfo inf)					// item info
+		{
+			register int i;
+										// slide larger values up
+			for (i = n; i > 0; i--) {
+				if (mk[i-1].key > kv)
+					mk[i] = mk[i-1];
+				else
+					break;
+			}
+			mk[i].key = kv;				// store element here
+			mk[i].info = inf;
+			if (n < k) n++;				// increment number of items
+			ANN_FLOP(k-i+1)				// increment floating ops
+		}
+};
+
+#endif
diff --git a/Contrib/gmm/gmm.h b/Contrib/gmm/gmm.h
new file mode 100755
index 0000000..c6bd391
--- /dev/null
+++ b/Contrib/gmm/gmm.h
@@ -0,0 +1,53 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 13, 2002.
+   @brief Include common gmm files.
+*/
+#ifndef GMM_H__
+#define GMM_H__
+
+#include "gmm_kernel.h"
+#include "gmm_dense_lu.h"
+#include "gmm_dense_qr.h"
+
+#include "gmm_iter_solvers.h"
+#include "gmm_condition_number.h"
+#include "gmm_inoutput.h"
+
+#include "gmm_lapack_interface.h"
+#include "gmm_superlu_interface.h"
+
+
+#include "gmm_domain_decomp.h"
+
+#endif //  GMM_H__
diff --git a/Contrib/gmm/gmm_MUMPS_interface.h b/Contrib/gmm/gmm_MUMPS_interface.h
new file mode 100755
index 0000000..a7c1401
--- /dev/null
+++ b/Contrib/gmm/gmm_MUMPS_interface.h
@@ -0,0 +1,306 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_MUMPS_interface.h
+   @author Yves Renard <Yves.Renard at insa-lyon.fr>,
+   @author Julien Pommier <Julien.Pommier at insa-toulouse.fr>
+   @date December 8, 2005.
+   @brief Interface with MUMPS (LU direct solver for sparse matrices).
+*/
+#if defined(GMM_USES_MUMPS)
+
+#ifndef GMM_MUMPS_INTERFACE_H
+#define GMM_MUMPS_INTERFACE_H
+
+#include "gmm_kernel.h"
+
+
+extern "C" {
+
+#include <smumps_c.h>
+#undef F_INT
+#undef F_DOUBLE
+#undef F_DOUBLE2
+#include <dmumps_c.h>
+#undef F_INT
+#undef F_DOUBLE
+#undef F_DOUBLE2
+#include <cmumps_c.h>
+#undef F_INT
+#undef F_DOUBLE
+#undef F_DOUBLE2
+#include <zmumps_c.h>
+#undef F_INT
+#undef F_DOUBLE
+#undef F_DOUBLE2
+
+}
+
+namespace gmm {
+
+  template <typename T> struct ij_sparse_matrix {
+    std::vector<int> irn;
+    std::vector<int> jcn;
+    std::vector<T>        a;
+    
+    template <typename L> void store(const L& l, size_type i) {
+       typename linalg_traits<L>::const_iterator it = vect_const_begin(l),
+	 ite = vect_const_end(l);
+       for (; it != ite; ++it)
+	 { irn.push_back(i + 1); jcn.push_back(it.index() + 1); a.push_back(*it); }
+    }
+
+    template <typename L> void build_from(const L& l, row_major) {
+      for (size_type i = 0; i < mat_nrows(l); ++i)
+	store(mat_const_row(l, i), i);
+    }
+
+    template <typename L> void build_from(const L& l, col_major) {
+      for (size_type i = 0; i < mat_ncols(l); ++i)
+	store(mat_const_col(l, i), i);
+      irn.swap(jcn);
+    }
+
+    template <typename L> ij_sparse_matrix(const L& A) {
+      size_type nz = nnz(A);
+      irn.reserve(nz); jcn.reserve(nz); a.reserve(nz);
+      build_from(A,  typename principal_orientation_type<typename
+	       linalg_traits<L>::sub_orientation>::potype());
+    }
+  };
+
+  /* ********************************************************************* */
+  /*   MUMPS solve interface                                               */
+  /* ********************************************************************* */
+
+
+  template <typename T> struct mumps_interf {};
+
+  template <> struct mumps_interf<float> {
+    typedef SMUMPS_STRUC_C  MUMPS_STRUC_C;
+    typedef float value_type;
+
+    static void mumps_c(MUMPS_STRUC_C &id) { smumps_c(&id); }
+  };
+
+  template <> struct mumps_interf<double> {
+    typedef DMUMPS_STRUC_C  MUMPS_STRUC_C;
+    typedef double value_type;
+    static void mumps_c(MUMPS_STRUC_C &id) { dmumps_c(&id); }
+  };
+
+  template <> struct mumps_interf<std::complex<float> > {
+    typedef CMUMPS_STRUC_C  MUMPS_STRUC_C;
+    typedef mumps_complex value_type;
+    static void mumps_c(MUMPS_STRUC_C &id) { cmumps_c(&id); }
+  };
+
+  template <> struct mumps_interf<std::complex<double> > {
+    typedef ZMUMPS_STRUC_C  MUMPS_STRUC_C;
+    typedef mumps_double_complex value_type;
+    static void mumps_c(MUMPS_STRUC_C &id) { zmumps_c(&id); }
+  };
+
+
+  /** MUMPS solve interface  
+   *  Works only with sparse or skyline matrices
+   */
+  template <typename MAT, typename VECTX, typename VECTB>
+  void MUMPS_solve(const MAT &A, const VECTX &X_, const VECTB &B) {
+    VECTX &X = const_cast<VECTX &>(X_);
+
+    typedef typename linalg_traits<MAT>::value_type T;
+    typedef typename mumps_interf<T>::value_type MUMPS_T;
+    GMM_ASSERT2(gmm::mat_nrows(A) == gmm::mat_ncols(A), "Non square matrix");
+  
+    std::vector<T> rhs(gmm::vect_size(B)); gmm::copy(B, rhs);
+  
+    ij_sparse_matrix<T> AA(A);
+  
+    const int JOB_INIT = -1;
+    const int JOB_END = -2;
+    const int USE_COMM_WORLD = -987654;
+
+    typename mumps_interf<T>::MUMPS_STRUC_C id;
+
+#ifdef GMM_USES_MPI
+    int rank;
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+#endif
+    
+    id.job = JOB_INIT;
+    id.par = 1;
+    id.sym = 0;
+    id.comm_fortran = USE_COMM_WORLD;
+    mumps_interf<T>::mumps_c(id);
+    
+#ifdef GMM_USES_MPI
+    if (rank == 0) {
+#endif
+      id.n = gmm::mat_nrows(A);
+      id.nz = AA.irn.size();
+      id.irn = &(AA.irn[0]);
+      id.jcn = &(AA.jcn[0]);
+      id.a = (MUMPS_T*)(&(AA.a[0]));
+      id.rhs = (MUMPS_T*)(&(rhs[0]));
+#ifdef GMM_USES_MPI
+    }
+#endif
+
+#define ICNTL(I) icntl[(I)-1]
+#define INFO(I) info[(I)-1]
+    id.ICNTL(1) = -1; id.ICNTL(2) = -1; id.ICNTL(3) = -1; id.ICNTL(4) = 0;
+    id.job = 6;
+    
+    id.ICNTL(14) += 40; /* small boost to the workspace size as we have encountered some problem
+			   who did not fit in the default settings of mumps.. 
+			   by default, ICNTL(14) = 15 or 20
+		       */
+    //cout << "ICNTL(14): " << id.ICNTL(14) << "\n";
+
+    mumps_interf<T>::mumps_c(id);
+    if (id.INFO(1) < 0) {
+      switch (id.INFO(1)) {
+	case -6 : case -10 :
+	  GMM_ASSERT1(false, "Solve with MUMPS failed: matrix is singular");
+	case -13 :
+	  GMM_ASSERT1(false, "Solve with MUMPS failed: not enough memory");
+        case -9:
+	  GMM_ASSERT1(false, "Solve with MUMPS failed: error " << id.INFO(1)
+		      << ", increase ICNTL(14)");
+	default :
+	  GMM_ASSERT1(false, "Solve with MUMPS failed with error "
+		      << id.INFO(1));
+      }
+    }
+
+    id.job = JOB_END;
+    mumps_interf<T>::mumps_c(id);
+
+    gmm::copy(rhs, X);
+
+#undef ICNTL
+#undef INFO
+
+  }
+
+
+
+  /** MUMPS solve interface for distributed matrices 
+   *  Works only with sparse or skyline matrices
+   */
+  template <typename MAT, typename VECTX, typename VECTB>
+  void MUMPS_distributed_matrix_solve(const MAT &A, const VECTX &X_,
+				      const VECTB &B) {
+    VECTX &X = const_cast<VECTX &>(X_);
+
+    typedef typename linalg_traits<MAT>::value_type T;
+    typedef typename mumps_interf<T>::value_type MUMPS_T;
+    GMM_ASSERT2(gmm::mat_nrows(A) == gmm::mat_ncols(A), "Non-square matrix");
+  
+    std::vector<T> rhs(gmm::vect_size(B)); gmm::copy(B, rhs);
+  
+    ij_sparse_matrix<T> AA(A);
+  
+    const int JOB_INIT = -1;
+    const int JOB_END = -2;
+    const int USE_COMM_WORLD = -987654;
+
+    typename mumps_interf<T>::MUMPS_STRUC_C id;
+
+#ifdef GMM_USES_MPI
+    int rank;
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+#endif
+    
+    id.job = JOB_INIT;
+    id.par = 1;
+    id.sym = 0;
+    id.comm_fortran = USE_COMM_WORLD;
+    mumps_interf<T>::mumps_c(id);
+    
+    id.n = gmm::mat_nrows(A);
+    id.nz_loc = AA.irn.size();
+    id.irn_loc = &(AA.irn[0]);
+    id.jcn_loc = &(AA.jcn[0]);
+    id.a_loc = (MUMPS_T*)(&(AA.a[0]));
+
+#ifdef GMM_USES_MPI
+    if (rank == 0) {
+#endif
+      id.rhs = (MUMPS_T*)(&(rhs[0]));
+#ifdef GMM_USES_MPI
+    }
+#endif
+
+#define ICNTL(I) icntl[(I)-1]
+#define INFO(I) info[(I)-1]
+    id.ICNTL(1) = -1; id.ICNTL(2) = 6; // id.ICNTL(2) = -1;
+    id.ICNTL(3) = 6;
+    // id.ICNTL(3) = -1; 
+    id.ICNTL(4) = 2;
+    id.ICNTL(5)=0; id.ICNTL(18)=3;
+    id.job = 6;
+    mumps_interf<T>::mumps_c(id);
+    if (id.INFO(1) < 0) {
+      switch (id.INFO(1)) {
+      case -6 : case -10 :
+	GMM_ASSERT1(false, "Solve with MUMPS failed: matrix is singular");
+      case -13:
+	GMM_ASSERT1(false, "Solve with MUMPS failed: not enough memory");
+      case -9:
+	GMM_ASSERT1(false, "Solve with MUMPS failed: error " << id.INFO(1)
+		    << ", increase ICNTL(14)");
+      default :
+	GMM_ASSERT1(false, "Solve with MUMPS failed with error " <<id.INFO(1));
+      }
+    }
+
+    id.job = JOB_END;
+    mumps_interf<T>::mumps_c(id);
+#ifdef GMM_USES_MPI
+    MPI_Bcast(&(rhs[0]),id.n,gmm::mpi_type(T()),0,MPI_COMM_WORLD);
+#endif
+    gmm::copy(rhs, X);
+
+#undef ICNTL
+#undef INFO
+
+  }
+
+
+
+
+}
+
+  
+#endif // GMM_MUMPS_INTERFACE_H
+
+#endif // GMM_USES_MUMPS
diff --git a/Contrib/gmm/gmm_algobase.h b/Contrib/gmm/gmm_algobase.h
new file mode 100755
index 0000000..1b72ac2
--- /dev/null
+++ b/Contrib/gmm/gmm_algobase.h
@@ -0,0 +1,225 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2000-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/** @file gmm_algobase.h 
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date September 28, 2000.
+    @brief Miscelleanous algorithms on containers.
+*/
+
+#ifndef GMM_ALGOBASE_H__
+#define GMM_ALGOBASE_H__
+#include "gmm_std.h"
+#include "gmm_except.h"
+#include <functional>
+
+namespace gmm {
+
+  /* ********************************************************************* */
+  /* Definitition de classes de comparaison.                               */
+  /* retournant un int.                                                    */
+  /* ********************************************************************* */
+  
+  template <class T>
+    struct less : public std::binary_function<T, T, int> {
+    inline int operator()(const T& x, const T& y) const
+    { return (x < y) ? -1 : ((y < x) ? 1 : 0); }
+  };
+
+  template<> struct less<int> : public std::binary_function<int, int, int>
+  { int operator()(int x, int y) const { return x-y; } };
+  template<> struct less<char> : public std::binary_function<char, char, int>
+  { int operator()(char x, char y) const { return int(x-y); } };
+  template<> struct less<short> : public std::binary_function<short,short,int>
+  { int operator()(short x, short y) const { return int(x-y); } };
+  template<> struct less<unsigned char>
+     : public std::binary_function<unsigned char, unsigned char, int> {
+    int operator()(unsigned char x, unsigned char y) const
+    { return int(x)-int(y); }
+  };
+  
+
+  template <class T>
+    struct greater : public std::binary_function<T, T, int> {
+    inline int operator()(const T& x, const T& y) const
+    { return (y < x) ? -1 : ((x < y) ? 1 : 0); }
+  };
+
+  template<> struct greater<int> : public std::binary_function<int, int, int>
+  { int operator()(int x, int y) const { return y-x; } };
+  template<> struct greater<char> : public std::binary_function<char,char,int>
+  { int operator()(char x, char y) const { return int(y-x); } };
+  template<> struct greater<short>
+      : public std::binary_function<short, short, int>
+  { int operator()(short x, short y) const { return int(y-x); } };
+  template<> struct greater<unsigned char>
+    : public std::binary_function<unsigned char, unsigned char, int> {
+    int operator()(unsigned char x, unsigned char y) const
+      { return int(y)-int(x); }
+  };
+
+  template <typename T> inline T my_abs(T a) { return (a < T(0)) ? T(-a) : a; }
+  
+  template <class T>
+    struct approx_less : public std::binary_function<T, T, int> { 
+    double eps;
+    inline int operator()(const T &x, const T &y) const
+    { if (my_abs(x - y) <= eps) return 0; if (x < y) return -1; return 1; }
+    approx_less(double e = 1E-13) { eps = e; }
+  };
+
+  template <class T>
+    struct approx_greater : public std::binary_function<T, T, int> { 
+    double eps;
+    inline int operator()(const T &x, const T &y) const
+    { if (my_abs(x - y) <= eps) return 0; if (x > y) return -1; return 1; }
+    approx_greater(double e = 1E-13) { eps = e; }
+  };
+
+  template<class ITER1, class ITER2, class COMP>
+    int lexicographical_compare(ITER1 b1, const ITER1 &e1,
+				ITER2 b2, const ITER2 &e2, const COMP &c)  {
+    int i;
+    for ( ; b1 != e1 && b2 != e2; ++b1, ++b2)
+      if ((i = c(*b1, *b2)) != 0) return i;
+    if (b1 != e1) return 1; if (b2 != e2) return -1; return 0; 
+  }
+
+  template<class CONT, class COMP = gmm::less<typename CONT::value_type> >
+    struct lexicographical_less : public std::binary_function<CONT, CONT, int>
+  { 
+    COMP c;
+    int operator()(const CONT &x, const CONT &y) const {
+      return gmm::lexicographical_compare(x.begin(), x.end(),
+					  y.begin(), y.end(), c);
+    }
+    lexicographical_less(const COMP &d = COMP()) { c = d; }
+  };
+
+  template<class CONT, class COMP = gmm::less<typename CONT::value_type> >
+  struct lexicographical_greater
+    : public std::binary_function<CONT, CONT, int> { 
+    COMP c;
+    int operator()(const CONT &x, const CONT &y) const {
+      return -gmm::lexicographical_compare(x.begin(), x.end(),
+					   y.begin(), y.end(), c);
+    }
+    lexicographical_greater(const COMP &d = COMP()) { c = d; }
+  };
+  
+
+  /* ********************************************************************* */
+  /* "Virtual" iterators on sequences.                                     */
+  /* The class T represent a class of sequence.                            */
+  /* ********************************************************************* */
+
+  template<class T> struct sequence_iterator {
+    
+    typedef T             value_type;
+    typedef value_type*   pointer;
+    typedef value_type&   reference;
+    typedef const value_type& const_reference;
+    typedef std::forward_iterator_tag iterator_category;
+
+    T Un;
+
+    sequence_iterator(T U0 = T(0)) { Un = U0; }
+    
+    sequence_iterator &operator ++()
+    { ++Un; return *this; }
+    sequence_iterator operator ++(int)
+    { sequence_iterator tmp = *this; (*this)++; return tmp; }
+	
+    const_reference operator *() const { return Un; }
+    reference operator *() { return Un; }
+    
+    bool operator ==(const sequence_iterator &i) const { return (i.Un==Un);}
+    bool operator !=(const sequence_iterator &i) const { return (i.Un!=Un);}
+  };
+
+  /* ********************************************************************* */
+  /* generic algorithms.                                                   */
+  /* ********************************************************************* */
+
+  template <class ITER1, class SIZE, class ITER2>
+  ITER2 copy_n(ITER1 first, SIZE count, ITER2 result) {
+    for ( ; count > 0; --count, ++first, ++result) *result = *first;
+    return result;
+  }
+
+  template<class ITER>
+    typename std::iterator_traits<ITER>::value_type
+      mean_value(ITER first, const ITER &last) {
+    GMM_ASSERT2(first != last, "mean value of empty container");
+    size_t n = 1;
+    typename std::iterator_traits<ITER>::value_type res = *first++;
+    while (first != last) { res += *first; ++first; ++n; }
+    res /= n;
+    return res;
+  }
+
+  template<class CONT>
+    typename CONT::value_type
+  mean_value(const CONT &c) { return mean_value(c.begin(), c.end()); }
+
+  template<class ITER> /* hum ... */
+    void minmax_box(typename std::iterator_traits<ITER>::value_type &pmin,
+		    typename std::iterator_traits<ITER>::value_type &pmax,
+		    ITER first, const ITER &last) {
+    typedef typename std::iterator_traits<ITER>::value_type PT;
+    if (first != last) { pmin = pmax = *first; ++first; }
+    while (first != last) {
+      typename PT::const_iterator b = (*first).begin(), e = (*first).end();
+      typename PT::iterator b1 = pmin.begin(), b2 = pmax.begin();
+      while (b != e)
+	{ *b1 = std::min(*b1, *b); *b2 = std::max(*b2, *b); ++b; ++b1; ++b2; }
+    }
+  }
+
+  template<typename VEC> struct sorted_indexes_aux {
+    const VEC &v;
+  public:
+    sorted_indexes_aux(const VEC& v_) : v(v_) {}
+    template <typename IDX>
+    bool operator()(const IDX &ia, const IDX &ib) const
+    { return v[ia] < v[ib]; }
+  };
+
+  template<typename VEC, typename IVEC> 
+  void sorted_indexes(const VEC &v, IVEC &iv) {
+    iv.clear(); iv.resize(v.size());
+    for (size_t i=0; i < v.size(); ++i) iv[i] = i;
+    std::sort(iv.begin(), iv.end(), sorted_indexes_aux<VEC>(v));
+  }
+
+}
+
+
+#endif /* GMM_ALGOBASE_H__ */
diff --git a/Contrib/gmm/gmm_blas.h b/Contrib/gmm/gmm_blas.h
new file mode 100755
index 0000000..31c76cc
--- /dev/null
+++ b/Contrib/gmm/gmm_blas.h
@@ -0,0 +1,2282 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_blas.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 13, 2002.
+   @brief Basic linear algebra functions.
+*/
+
+#ifndef GMM_BLAS_H__
+#define GMM_BLAS_H__
+
+#include "gmm_scaled.h"
+#include "gmm_transposed.h"
+#include "gmm_conjugated.h"
+
+namespace gmm {
+
+  /* ******************************************************************** */
+  /*		                                         		  */
+  /*		Generic algorithms                           		  */
+  /*		                                         		  */
+  /* ******************************************************************** */
+
+
+  /* ******************************************************************** */
+  /*		Miscellaneous                           		  */
+  /* ******************************************************************** */
+
+  /** clear (fill with zeros) a vector or matrix. */
+  template <typename L> inline void clear(L &l)
+  { linalg_traits<L>::do_clear(l); }
+  /** @cond DOXY_SHOW_ALL_FUNCTIONS 
+      skip all these redundant definitions in doxygen documentation..
+   */
+  template <typename L> inline void clear(const L &l)
+  { linalg_traits<L>::do_clear(linalg_const_cast(l)); }
+
+  ///@endcond
+  /** count the number of non-zero entries of a vector or matrix. */  template <typename L> inline size_type nnz(const L& l)
+  { return nnz(l, typename linalg_traits<L>::linalg_type()); }
+
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+  template <typename L> inline size_type nnz(const L& l, abstract_vector) { 
+    typename linalg_traits<L>::const_iterator it = vect_const_begin(l),
+      ite = vect_const_end(l);
+    size_type res(0);
+    for (; it != ite; ++it) ++res;
+    return res;
+  }
+
+  template <typename L> inline size_type nnz(const L& l, abstract_matrix) {
+    return nnz(l,  typename principal_orientation_type<typename
+	       linalg_traits<L>::sub_orientation>::potype());
+  }
+
+  template <typename L> inline size_type nnz(const L& l, row_major) {
+    size_type res(0);
+    for (size_type i = 0; i < mat_nrows(l); ++i)
+      res += nnz(mat_const_row(l, i));
+    return res;
+  } 
+
+  template <typename L> inline size_type nnz(const L& l, col_major) {
+    size_type res(0);
+    for (size_type i = 0; i < mat_ncols(l); ++i)
+      res += nnz(mat_const_col(l, i));
+    return res;
+  }
+
+  ///@endcond
+
+
+  /** fill a vector or matrix with x. */
+  template <typename L> inline
+  void fill(L& l, typename gmm::linalg_traits<L>::value_type x) {
+    typedef typename gmm::linalg_traits<L>::value_type T;
+    if (x == T(0)) gmm::clear(l);
+    fill(l, x, typename linalg_traits<L>::linalg_type());
+  }
+
+  template <typename L> inline
+  void fill(const L& l, typename gmm::linalg_traits<L>::value_type x) {
+    fill(linalg_const_cast(l), x);
+  }
+
+  template <typename L> inline // to be optimized for dense vectors ...
+  void fill(L& l,  typename gmm::linalg_traits<L>::value_type x,
+		   abstract_vector) {
+    for (size_type i = 0; i < vect_size(l); ++i) l[i] = x;
+  }
+
+  template <typename L> inline // to be optimized for dense matrices ...
+  void fill(L& l, typename gmm::linalg_traits<L>::value_type x,
+		   abstract_matrix) {
+    for (size_type i = 0; i < mat_nrows(l); ++i)
+      for (size_type j = 0; j < mat_ncols(l); ++j)
+	l(i,j) = x;
+  }
+
+  /** fill a vector or matrix with random value (uniform [0,1]). */
+  template <typename L> inline void fill_random(L& l)
+  { fill_random(l, typename linalg_traits<L>::linalg_type()); }
+
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+  template <typename L> inline void fill_random(const L& l) {
+    fill_random(linalg_const_cast(l),
+		typename linalg_traits<L>::linalg_type());
+  }
+
+  template <typename L> inline void fill_random(L& l, abstract_vector) {
+    for (size_type i = 0; i < vect_size(l); ++i)
+      l[i] = gmm::random(typename linalg_traits<L>::value_type());
+  }
+
+  template <typename L> inline void fill_random(L& l, abstract_matrix) {
+    for (size_type i = 0; i < mat_nrows(l); ++i)
+      for (size_type j = 0; j < mat_ncols(l); ++j)
+	l(i,j) = gmm::random(typename linalg_traits<L>::value_type());
+  }
+
+  ///@endcond
+  /** fill a vector or matrix with random value.
+      @param l a vector or matrix.
+      @param cfill probability of a non-zero value.
+  */
+  template <typename L> inline void fill_random(L& l, double cfill)
+  { fill_random(l, cfill, typename linalg_traits<L>::linalg_type()); }
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+  template <typename L> inline void fill_random(const L& l, double cfill) {
+    fill_random(linalg_const_cast(l), cfill,
+		typename linalg_traits<L>::linalg_type());
+  }
+
+  template <typename L> inline
+  void fill_random(L& l, double cfill, abstract_vector) {
+    typedef typename linalg_traits<L>::value_type T;
+    size_type ntot = std::min(vect_size(l), size_type(vect_size(l)*cfill) + 1);
+    for (size_type nb = 0; nb < ntot;) {
+      size_type i = gmm::irandom(vect_size(l));
+      if (l[i] == T(0)) { 
+	l[i] = gmm::random(typename linalg_traits<L>::value_type());
+	++nb;
+      }
+    }
+  }
+
+  template <typename L> inline
+  void fill_random(L& l, double cfill, abstract_matrix) {
+    fill_random(l, cfill, typename principal_orientation_type<typename
+		linalg_traits<L>::sub_orientation>::potype());
+  }
+
+  template <typename L> inline
+  void fill_random(L& l, double cfill, row_major) {
+    for (size_type i=0; i < mat_nrows(l); ++i) fill_random(mat_row(l,i),cfill);
+  }
+
+  template <typename L> inline
+  void fill_random(L& l, double cfill, col_major) {
+    for (size_type j=0; j < mat_ncols(l); ++j) fill_random(mat_col(l,j),cfill);
+  }
+
+  /* resize a vector */
+  template <typename V> inline
+  void resize(V &v, size_type n, linalg_false)
+  { linalg_traits<V>::resize(v, n); }
+
+  template <typename V> inline
+  void resize(V &, size_type , linalg_modifiable)
+  { GMM_ASSERT1(false, "You cannot resize a reference"); }
+
+  template <typename V> inline
+  void resize(V &, size_type , linalg_const)
+  { GMM_ASSERT1(false, "You cannot resize a reference"); }
+
+  ///@endcond
+  /** resize a vector. */
+   template <typename V> inline
+  void resize(V &v, size_type n) {
+    resize(v, n, typename linalg_traits<V>::is_reference());
+  }
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+  /** resize a matrix **/
+  template <typename M> inline
+  void resize(M &v, size_type m, size_type n, linalg_false) {
+    linalg_traits<M>::resize(v, m, n);
+  }
+
+  template <typename M> inline
+  void resize(M &, size_type, size_type, linalg_modifiable)
+  { GMM_ASSERT1(false, "You cannot resize a reference"); }
+
+  template <typename M> inline
+  void resize(M &, size_type, size_type, linalg_const)
+  { GMM_ASSERT1(false, "You cannot resize a reference"); }
+
+  ///@endcond 
+  /** resize a matrix */
+  template <typename M> inline
+  void resize(M &v, size_type m, size_type n)
+  { resize(v, m, n, typename linalg_traits<M>::is_reference()); }
+  ///@cond
+
+  template <typename M> inline
+  void reshape(M &v, size_type m, size_type n, linalg_false)
+  { linalg_traits<M>::reshape(v, m, n); }
+
+  template <typename M> inline
+  void reshape(M &, size_type, size_type, linalg_modifiable)
+  { GMM_ASSERT1(false, "You cannot reshape a reference"); }
+
+  template <typename M> inline
+  void reshape(M &, size_type, size_type, linalg_const)
+  { GMM_ASSERT1(false, "You cannot reshape a reference"); }
+
+  ///@endcond 
+  /** reshape a matrix */
+  template <typename M> inline
+  void reshape(M &v, size_type m, size_type n)
+  { reshape(v, m, n, typename linalg_traits<M>::is_reference()); }
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+  
+
+  /* ******************************************************************** */
+  /*		Scalar product                             		  */
+  /* ******************************************************************** */
+
+  ///@endcond
+  /** scalar product between two vectors */
+  template <typename V1, typename V2> inline
+  typename strongest_value_type<V1,V2>::value_type
+    vect_sp(const V1 &v1, const V2 &v2) {
+    GMM_ASSERT2(vect_size(v1) == vect_size(v2), "dimensions mismatch");
+    return vect_sp(v1, v2,
+		   typename linalg_traits<V1>::storage_type(), 
+		   typename linalg_traits<V2>::storage_type());
+  }
+
+  /** scalar product between two vectors, using a matrix.
+      @param ps the matrix of the scalar product.
+      @param v1 the first vector
+      @param v2 the second vector
+  */
+  template <typename MATSP, typename V1, typename V2> inline
+  typename strongest_value_type3<V1,V2,MATSP>::value_type
+    vect_sp(const MATSP &ps, const V1 &v1, const V2 &v2) {
+    return vect_sp_with_mat(ps, v1, v2,
+			    typename linalg_traits<MATSP>::sub_orientation());
+  }
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+  template <typename MATSP, typename V1, typename V2> inline
+    typename strongest_value_type3<V1,V2,MATSP>::value_type
+    vect_sp_with_mat(const MATSP &ps, const V1 &v1, const V2 &v2, row_major) {
+    return vect_sp_with_matr(ps, v1, v2, 
+			     typename linalg_traits<V2>::storage_type());
+  }
+
+  template <typename MATSP, typename V1, typename V2> inline 
+    typename strongest_value_type3<V1,V2,MATSP>::value_type
+    vect_sp_with_matr(const MATSP &ps, const V1 &v1, const V2 &v2,
+		      abstract_sparse) {
+    GMM_ASSERT2(vect_size(v1) == mat_ncols(ps) &&
+		vect_size(v2) == mat_nrows(ps), "dimensions mismatch");
+    size_type nr = mat_nrows(ps);
+    typename linalg_traits<V2>::const_iterator
+      it = vect_const_begin(v2), ite = vect_const_end(v2);
+    typename strongest_value_type3<V1,V2,MATSP>::value_type res(0);
+    for (; it != ite; ++it)
+      res += vect_sp(mat_const_row(ps, it.index()), v1)* (*it);
+    return res;
+  }
+
+  template <typename MATSP, typename V1, typename V2> inline
+    typename strongest_value_type3<V1,V2,MATSP>::value_type
+    vect_sp_with_matr(const MATSP &ps, const V1 &v1, const V2 &v2,
+		      abstract_skyline)
+  { return vect_sp_with_matr(ps, v1, v2, abstract_sparse()); }
+
+  template <typename MATSP, typename V1, typename V2> inline
+    typename strongest_value_type3<V1,V2,MATSP>::value_type
+    vect_sp_with_matr(const MATSP &ps, const V1 &v1, const V2 &v2,
+		      abstract_dense) {
+    GMM_ASSERT2(vect_size(v1) == mat_ncols(ps) &&
+		vect_size(v2) == mat_nrows(ps), "dimensions mismatch");
+    typename linalg_traits<V2>::const_iterator
+      it = vect_const_begin(v2), ite = vect_const_end(v2);
+    typename strongest_value_type3<V1,V2,MATSP>::value_type res(0);
+    for (size_type i = 0; it != ite; ++i, ++it)
+      res += vect_sp(mat_const_row(ps, i), v1) * (*it);
+    return res;
+  }
+
+  template <typename MATSP, typename V1, typename V2> inline
+  typename strongest_value_type3<V1,V2,MATSP>::value_type
+  vect_sp_with_mat(const MATSP &ps, const V1 &v1,const V2 &v2,row_and_col)
+  { return vect_sp_with_mat(ps, v1, v2, row_major()); }
+
+  template <typename MATSP, typename V1, typename V2> inline
+  typename strongest_value_type3<V1,V2,MATSP>::value_type
+  vect_sp_with_mat(const MATSP &ps, const V1 &v1, const V2 &v2,col_major){
+    return vect_sp_with_matc(ps, v1, v2,
+			     typename linalg_traits<V1>::storage_type());
+  }
+
+  template <typename MATSP, typename V1, typename V2> inline
+    typename strongest_value_type3<V1,V2,MATSP>::value_type
+    vect_sp_with_matc(const MATSP &ps, const V1 &v1, const V2 &v2,
+		      abstract_sparse) {
+    GMM_ASSERT2(vect_size(v1) == mat_ncols(ps) &&
+		vect_size(v2) == mat_nrows(ps),"dimensions mismatch");
+    typename linalg_traits<V1>::const_iterator
+      it = vect_const_begin(v1), ite = vect_const_end(v1);
+    typename strongest_value_type3<V1,V2,MATSP>::value_type res(0);
+    for (; it != ite; ++it)
+      res += vect_sp(mat_const_col(ps, it.index()), v2) * (*it);
+    return res;
+  }
+
+  template <typename MATSP, typename V1, typename V2> inline
+    typename strongest_value_type3<V1,V2,MATSP>::value_type
+    vect_sp_with_matc(const MATSP &ps, const V1 &v1, const V2 &v2,
+		      abstract_skyline)
+  { return vect_sp_with_matc(ps, v1, v2, abstract_sparse()); }
+
+  template <typename MATSP, typename V1, typename V2> inline
+    typename strongest_value_type3<V1,V2,MATSP>::value_type
+    vect_sp_with_matc(const MATSP &ps, const V1 &v1, const V2 &v2,
+		      abstract_dense) {
+    GMM_ASSERT2(vect_size(v1) == mat_ncols(ps) &&
+		vect_size(v2) == mat_nrows(ps), "dimensions mismatch");
+    typename linalg_traits<V1>::const_iterator
+      it = vect_const_begin(v1), ite = vect_const_end(v1);
+    typename strongest_value_type3<V1,V2,MATSP>::value_type res(0);
+    for (size_type i = 0; it != ite; ++i, ++it)
+      res += vect_sp(mat_const_col(ps, i), v2) * (*it);
+    return res;
+  }
+
+  template <typename MATSP, typename V1, typename V2> inline
+  typename strongest_value_type3<V1,V2,MATSP>::value_type
+  vect_sp_with_mat(const MATSP &ps, const V1 &v1,const V2 &v2,col_and_row)
+  { return vect_sp_with_mat(ps, v1, v2, col_major()); }
+
+  template <typename MATSP, typename V1, typename V2> inline
+  typename strongest_value_type3<V1,V2,MATSP>::value_type
+  vect_sp_with_mat(const MATSP &ps, const V1 &v1, const V2 &v2,
+		   abstract_null_type) {
+    typename temporary_vector<V1>::vector_type w(mat_nrows(ps));
+    GMM_WARNING2("Warning, a temporary is used in scalar product\n");
+    mult(ps, v1, w); 
+    return vect_sp(w, v2);
+  }
+
+  template <typename IT1, typename IT2> inline
+  typename strongest_numeric_type<typename std::iterator_traits<IT1>::value_type,
+				  typename std::iterator_traits<IT2>::value_type>::T
+  vect_sp_dense_(IT1 it, IT1 ite, IT2 it2) {
+    typename strongest_numeric_type<typename std::iterator_traits<IT1>::value_type,
+      typename std::iterator_traits<IT2>::value_type>::T res(0);
+    for (; it != ite; ++it, ++it2) res += (*it) * (*it2);
+    return res;
+  }
+  
+  template <typename IT1, typename V> inline
+    typename strongest_numeric_type<typename std::iterator_traits<IT1>::value_type,
+				    typename linalg_traits<V>::value_type>::T
+    vect_sp_sparse_(IT1 it, IT1 ite, const V &v) {
+      typename strongest_numeric_type<typename std::iterator_traits<IT1>::value_type,
+	typename linalg_traits<V>::value_type>::T res(0);
+    for (; it != ite; ++it) res += (*it) * v[it.index()];
+    return res;
+  }
+
+  template <typename V1, typename V2> inline
+  typename strongest_value_type<V1,V2>::value_type
+    vect_sp(const V1 &v1, const V2 &v2, abstract_dense, abstract_dense) {
+    return vect_sp_dense_(vect_const_begin(v1), vect_const_end(v1),
+			  vect_const_begin(v2));
+  }
+
+  template <typename V1, typename V2> inline
+    typename strongest_value_type<V1,V2>::value_type
+    vect_sp(const V1 &v1, const V2 &v2, abstract_skyline, abstract_dense) {
+    typename linalg_traits<V1>::const_iterator it1 = vect_const_begin(v1),
+      ite =  vect_const_end(v1);
+    typename linalg_traits<V2>::const_iterator it2 = vect_const_begin(v2);
+    return vect_sp_dense_(it1, ite, it2 + it1.index());
+  }
+
+  template <typename V1, typename V2> inline
+    typename strongest_value_type<V1,V2>::value_type
+    vect_sp(const V1 &v1, const V2 &v2, abstract_dense, abstract_skyline) {
+    typename linalg_traits<V2>::const_iterator it1 = vect_const_begin(v2),
+      ite =  vect_const_end(v2);
+    typename linalg_traits<V1>::const_iterator it2 = vect_const_begin(v1);
+    return vect_sp_dense_(it1, ite, it2 + it1.index());
+  }
+
+  template <typename V1, typename V2> inline
+    typename strongest_value_type<V1,V2>::value_type
+    vect_sp(const V1 &v1, const V2 &v2, abstract_skyline, abstract_skyline) {
+    typedef typename strongest_value_type<V1,V2>::value_type T;
+    typename linalg_traits<V1>::const_iterator it1 = vect_const_begin(v1),
+      ite1 =  vect_const_end(v1);
+    typename linalg_traits<V2>::const_iterator it2 = vect_const_begin(v2),
+      ite2 =  vect_const_end(v2);
+    size_type n = std::min(ite1.index(), ite2.index());
+    size_type l = std::max(it1.index(), it2.index());
+
+    if (l < n) {
+      size_type m = l - it1.index(), p = l - it2.index(), q = m + n - l;
+      return vect_sp_dense_(it1+m, it1+q, it2 + p);
+    }
+    return T(0);
+  }
+
+  template <typename V1, typename V2> inline
+    typename strongest_value_type<V1,V2>::value_type
+  vect_sp(const V1 &v1, const V2 &v2,abstract_sparse,abstract_dense) {
+    return vect_sp_sparse_(vect_const_begin(v1), vect_const_end(v1), v2);
+  }
+
+  template <typename V1, typename V2> inline
+    typename strongest_value_type<V1,V2>::value_type
+    vect_sp(const V1 &v1, const V2 &v2, abstract_sparse, abstract_skyline) {
+    return vect_sp_sparse_(vect_const_begin(v1), vect_const_end(v1), v2);
+  }
+
+  template <typename V1, typename V2> inline
+    typename strongest_value_type<V1,V2>::value_type
+    vect_sp(const V1 &v1, const V2 &v2, abstract_skyline, abstract_sparse) {
+    return vect_sp_sparse_(vect_const_begin(v2), vect_const_end(v2), v1);
+  }
+
+  template <typename V1, typename V2> inline
+    typename strongest_value_type<V1,V2>::value_type
+    vect_sp(const V1 &v1, const V2 &v2, abstract_dense,abstract_sparse) {
+    return vect_sp_sparse_(vect_const_begin(v2), vect_const_end(v2), v1);
+  }
+
+
+  template <typename V1, typename V2> inline
+  typename strongest_value_type<V1,V2>::value_type
+  vect_sp_sparse_sparse(const V1 &v1, const V2 &v2, linalg_true) {
+    typename linalg_traits<V1>::const_iterator it1 = vect_const_begin(v1),
+      ite1 = vect_const_end(v1);
+    typename linalg_traits<V2>::const_iterator it2 = vect_const_begin(v2),
+      ite2 = vect_const_end(v2);
+    typename strongest_value_type<V1,V2>::value_type res(0);
+    
+    while (it1 != ite1 && it2 != ite2) {
+      if (it1.index() == it2.index())
+	{ res += (*it1) * *it2; ++it1; ++it2; }
+      else if (it1.index() < it2.index()) ++it1; else ++it2;
+    }
+    return res;
+  }
+
+  template <typename V1, typename V2> inline
+  typename strongest_value_type<V1,V2>::value_type
+  vect_sp_sparse_sparse(const V1 &v1, const V2 &v2, linalg_false) {
+    return vect_sp_sparse_(vect_const_begin(v1), vect_const_end(v1), v2);
+  }
+
+  template <typename V1, typename V2> inline
+    typename strongest_value_type<V1,V2>::value_type
+    vect_sp(const V1 &v1, const V2 &v2,abstract_sparse,abstract_sparse) {
+    return vect_sp_sparse_sparse(v1, v2,
+	    typename linalg_and<typename linalg_traits<V1>::index_sorted,
+	    typename linalg_traits<V2>::index_sorted>::bool_type());
+  }
+  
+  /* ******************************************************************** */
+  /*		Hermitian product                             		  */
+  /* ******************************************************************** */
+  ///@endcond
+  /** Hermitian product. */
+  template <typename V1, typename V2>
+  inline typename strongest_value_type<V1,V2>::value_type
+  vect_hp(const V1 &v1, const V2 &v2)
+  { return vect_sp(v1, conjugated(v2)); }
+
+  /** Hermitian product with a matrix. */
+  template <typename MATSP, typename V1, typename V2> inline
+  typename strongest_value_type3<V1,V2,MATSP>::value_type
+    vect_hp(const MATSP &ps, const V1 &v1, const V2 &v2) {
+    return vect_sp(ps, v1, gmm::conjugated(v2));
+  }
+
+  /* ******************************************************************** */
+  /*		Trace of a matrix                             		  */
+  /* ******************************************************************** */
+  
+  /** Trace of a matrix */
+   template <typename M>
+   typename linalg_traits<M>::value_type
+   mat_trace(const M &m) {
+     typedef typename linalg_traits<M>::value_type T;
+     T res(0);
+     for (size_type i = 0; i < std::max(mat_nrows(m), mat_ncols(m)); ++i)
+       res += m(i,i);
+     return res;
+  }
+
+  /* ******************************************************************** */
+  /*		Euclidean norm                             		  */
+  /* ******************************************************************** */
+
+  /** Euclidean norm of a vector. */
+  template <typename V>
+  typename number_traits<typename linalg_traits<V>::value_type>
+  ::magnitude_type
+  vect_norm2_sqr(const V &v) {
+    typedef typename linalg_traits<V>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+    typename linalg_traits<V>::const_iterator
+      it = vect_const_begin(v), ite = vect_const_end(v);
+    R res(0);
+    for (; it != ite; ++it) res += gmm::abs_sqr(*it);
+    return res;
+  }
+
+  /** squared Euclidean norm of a vector. */
+  template <typename V> inline
+   typename number_traits<typename linalg_traits<V>::value_type>
+   ::magnitude_type 
+  vect_norm2(const V &v)
+  { return sqrt(vect_norm2_sqr(v)); }
+  
+
+  /** squared Euclidean distance between two vectors */
+  template <typename V1, typename V2> inline
+   typename number_traits<typename linalg_traits<V1>::value_type>
+   ::magnitude_type
+  vect_dist2_sqr(const V1 &v1, const V2 &v2) { // not fully optimized 
+    typedef typename linalg_traits<V1>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+    typename linalg_traits<V1>::const_iterator
+      it1 = vect_const_begin(v1), ite1 = vect_const_end(v1);
+    typename linalg_traits<V2>::const_iterator
+      it2 = vect_const_begin(v2), ite2 = vect_const_end(v2);
+    size_type k1(0), k2(0);
+    R res(0);
+    while (it1 != ite1 && it2 != ite2) {
+      size_type i1 = index_of_it(it1, k1,
+				 typename linalg_traits<V1>::storage_type());
+      size_type i2 = index_of_it(it2, k2,
+				 typename linalg_traits<V2>::storage_type());
+
+      if (i1 == i2) {
+	res += gmm::abs_sqr(*it2 - *it1); ++it1; ++k1; ++it2; ++k2;
+      }
+      else if (i1 < i2) {
+	res += gmm::abs_sqr(*it1); ++it1; ++k1; 
+      }
+      else  {
+	res += gmm::abs_sqr(*it2); ++it2; ++k2; 
+      }
+    }
+    while (it1 != ite1) { res += gmm::abs_sqr(*it1); ++it1; }
+    while (it2 != ite2) { res += gmm::abs_sqr(*it2); ++it2; }
+    return res;
+  }
+ 
+  /** Euclidean distance between two vectors */
+  template <typename V1, typename V2> inline
+   typename number_traits<typename linalg_traits<V1>::value_type>
+   ::magnitude_type
+  vect_dist2(const V1 &v1, const V2 &v2)
+  { return sqrt(vect_dist2_sqr(v1, v2)); }
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+  template <typename M>
+   typename number_traits<typename linalg_traits<M>::value_type>
+   ::magnitude_type
+   mat_euclidean_norm_sqr(const M &m, row_major) {
+    typename number_traits<typename linalg_traits<M>::value_type>
+      ::magnitude_type res(0);
+    for (size_type i = 0; i < mat_nrows(m); ++i)
+      res += vect_norm2_sqr(mat_const_row(m, i));
+    return res;
+  }
+
+  template <typename M>
+   typename number_traits<typename linalg_traits<M>::value_type>
+   ::magnitude_type
+   mat_euclidean_norm_sqr(const M &m, col_major) {
+    typename number_traits<typename linalg_traits<M>::value_type>
+      ::magnitude_type res(0);
+    for (size_type i = 0; i < mat_ncols(m); ++i)
+      res += vect_norm2_sqr(mat_const_col(m, i));
+    return res;
+  }
+  ///@endcond
+  /** squared Euclidean norm of a matrix. */
+  template <typename M> inline
+   typename number_traits<typename linalg_traits<M>::value_type>
+   ::magnitude_type
+   mat_euclidean_norm_sqr(const M &m) {
+    return mat_euclidean_norm_sqr(m,
+		     typename principal_orientation_type<typename
+		     linalg_traits<M>::sub_orientation>::potype());
+  }
+
+  /** Euclidean norm of a matrix. */
+  template <typename M> inline
+   typename number_traits<typename linalg_traits<M>::value_type>
+   ::magnitude_type
+   mat_euclidean_norm(const M &m)
+  { return gmm::sqrt(mat_euclidean_norm_sqr(m)); }
+
+  /* ******************************************************************** */
+  /*		vector norm1                                    	  */
+  /* ******************************************************************** */
+  /** 1-norm of a vector */
+  template <typename V>
+  typename number_traits<typename linalg_traits<V>::value_type>
+  ::magnitude_type
+  vect_norm1(const V &v) {
+    typename linalg_traits<V>::const_iterator
+      it = vect_const_begin(v), ite = vect_const_end(v);
+    typename number_traits<typename linalg_traits<V>::value_type>
+	::magnitude_type res(0);
+    for (; it != ite; ++it) res += gmm::abs(*it);
+    return res;
+  }
+
+  /* ******************************************************************** */
+  /*		vector Infinity norm                              	  */
+  /* ******************************************************************** */
+  /** Infinity norm of a vector. */
+  template <typename V>
+  typename number_traits<typename linalg_traits<V>::value_type>
+  ::magnitude_type 
+  vect_norminf(const V &v) {
+    typename linalg_traits<V>::const_iterator
+      it = vect_const_begin(v), ite = vect_const_end(v);
+      typename number_traits<typename linalg_traits<V>::value_type>
+	::magnitude_type res(0);
+    for (; it != ite; ++it) res = std::max(res, gmm::abs(*it));
+    return res;
+  }
+
+  /* ******************************************************************** */
+  /*		matrix norm1                                    	  */
+  /* ******************************************************************** */
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+  template <typename M>
+   typename number_traits<typename linalg_traits<M>::value_type>
+   ::magnitude_type
+   mat_norm1(const M &m, col_major) {
+    typename number_traits<typename linalg_traits<M>::value_type>
+      ::magnitude_type res(0);
+    for (size_type i = 0; i < mat_ncols(m); ++i)
+      res = std::max(res, vect_norm1(mat_const_col(m,i)));
+    return res;
+  }
+
+  template <typename M>
+   typename number_traits<typename linalg_traits<M>::value_type>
+   ::magnitude_type
+   mat_norm1(const M &m, row_major) {
+    typedef typename linalg_traits<M>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+    typedef typename linalg_traits<M>::storage_type store_type;
+    
+    std::vector<R> aux(mat_ncols(m));
+    for (size_type i = 0; i < mat_nrows(m); ++i) {
+      typedef typename linalg_traits<M>::const_sub_row_type row_type;
+      row_type row = mat_const_row(m, i);
+      typename linalg_traits<row_type>::const_iterator
+	it = vect_const_begin(row), ite = vect_const_end(row);
+      for (size_type k = 0; it != ite; ++it, ++k)
+	aux[index_of_it(it, k, store_type())] += gmm::abs(*it);
+    }
+    return vect_norminf(aux);
+  }
+
+  template <typename M>
+   typename number_traits<typename linalg_traits<M>::value_type>
+   ::magnitude_type
+   mat_norm1(const M &m, col_and_row)
+  { return mat_norm1(m, col_major()); }
+
+  template <typename M>
+   typename number_traits<typename linalg_traits<M>::value_type>
+   ::magnitude_type
+   mat_norm1(const M &m, row_and_col)
+  { return mat_norm1(m, col_major()); }
+  ///@endcond
+  /** 1-norm of a matrix */
+  template <typename M>
+   typename number_traits<typename linalg_traits<M>::value_type>
+   ::magnitude_type
+   mat_norm1(const M &m) {
+    return mat_norm1(m, typename linalg_traits<M>::sub_orientation());
+  }
+
+
+  /* ******************************************************************** */
+  /*		matrix Infinity norm                              	  */
+  /* ******************************************************************** */
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+  template <typename M>
+   typename number_traits<typename linalg_traits<M>::value_type>
+   ::magnitude_type
+   mat_norminf(const M &m, row_major) {
+    typename number_traits<typename linalg_traits<M>::value_type>
+      ::magnitude_type res(0);
+    for (size_type i = 0; i < mat_nrows(m); ++i)
+      res = std::max(res, vect_norm1(mat_const_row(m,i)));
+    return res;
+  }
+
+  template <typename M>
+   typename number_traits<typename linalg_traits<M>::value_type>
+   ::magnitude_type
+   mat_norminf(const M &m, col_major) {
+    typedef typename linalg_traits<M>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+    typedef typename linalg_traits<M>::storage_type store_type;
+    
+    std::vector<R> aux(mat_nrows(m));
+    for (size_type i = 0; i < mat_ncols(m); ++i) {
+      typedef typename linalg_traits<M>::const_sub_col_type col_type;
+      col_type col = mat_const_col(m, i);
+      typename linalg_traits<col_type>::const_iterator
+	it = vect_const_begin(col), ite = vect_const_end(col);
+      for (size_type k = 0; it != ite; ++it, ++k)
+	aux[index_of_it(it, k, store_type())] += gmm::abs(*it);
+    }
+    return vect_norminf(aux);
+  }
+
+  template <typename M>
+   typename number_traits<typename linalg_traits<M>::value_type>
+   ::magnitude_type
+   mat_norminf(const M &m, col_and_row)
+  { return mat_norminf(m, row_major()); }
+
+  template <typename M>
+   typename number_traits<typename linalg_traits<M>::value_type>
+   ::magnitude_type
+   mat_norminf(const M &m, row_and_col)
+  { return mat_norminf(m, row_major()); }
+  ///@endcond
+  /** infinity-norm of a matrix.*/
+  template <typename M>
+   typename number_traits<typename linalg_traits<M>::value_type>
+   ::magnitude_type
+   mat_norminf(const M &m) {
+    return mat_norminf(m, typename linalg_traits<M>::sub_orientation());
+  }
+
+  /* ******************************************************************** */
+  /*		Max norm for matrices                              	  */
+  /* ******************************************************************** */
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+  template <typename M>
+   typename number_traits<typename linalg_traits<M>::value_type>
+   ::magnitude_type
+   mat_maxnorm(const M &m, row_major) {
+    typename number_traits<typename linalg_traits<M>::value_type>
+      ::magnitude_type res(0);
+    for (size_type i = 0; i < mat_nrows(m); ++i)
+      res = std::max(res, vect_norminf(mat_const_row(m,i)));
+    return res;
+  }
+
+  template <typename M>
+   typename number_traits<typename linalg_traits<M>::value_type>
+   ::magnitude_type
+   mat_maxnorm(const M &m, col_major) {
+    typename number_traits<typename linalg_traits<M>::value_type>
+      ::magnitude_type res(0);
+    for (size_type i = 0; i < mat_ncols(m); ++i)
+      res = std::max(res, vect_norminf(mat_const_col(m,i)));
+    return res;
+  }
+  ///@endcond
+  /** max-norm of a matrix. */
+  template <typename M>
+   typename number_traits<typename linalg_traits<M>::value_type>
+   ::magnitude_type
+   mat_maxnorm(const M &m) {
+    return mat_maxnorm(m,
+		     typename principal_orientation_type<typename
+		     linalg_traits<M>::sub_orientation>::potype());
+  }
+
+  /* ******************************************************************** */
+  /*		Clean                                    		  */
+  /* ******************************************************************** */
+  /** Clean a vector or matrix (replace near-zero entries with zeroes).   */
+  
+  template <typename L> inline void clean(L &l, double threshold);
+
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+  template <typename L, typename T>
+  void clean(L &l, double threshold, abstract_dense, T) {
+    typedef typename number_traits<T>::magnitude_type R;
+    typename linalg_traits<L>::iterator it = vect_begin(l), ite = vect_end(l);
+    for (; it != ite; ++it)
+      if (gmm::abs(*it) < R(threshold)) *it = T(0);
+  }
+
+  template <typename L, typename T>
+  void clean(L &l, double threshold, abstract_skyline, T)
+  { gmm::clean(l, threshold, abstract_dense(), T()); }
+
+  template <typename L, typename T>
+  void clean(L &l, double threshold, abstract_sparse, T) {
+    typedef typename number_traits<T>::magnitude_type R;
+    typename linalg_traits<L>::iterator it = vect_begin(l), ite = vect_end(l);
+    std::vector<size_type> ind;
+    for (; it != ite; ++it)
+      if (gmm::abs(*it) < R(threshold)) ind.push_back(it.index());
+    for (size_type i = 0; i < ind.size(); ++i) l[ind[i]] = T(0);
+  }
+  
+  template <typename L, typename T>
+  void clean(L &l, double threshold, abstract_dense, std::complex<T>) {
+    typename linalg_traits<L>::iterator it = vect_begin(l), ite = vect_end(l);
+    for (; it != ite; ++it){
+      if (gmm::abs((*it).real()) < T(threshold))
+	*it = std::complex<T>(T(0), (*it).imag());
+      if (gmm::abs((*it).imag()) < T(threshold))
+	*it = std::complex<T>((*it).real(), T(0));
+    }
+  }
+
+  template <typename L, typename T>
+  void clean(L &l, double threshold, abstract_skyline, std::complex<T>)
+  { gmm::clean(l, threshold, abstract_dense(), std::complex<T>()); }
+
+  template <typename L, typename T>
+  void clean(L &l, double threshold, abstract_sparse, std::complex<T>) {
+    typename linalg_traits<L>::iterator it = vect_begin(l), ite = vect_end(l);
+    std::vector<size_type> ind;
+    for (; it != ite; ++it) {
+      bool r = (gmm::abs((*it).real()) < T(threshold));
+      bool i = (gmm::abs((*it).imag()) < T(threshold));
+      if (r && i) ind.push_back(it.index());
+      else if (r) (*it).real() = T(0);
+      else if (i) (*it).imag() = T(0);
+    }
+    for (size_type i = 0; i < ind.size(); ++i)
+      l[ind[i]] = std::complex<T>(T(0),T(0));
+  }
+
+  template <typename L> inline void clean(L &l, double threshold,
+					  abstract_vector) {
+    gmm::clean(l, threshold, typename linalg_traits<L>::storage_type(),
+	       typename linalg_traits<L>::value_type());
+  }
+
+  template <typename L> inline void clean(const L &l, double threshold);
+
+  template <typename L> void clean(L &l, double threshold, row_major) {
+    for (size_type i = 0; i < mat_nrows(l); ++i)
+      gmm::clean(mat_row(l, i), threshold);
+  }
+
+  template <typename L> void clean(L &l, double threshold, col_major) {
+    for (size_type i = 0; i < mat_ncols(l); ++i)
+      gmm::clean(mat_col(l, i), threshold);
+  }
+
+  template <typename L> inline void clean(L &l, double threshold,
+					  abstract_matrix) {
+    gmm::clean(l, threshold,
+	       typename principal_orientation_type<typename
+	       linalg_traits<L>::sub_orientation>::potype());
+  }
+
+  template <typename L> inline void clean(L &l, double threshold)
+  { clean(l, threshold, typename linalg_traits<L>::linalg_type()); }
+ 
+  template <typename L> inline void clean(const L &l, double threshold)
+  { gmm::clean(linalg_const_cast(l), threshold); }
+
+  /* ******************************************************************** */
+  /*		Copy                                    		  */
+  /* ******************************************************************** */
+  ///@endcond
+  /** Copy vectors or matrices. 
+      @param l1 source vector or matrix.
+      @param l2 destination.
+  */
+  template <typename L1, typename L2> inline
+  void copy(const L1& l1, L2& l2) { 
+    if ((const void *)(&l1) != (const void *)(&l2)) {
+      if (same_origin(l1,l2))
+	GMM_WARNING2("Warning : a conflict is possible in copy\n");
+     
+      copy(l1, l2, typename linalg_traits<L1>::linalg_type(),
+	   typename linalg_traits<L2>::linalg_type());
+    }
+  }
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+  template <typename L1, typename L2> inline
+  void copy(const L1& l1, const L2& l2) { copy(l1, linalg_const_cast(l2)); }
+
+  template <typename L1, typename L2> inline
+  void copy(const L1& l1, L2& l2, abstract_vector, abstract_vector) {
+    GMM_ASSERT2(vect_size(l1) == vect_size(l2), "dimensions mismatch");
+    copy_vect(l1, l2, typename linalg_traits<L1>::storage_type(),
+	      typename linalg_traits<L2>::storage_type());
+  }
+
+  template <typename L1, typename L2> inline
+  void copy(const L1& l1, L2& l2, abstract_matrix, abstract_matrix) {
+    size_type m = mat_nrows(l1), n = mat_ncols(l1);
+    if (!m || !n) return;
+    GMM_ASSERT2(n==mat_ncols(l2) && m==mat_nrows(l2), "dimensions mismatch");
+    copy_mat(l1, l2, typename linalg_traits<L1>::sub_orientation(),
+	     typename linalg_traits<L2>::sub_orientation());
+  }
+
+  template <typename V1, typename V2, typename C1, typename C2> inline 
+  void copy_vect(const V1 &v1, const V2 &v2, C1, C2)
+  { copy_vect(v1, const_cast<V2 &>(v2), C1(), C2()); }
+  
+
+  template <typename L1, typename L2>
+  void copy_mat_by_row(const L1& l1, L2& l2) {
+    size_type nbr = mat_nrows(l1);
+    for (size_type i = 0; i < nbr; ++i)
+      copy_vect(mat_const_row(l1, i), mat_row(l2, i),
+      		typename linalg_traits<L1>::storage_type(),
+		typename linalg_traits<L2>::storage_type());
+  }
+
+  template <typename L1, typename L2>
+  void copy_mat_by_col(const L1 &l1, L2 &l2) {
+    size_type nbc = mat_ncols(l1);
+    for (size_type i = 0; i < nbc; ++i) {
+      copy_vect(mat_const_col(l1, i), mat_col(l2, i),
+      		typename linalg_traits<L1>::storage_type(),
+		typename linalg_traits<L2>::storage_type());
+    }
+  }
+
+  template <typename L1, typename L2> inline
+  void copy_mat(const L1& l1, L2& l2, row_major, row_major)
+  { copy_mat_by_row(l1, l2); }
+
+  template <typename L1, typename L2> inline
+  void copy_mat(const L1& l1, L2& l2, row_major, row_and_col)
+  { copy_mat_by_row(l1, l2); }
+
+  template <typename L1, typename L2> inline
+  void copy_mat(const L1& l1, L2& l2, row_and_col, row_and_col)
+  { copy_mat_by_row(l1, l2); }
+
+  template <typename L1, typename L2> inline
+  void copy_mat(const L1& l1, L2& l2, row_and_col, row_major)
+  { copy_mat_by_row(l1, l2); }
+
+  template <typename L1, typename L2> inline
+  void copy_mat(const L1& l1, L2& l2, col_and_row, row_major)
+  { copy_mat_by_row(l1, l2); }
+
+  template <typename L1, typename L2> inline
+  void copy_mat(const L1& l1, L2& l2, row_major, col_and_row)
+  { copy_mat_by_row(l1, l2); }
+
+  template <typename L1, typename L2> inline
+  void copy_mat(const L1& l1, L2& l2, col_and_row, row_and_col)
+  { copy_mat_by_row(l1, l2); }
+
+  template <typename L1, typename L2> inline
+  void copy_mat(const L1& l1, L2& l2, row_and_col, col_and_row)
+  { copy_mat_by_row(l1, l2); }
+
+  template <typename L1, typename L2> inline
+  void copy_mat(const L1& l1, L2& l2, col_major, col_major)
+  { copy_mat_by_col(l1, l2); }
+
+  template <typename L1, typename L2> inline
+  void copy_mat(const L1& l1, L2& l2, col_major, col_and_row)
+  { copy_mat_by_col(l1, l2); }
+
+  template <typename L1, typename L2> inline
+  void copy_mat(const L1& l1, L2& l2, col_major, row_and_col)
+  { copy_mat_by_col(l1, l2); }
+
+  template <typename L1, typename L2> inline
+  void copy_mat(const L1& l1, L2& l2, row_and_col, col_major)
+  { copy_mat_by_col(l1, l2); }
+
+  template <typename L1, typename L2> inline
+  void copy_mat(const L1& l1, L2& l2, col_and_row, col_major)
+  { copy_mat_by_col(l1, l2); }
+
+  template <typename L1, typename L2> inline
+  void copy_mat(const L1& l1, L2& l2, col_and_row, col_and_row)
+  { copy_mat_by_col(l1, l2); }
+  
+  template <typename L1, typename L2> inline
+  void copy_mat_mixed_rc(const L1& l1, L2& l2, size_type i) {
+    copy_mat_mixed_rc(l1, l2, i, typename linalg_traits<L1>::storage_type());
+  }
+
+  template <typename L1, typename L2>
+  void copy_mat_mixed_rc(const L1& l1, L2& l2, size_type i, abstract_sparse) {
+    typename linalg_traits<L1>::const_iterator
+      it  = vect_const_begin(l1), ite = vect_const_end(l1);
+    for (; it != ite; ++it)
+      l2(i, it.index()) = *it;
+  }
+
+  template <typename L1, typename L2>
+  void copy_mat_mixed_rc(const L1& l1, L2& l2, size_type i, abstract_skyline) {
+    typename linalg_traits<L1>::const_iterator
+      it  = vect_const_begin(l1), ite = vect_const_end(l1);
+    for (; it != ite; ++it)
+      l2(i, it.index()) = *it;
+  }
+
+  template <typename L1, typename L2>
+  void copy_mat_mixed_rc(const L1& l1, L2& l2, size_type i, abstract_dense) {
+    typename linalg_traits<L1>::const_iterator
+      it  = vect_const_begin(l1), ite = vect_const_end(l1);
+    for (size_type j = 0; it != ite; ++it, ++j) l2(i, j) = *it;
+  }
+
+  template <typename L1, typename L2> inline
+  void copy_mat_mixed_cr(const L1& l1, L2& l2, size_type i) {
+    copy_mat_mixed_cr(l1, l2, i, typename linalg_traits<L1>::storage_type());
+  }
+
+  template <typename L1, typename L2>
+  void copy_mat_mixed_cr(const L1& l1, L2& l2, size_type i, abstract_sparse) {
+    typename linalg_traits<L1>::const_iterator
+      it  = vect_const_begin(l1), ite = vect_const_end(l1);
+    for (; it != ite; ++it) l2(it.index(), i) = *it;
+  }
+
+  template <typename L1, typename L2>
+  void copy_mat_mixed_cr(const L1& l1, L2& l2, size_type i, abstract_skyline) {
+    typename linalg_traits<L1>::const_iterator
+      it  = vect_const_begin(l1), ite = vect_const_end(l1);
+    for (; it != ite; ++it) l2(it.index(), i) = *it;
+  }
+
+  template <typename L1, typename L2>
+  void copy_mat_mixed_cr(const L1& l1, L2& l2, size_type i, abstract_dense) {
+    typename linalg_traits<L1>::const_iterator
+      it  = vect_const_begin(l1), ite = vect_const_end(l1);
+    for (size_type j = 0; it != ite; ++it, ++j) l2(j, i) = *it;
+  }
+
+  template <typename L1, typename L2>
+  void copy_mat(const L1& l1, L2& l2, row_major, col_major) {
+    clear(l2);
+    size_type nbr = mat_nrows(l1);
+    for (size_type i = 0; i < nbr; ++i)
+      copy_mat_mixed_rc(mat_const_row(l1, i), l2, i);
+  }
+  
+  template <typename L1, typename L2>
+  void copy_mat(const L1& l1, L2& l2, col_major, row_major) {
+    clear(l2);
+    size_type nbc = mat_ncols(l1);
+    for (size_type i = 0; i < nbc; ++i)
+      copy_mat_mixed_cr(mat_const_col(l1, i), l2, i);
+  }
+  
+  template <typename L1, typename L2> inline
+  void copy_vect(const L1 &l1, L2 &l2, abstract_dense, abstract_dense) {
+    std::copy(vect_const_begin(l1), vect_const_end(l1), vect_begin(l2));
+  }
+
+  template <typename L1, typename L2> inline // to be optimised ?
+  void copy_vect(const L1 &l1, L2 &l2, abstract_skyline, abstract_skyline) {
+    typename linalg_traits<L1>::const_iterator it1 = vect_const_begin(l1),
+      ite1 = vect_const_end(l1);
+    while (it1 != ite1 && *it1 == typename linalg_traits<L1>::value_type(0))
+      ++it1;
+
+    if (ite1 - it1 > 0) {
+      clear(l2);
+      typename linalg_traits<L2>::iterator it2 = vect_begin(l2), 
+	ite2 = vect_end(l2);
+      while (*(ite1-1) == typename linalg_traits<L1>::value_type(0)) ite1--;
+
+      if (it2 == ite2) {
+	l2[it1.index()] = *it1; ++it1;
+	l2[ite1.index()-1] = *(ite1-1); --ite1;
+	if (it1 < ite1)
+	  { it2 = vect_begin(l2); ++it2; std::copy(it1, ite1, it2); }
+      }
+      else {
+	ptrdiff_t m = it1.index() - it2.index();
+	if (m >= 0 && ite1.index() <= ite2.index())
+	  std::copy(it1, ite1, it2 + m);
+	else {
+	  if (m < 0) l2[it1.index()] = *it1;
+	  if (ite1.index() > ite2.index()) l2[ite1.index()-1] = *(ite1-1);
+	  it2 = vect_begin(l2); ite2 = vect_end(l2);
+	  m = it1.index() - it2.index();
+	  std::copy(it1, ite1, it2 + m);
+	}
+      }
+    }
+  }
+  
+  template <typename L1, typename L2>
+  void copy_vect(const L1& l1, L2& l2, abstract_sparse, abstract_dense) {
+    clear(l2);
+    typename linalg_traits<L1>::const_iterator
+      it  = vect_const_begin(l1), ite = vect_const_end(l1);
+    for (; it != ite; ++it) { l2[it.index()] = *it; }
+  }
+
+  template <typename L1, typename L2>
+  void copy_vect(const L1& l1, L2& l2, abstract_sparse, abstract_skyline) {
+    clear(l2);
+    typename linalg_traits<L1>::const_iterator
+      it  = vect_const_begin(l1), ite = vect_const_end(l1);
+    for (; it != ite; ++it) l2[it.index()] = *it;
+  }
+
+  template <typename L1, typename L2>
+  void copy_vect(const L1& l1, L2& l2, abstract_skyline, abstract_dense) {
+    typedef typename linalg_traits<L1>::value_type T;
+    typedef typename linalg_traits<L1>::const_iterator l1_const_iterator;
+    typedef typename linalg_traits<L2>::iterator l2_iterator;
+    l1_const_iterator it = vect_const_begin(l1), ite = vect_const_end(l1);
+    if (it == ite)
+      gmm::clear(l2);
+    else {
+      l2_iterator it2 = vect_begin(l2), ite2 = vect_end(l2);
+      
+      size_type i = it.index(), j;
+      for (j = 0; j < i; ++j, ++it2) *it2 = T(0);
+      for (; it != ite; ++it, ++it2) *it2 = *it;
+      for (; it2 != ite2; ++it2) *it2 = T(0);
+    }
+  }
+    
+  template <typename L1, typename L2>
+  void copy_vect(const L1& l1, L2& l2, abstract_sparse, abstract_sparse) {
+    typename linalg_traits<L1>::const_iterator
+      it  = vect_const_begin(l1), ite = vect_const_end(l1);
+    clear(l2);
+    for (; it != ite; ++it)
+      if (*it != (typename linalg_traits<L1>::value_type)(0))
+	l2[it.index()] = *it;
+  }
+  
+  template <typename L1, typename L2>
+  void copy_vect(const L1& l1, L2& l2, abstract_dense, abstract_sparse) {
+    clear(l2);
+    typename linalg_traits<L1>::const_iterator
+      it  = vect_const_begin(l1), ite = vect_const_end(l1);
+    for (size_type i = 0; it != ite; ++it, ++i)
+      if (*it != (typename linalg_traits<L1>::value_type)(0))
+	l2[i] = *it;
+  }
+
+  template <typename L1, typename L2> // to be optimised ...
+  void copy_vect(const L1& l1, L2& l2, abstract_dense, abstract_skyline) {
+    clear(l2);
+    typename linalg_traits<L1>::const_iterator
+      it  = vect_const_begin(l1), ite = vect_const_end(l1);
+    for (size_type i = 0; it != ite; ++it, ++i)
+      if (*it != (typename linalg_traits<L1>::value_type)(0))
+	l2[i] = *it;
+  }
+
+  
+  template <typename L1, typename L2>
+  void copy_vect(const L1& l1, L2& l2, abstract_skyline, abstract_sparse) {
+    clear(l2);
+    typename linalg_traits<L1>::const_iterator
+      it  = vect_const_begin(l1), ite = vect_const_end(l1);
+    for (; it != ite; ++it)
+      if (*it != (typename linalg_traits<L1>::value_type)(0))
+	l2[it.index()] = *it;
+  }
+
+  /* ******************************************************************** */
+  /*		Matrix and vector addition                             	  */
+  /*   algorithms are built in order to avoid some conflicts whith        */
+  /*   repeated arguments or with overlapping part of a same object.      */
+  /*   In the latter case, conflicts are still possible.                  */
+  /* ******************************************************************** */
+  ///@endcond
+  /** Add two vectors or matrices
+      @param l1
+      @param l2 contains on output, l2+l1.
+  */
+  template <typename L1, typename L2> inline
+    void add(const L1& l1, L2& l2) {
+      add_spec(l1, l2, typename linalg_traits<L2>::linalg_type());
+  }
+  ///@cond
+
+  template <typename L1, typename L2> inline
+  void add(const L1& l1, const L2& l2) { add(l1, linalg_const_cast(l2)); }
+
+  template <typename L1, typename L2> inline
+    void add_spec(const L1& l1, L2& l2, abstract_vector) {
+    GMM_ASSERT2(vect_size(l1) == vect_size(l2), "dimensions mismatch");
+    add(l1, l2, typename linalg_traits<L1>::storage_type(),
+	typename linalg_traits<L2>::storage_type());
+  }
+
+  template <typename L1, typename L2> inline
+    void add_spec(const L1& l1, L2& l2, abstract_matrix) {
+    size_type m = mat_nrows(l1), n = mat_ncols(l1);
+    GMM_ASSERT2(m==mat_nrows(l2) && n==mat_ncols(l2), "dimensions mismatch");
+    add(l1, l2, typename linalg_traits<L1>::sub_orientation(),
+	typename linalg_traits<L2>::sub_orientation());
+  }
+
+  template <typename L1, typename L2>
+  void add(const L1& l1, L2& l2, row_major, row_major) {
+    typename linalg_traits<L1>::const_row_iterator it1 = mat_row_begin(l1),
+      ite = mat_row_end(l1);
+    typename linalg_traits<L2>::row_iterator it2 = mat_row_begin(l2);
+    for ( ; it1 != ite; ++it1, ++it2)
+      add(linalg_traits<L1>::row(it1), linalg_traits<L2>::row(it2));
+  }
+
+  template <typename L1, typename L2>
+  void add(const L1& l1, L2& l2, col_major, col_major) {
+    typename linalg_traits<L1>::const_col_iterator
+      it1 = mat_col_const_begin(l1),
+      ite = mat_col_const_end(l1);
+    typename linalg_traits<L2>::col_iterator it2 = mat_col_begin(l2);
+    for ( ; it1 != ite; ++it1, ++it2)
+      add(linalg_traits<L1>::col(it1),  linalg_traits<L2>::col(it2));
+  }
+  
+    template <typename L1, typename L2> inline
+  void add_mat_mixed_rc(const L1& l1, L2& l2, size_type i) {
+    add_mat_mixed_rc(l1, l2, i, typename linalg_traits<L1>::storage_type());
+  }
+
+  template <typename L1, typename L2>
+  void add_mat_mixed_rc(const L1& l1, L2& l2, size_type i, abstract_sparse) {
+    typename linalg_traits<L1>::const_iterator
+      it  = vect_const_begin(l1), ite = vect_const_end(l1);
+    for (; it != ite; ++it) l2(i, it.index()) += *it;
+  }
+
+  template <typename L1, typename L2>
+  void add_mat_mixed_rc(const L1& l1, L2& l2, size_type i, abstract_skyline) {
+    typename linalg_traits<L1>::const_iterator
+      it  = vect_const_begin(l1), ite = vect_const_end(l1);
+    for (; it != ite; ++it) l2(i, it.index()) += *it;
+  }
+
+  template <typename L1, typename L2>
+  void add_mat_mixed_rc(const L1& l1, L2& l2, size_type i, abstract_dense) {
+    typename linalg_traits<L1>::const_iterator
+      it  = vect_const_begin(l1), ite = vect_const_end(l1);
+    for (size_type j = 0; it != ite; ++it, ++j) l2(i, j) += *it;
+  }
+
+  template <typename L1, typename L2> inline
+  void add_mat_mixed_cr(const L1& l1, L2& l2, size_type i) {
+    add_mat_mixed_cr(l1, l2, i, typename linalg_traits<L1>::storage_type());
+  }
+
+  template <typename L1, typename L2>
+  void add_mat_mixed_cr(const L1& l1, L2& l2, size_type i, abstract_sparse) {
+    typename linalg_traits<L1>::const_iterator
+      it  = vect_const_begin(l1), ite = vect_const_end(l1);
+    for (; it != ite; ++it) l2(it.index(), i) += *it;
+  }
+
+  template <typename L1, typename L2>
+  void add_mat_mixed_cr(const L1& l1, L2& l2, size_type i, abstract_skyline) {
+    typename linalg_traits<L1>::const_iterator
+      it  = vect_const_begin(l1), ite = vect_const_end(l1);
+    for (; it != ite; ++it) l2(it.index(), i) += *it;
+  }
+
+  template <typename L1, typename L2>
+  void add_mat_mixed_cr(const L1& l1, L2& l2, size_type i, abstract_dense) {
+    typename linalg_traits<L1>::const_iterator
+      it  = vect_const_begin(l1), ite = vect_const_end(l1);
+    for (size_type j = 0; it != ite; ++it, ++j) l2(j, i) += *it;
+  }
+
+  template <typename L1, typename L2>
+  void add(const L1& l1, L2& l2, row_major, col_major) {
+    size_type nbr = mat_nrows(l1);
+    for (size_type i = 0; i < nbr; ++i)
+      add_mat_mixed_rc(mat_const_row(l1, i), l2, i);
+  }
+  
+  template <typename L1, typename L2>
+  void add(const L1& l1, L2& l2, col_major, row_major) {
+    size_type nbc = mat_ncols(l1);
+    for (size_type i = 0; i < nbc; ++i)
+      add_mat_mixed_cr(mat_const_col(l1, i), l2, i);
+  }
+
+  template <typename L1, typename L2> inline
+  void add(const L1& l1, L2& l2, row_and_col, row_major)
+  { add(l1, l2, row_major(), row_major()); }
+
+  template <typename L1, typename L2> inline
+  void add(const L1& l1, L2& l2, row_and_col, row_and_col)
+  { add(l1, l2, row_major(), row_major()); }
+
+  template <typename L1, typename L2> inline
+  void add(const L1& l1, L2& l2, row_and_col, col_and_row)
+  { add(l1, l2, row_major(), row_major()); }
+
+  template <typename L1, typename L2> inline
+  void add(const L1& l1, L2& l2, col_and_row, row_and_col)
+  { add(l1, l2, row_major(), row_major()); }
+
+  template <typename L1, typename L2> inline
+  void add(const L1& l1, L2& l2, row_major, row_and_col)
+  { add(l1, l2, row_major(), row_major()); }
+
+  template <typename L1, typename L2> inline
+  void add(const L1& l1, L2& l2, col_and_row, row_major)
+  { add(l1, l2, row_major(), row_major()); }
+
+  template <typename L1, typename L2> inline
+  void add(const L1& l1, L2& l2, row_major, col_and_row)
+  { add(l1, l2, row_major(), row_major()); }
+
+  template <typename L1, typename L2> inline
+  void add(const L1& l1, L2& l2, row_and_col, col_major)
+  { add(l1, l2, col_major(), col_major()); }
+
+  template <typename L1, typename L2> inline
+  void add(const L1& l1, L2& l2, col_major, row_and_col)
+  { add(l1, l2, col_major(), col_major()); }
+
+  template <typename L1, typename L2> inline
+  void add(const L1& l1, L2& l2, col_and_row, col_major)
+  { add(l1, l2, col_major(), col_major()); }
+
+  template <typename L1, typename L2> inline
+  void add(const L1& l1, L2& l2, col_and_row, col_and_row)
+  { add(l1, l2, col_major(), col_major()); }
+
+  template <typename L1, typename L2> inline
+  void add(const L1& l1, L2& l2, col_major, col_and_row)
+  { add(l1, l2, col_major(), col_major()); }
+
+  ///@endcond
+  /** Addition of two vectors/matrices
+      @param l1
+      @param l2
+      @param l3 contains l1+l2 on output
+  */
+  template <typename L1, typename L2, typename L3> inline
+  void add(const L1& l1, const L2& l2, L3& l3) {
+    add_spec(l1, l2, l3, typename linalg_traits<L2>::linalg_type());
+  }
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+  template <typename L1, typename L2, typename L3> inline
+  void add(const L1& l1, const L2& l2, const L3& l3)
+  { add(l1, l2, linalg_const_cast(l3)); }
+
+  template <typename L1, typename L2, typename L3> inline
+    void add_spec(const L1& l1, const L2& l2, L3& l3, abstract_matrix)
+  { copy(l2, l3); add(l1, l3); }
+
+  template <typename L1, typename L2, typename L3> inline
+    void add_spec(const L1& l1, const L2& l2, L3& l3, abstract_vector) {
+    GMM_ASSERT2(vect_size(l1) == vect_size(l2) &&
+		vect_size(l1) == vect_size(l3), "dimensions mismatch");
+    if ((const void *)(&l1) == (const void *)(&l3))
+      add(l2, l3);
+    else if ((const void *)(&l2) == (const void *)(&l3))
+      add(l1, l3);
+    else
+      add(l1, l2, l3, typename linalg_traits<L1>::storage_type(),
+	  typename linalg_traits<L2>::storage_type(),
+	  typename linalg_traits<L3>::storage_type());
+  }
+
+  template <typename IT1, typename IT2, typename IT3>
+    void add_full_(IT1 it1, IT2 it2, IT3 it3, IT3 ite) {
+    for (; it3 != ite; ++it3, ++it2, ++it1) *it3 = *it1 + *it2;
+  }
+
+  template <typename IT1, typename IT2, typename IT3>
+    void add_almost_full_(IT1 it1, IT1 ite1, IT2 it2, IT3 it3, IT3 ite3) {
+    IT3 it = it3;
+    for (; it != ite3; ++it, ++it2) *it = *it2;
+    for (; it1 != ite1; ++it1)
+      *(it3 + it1.index()) += *it1;
+  }
+
+  template <typename IT1, typename IT2, typename IT3>
+  void add_to_full_(IT1 it1, IT1 ite1, IT2 it2, IT2 ite2,
+		    IT3 it3, IT3 ite3) {
+    typedef typename std::iterator_traits<IT3>::value_type T;
+    IT3 it = it3;
+    for (; it != ite3; ++it) *it = T(0);
+    for (; it1 != ite1; ++it1) *(it3 + it1.index()) = *it1;
+    for (; it2 != ite2; ++it2) *(it3 + it2.index()) += *it2;    
+  }
+  
+  template <typename L1, typename L2, typename L3> inline
+  void add(const L1& l1, const L2& l2, L3& l3,
+	   abstract_dense, abstract_dense, abstract_dense) {
+    add_full_(vect_const_begin(l1), vect_const_begin(l2),
+	      vect_begin(l3), vect_end(l3));
+  }
+  
+  // generic function for add(v1, v2, v3).
+  // Need to be specialized to optimize particular additions.
+  template <typename L1, typename L2, typename L3,
+	    typename ST1, typename ST2, typename ST3>
+  inline void add(const L1& l1, const L2& l2, L3& l3, ST1, ST2, ST3)
+  { copy(l2, l3); add(l1, l3, ST1(), ST3()); }
+
+  template <typename L1, typename L2, typename L3> inline
+  void add(const L1& l1, const L2& l2, L3& l3,
+	   abstract_sparse, abstract_dense, abstract_dense) {
+    add_almost_full_(vect_const_begin(l1), vect_const_end(l1),
+		     vect_const_begin(l2), vect_begin(l3), vect_end(l3));
+  }
+  
+  template <typename L1, typename L2, typename L3> inline
+  void add(const L1& l1, const L2& l2, L3& l3,
+	   abstract_dense, abstract_sparse, abstract_dense)
+  { add(l2, l1, l3, abstract_sparse(), abstract_dense(), abstract_dense()); }
+  
+  template <typename L1, typename L2, typename L3> inline
+  void add(const L1& l1, const L2& l2, L3& l3,
+	   abstract_sparse, abstract_sparse, abstract_dense) {
+    add_to_full_(vect_const_begin(l1), vect_const_end(l1),
+		 vect_const_begin(l2), vect_const_end(l2),
+		 vect_begin(l3), vect_end(l3));
+  }
+
+
+  template <typename L1, typename L2, typename L3>
+  void add_spspsp(const L1& l1, const L2& l2, L3& l3, linalg_true) {
+    typename linalg_traits<L1>::const_iterator
+      it1 = vect_const_begin(l1), ite1 = vect_const_end(l1);
+    typename linalg_traits<L2>::const_iterator
+      it2 = vect_const_begin(l2), ite2 = vect_const_end(l2);
+    clear(l3);
+    while (it1 != ite1 && it2 != ite2) {
+      ptrdiff_t d = it1.index() - it2.index();
+      if (d < 0)
+	{ l3[it1.index()] += *it1; ++it1; }
+      else if (d > 0)
+	{ l3[it2.index()] += *it2; ++it2; }
+      else
+	{ l3[it1.index()] = *it1 + *it2; ++it1; ++it2; }
+    }
+    for (; it1 != ite1; ++it1) l3[it1.index()] += *it1;
+    for (; it2 != ite2; ++it2) l3[it2.index()] += *it2;   
+  }
+
+  template <typename L1, typename L2, typename L3>
+  void add_spspsp(const L1& l1, const L2& l2, L3& l3, linalg_false)
+  { copy(l2, l3); add(l2, l3); }
+  
+  template <typename L1, typename L2, typename L3>
+  void add(const L1& l1, const L2& l2, L3& l3,
+	   abstract_sparse, abstract_sparse, abstract_sparse) {
+    add_spspsp(l1, l2, l3, typename linalg_and<typename
+	       linalg_traits<L1>::index_sorted,
+	       typename linalg_traits<L2>::index_sorted>::bool_type());
+  }
+
+  template <typename L1, typename L2>
+  void add(const L1& l1, L2& l2, abstract_dense, abstract_dense) {
+    typename linalg_traits<L1>::const_iterator it1 = vect_const_begin(l1); 
+    typename linalg_traits<L2>::iterator
+             it2 = vect_begin(l2), ite = vect_end(l2);
+    for (; it2 != ite; ++it2, ++it1) *it2 += *it1;
+  }
+
+  template <typename L1, typename L2>
+  void add(const L1& l1, L2& l2, abstract_dense, abstract_skyline) {
+    typedef typename linalg_traits<L1>::const_iterator const_l1_iterator;
+    typedef typename linalg_traits<L2>::iterator l2_iterator;
+    typedef typename linalg_traits<L1>::value_type T;
+
+    const_l1_iterator it1 = vect_const_begin(l1), ite1 = vect_const_end(l1); 
+    size_type i1 = 0, ie1 = vect_size(l1);
+    while (it1 != ite1 && *it1 == T(0)) { ++it1; ++i1; }
+    if (it1 != ite1) {
+      l2_iterator it2 = vect_begin(l2), ite2 = vect_end(l2);
+      while (ie1 && *(ite1-1) == T(0)) { ite1--; --ie1; }
+
+      if (it2 == ite2 || i1 < it2.index()) {
+	l2[i1] = *it1; ++i1; ++it1;
+	if (it1 == ite1) return;
+	it2 = vect_begin(l2); ite2 = vect_end(l2);
+      }
+      if (ie1 > ite2.index()) {
+	--ite1; l2[ie1 - 1] = *ite1;
+	it2 = vect_begin(l2);
+      }
+      it2 += i1 - it2.index();
+      for (; it1 != ite1; ++it1, ++it2) { *it2 += *it1; }
+    }
+  }
+
+
+  template <typename L1, typename L2>
+  void add(const L1& l1, L2& l2, abstract_skyline, abstract_dense) {
+    typename linalg_traits<L1>::const_iterator it1 = vect_const_begin(l1),
+      ite1 = vect_const_end(l1);
+    if (it1 != ite1) {
+      typename linalg_traits<L2>::iterator it2 = vect_begin(l2);
+      it2 += it1.index();
+      for (; it1 != ite1; ++it2, ++it1) *it2 += *it1;
+    }
+  }
+
+  
+  template <typename L1, typename L2>
+  void add(const L1& l1, L2& l2, abstract_sparse, abstract_dense) {
+    typename linalg_traits<L1>::const_iterator
+      it1 = vect_const_begin(l1), ite1 = vect_const_end(l1);
+    for (; it1 != ite1; ++it1) l2[it1.index()] += *it1;
+  }
+  
+  template <typename L1, typename L2>
+  void add(const L1& l1, L2& l2, abstract_sparse, abstract_sparse) {
+    typename linalg_traits<L1>::const_iterator
+      it1 = vect_const_begin(l1), ite1 = vect_const_end(l1);
+    for (; it1 != ite1; ++it1) l2[it1.index()] += *it1;
+  }
+
+  template <typename L1, typename L2>
+  void add(const L1& l1, L2& l2, abstract_sparse, abstract_skyline) {
+    typename linalg_traits<L1>::const_iterator
+      it1 = vect_const_begin(l1), ite1 = vect_const_end(l1);
+    for (; it1 != ite1; ++it1) l2[it1.index()] += *it1;
+  }
+
+
+  template <typename L1, typename L2>
+  void add(const L1& l1, L2& l2, abstract_skyline, abstract_sparse) {
+    typename linalg_traits<L1>::const_iterator
+      it1 = vect_const_begin(l1), ite1 = vect_const_end(l1);
+    for (; it1 != ite1; ++it1)
+      if (*it1 != typename linalg_traits<L1>::value_type(0))
+	l2[it1.index()] += *it1;
+  }
+
+  template <typename L1, typename L2>
+  void add(const L1& l1, L2& l2, abstract_skyline, abstract_skyline) {
+    typedef typename linalg_traits<L1>::const_iterator const_l1_iterator;
+    typedef typename linalg_traits<L2>::iterator l2_iterator;
+    typedef typename linalg_traits<L1>::value_type T1;
+    typedef typename linalg_traits<L2>::value_type T2;
+
+    const_l1_iterator it1 = vect_const_begin(l1), ite1 = vect_const_end(l1);
+    
+    while (it1 != ite1 && *it1 == T1(0)) ++it1;
+    if (ite1 != it1) {
+      l2_iterator it2 = vect_begin(l2), ite2 = vect_end(l2);
+      while (*(ite1-1) == T1(0)) ite1--;
+      if (it2 == ite2 || it1.index() < it2.index()) {
+	l2[it1.index()] = T2(0);
+	it2 = vect_begin(l2); ite2 = vect_end(l2);
+      }
+      if (ite1.index() > ite2.index()) {
+	l2[ite1.index() - 1] = T2(0);
+	it2 = vect_begin(l2); 
+      }
+      it2 += it1.index() - it2.index();
+      for (; it1 != ite1; ++it1, ++it2) *it2 += *it1;
+    }
+  }
+  
+  template <typename L1, typename L2>
+  void add(const L1& l1, L2& l2, abstract_dense, abstract_sparse) {
+    typename linalg_traits<L1>::const_iterator
+      it1 = vect_const_begin(l1), ite1 = vect_const_end(l1);
+    for (size_type i = 0; it1 != ite1; ++it1, ++i)
+      if (*it1 != typename linalg_traits<L1>::value_type(0)) l2[i] += *it1;
+  } 
+
+  /* ******************************************************************** */
+  /*		Matrix-vector mult                                    	  */
+  /* ******************************************************************** */
+  ///@endcond
+  /** matrix-vector or matrix-matrix product.
+      @param l1 a matrix.
+      @param l2 a vector or matrix.
+      @param l3 the product l1*l2.
+  */
+  template <typename L1, typename L2, typename L3> inline
+  void mult(const L1& l1, const L2& l2, L3& l3) {
+    mult_dispatch(l1, l2, l3, typename linalg_traits<L2>::linalg_type());
+  }
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+  template <typename L1, typename L2, typename L3> inline
+  void mult(const L1& l1, const L2& l2, const L3& l3)
+  { mult(l1, l2, linalg_const_cast(l3)); }
+
+  template <typename L1, typename L2, typename L3> inline
+  void mult_dispatch(const L1& l1, const L2& l2, L3& l3, abstract_vector) {
+    size_type m = mat_nrows(l1), n = mat_ncols(l1);
+    if (!m || !n) { gmm::clear(l3); return; }
+    GMM_ASSERT2(n==vect_size(l2) && m==vect_size(l3), "dimensions mismatch");
+    if (!same_origin(l2, l3))
+      mult_spec(l1, l2, l3, typename principal_orientation_type<typename
+		linalg_traits<L1>::sub_orientation>::potype());
+    else {
+      GMM_WARNING2("Warning, A temporary is used for mult\n");
+      typename temporary_vector<L3>::vector_type temp(vect_size(l3));
+      mult_spec(l1, l2, temp, typename principal_orientation_type<typename
+		linalg_traits<L1>::sub_orientation>::potype());
+      copy(temp, l3);
+    }
+  }
+
+  template <typename L1, typename L2, typename L3>
+  void mult_by_row(const L1& l1, const L2& l2, L3& l3, abstract_sparse) {
+    typedef typename  linalg_traits<L3>::value_type T;
+    clear(l3);
+    size_type nr = mat_nrows(l1);
+    for (size_type i = 0; i < nr; ++i) {
+      T aux = vect_sp(mat_const_row(l1, i), l2);
+      if (aux != T(0)) l3[i] = aux;
+    }
+  }
+
+  template <typename L1, typename L2, typename L3>
+  void mult_by_row(const L1& l1, const L2& l2, L3& l3, abstract_skyline) {
+    typedef typename  linalg_traits<L3>::value_type T;
+    clear(l3); 
+    size_type nr = mat_nrows(l1);
+    for (size_type i = 0; i < nr; ++i) {
+      T aux = vect_sp(mat_const_row(l1, i), l2);
+      if (aux != T(0)) l3[i] = aux;
+    }
+  }
+
+  template <typename L1, typename L2, typename L3>
+  void mult_by_row(const L1& l1, const L2& l2, L3& l3, abstract_dense) {
+    typename linalg_traits<L3>::iterator it=vect_begin(l3), ite=vect_end(l3);
+    typename linalg_traits<L1>::const_row_iterator
+      itr = mat_row_const_begin(l1); 
+    for (; it != ite; ++it, ++itr)
+      *it = vect_sp(linalg_traits<L1>::row(itr), l2,
+		    typename linalg_traits<L1>::storage_type(),
+		    typename linalg_traits<L2>::storage_type());
+  }
+
+  template <typename L1, typename L2, typename L3>
+  void mult_by_col(const L1& l1, const L2& l2, L3& l3, abstract_dense) {
+    clear(l3);
+    size_type nc = mat_ncols(l1);
+    for (size_type i = 0; i < nc; ++i)
+      add(scaled(mat_const_col(l1, i), l2[i]), l3);
+  }
+
+  template <typename L1, typename L2, typename L3>
+  void mult_by_col(const L1& l1, const L2& l2, L3& l3, abstract_sparse) {
+    typedef typename linalg_traits<L2>::value_type T;
+    clear(l3);
+    typename linalg_traits<L2>::const_iterator it = vect_const_begin(l2),
+      ite = vect_const_end(l2);
+    for (; it != ite; ++it)
+      if (*it != T(0)) add(scaled(mat_const_col(l1, it.index()), *it), l3);
+  }
+
+  template <typename L1, typename L2, typename L3>
+  void mult_by_col(const L1& l1, const L2& l2, L3& l3, abstract_skyline) {
+    typedef typename linalg_traits<L2>::value_type T;
+    clear(l3); 
+    typename linalg_traits<L2>::const_iterator it = vect_const_begin(l2),
+      ite = vect_const_end(l2);
+    for (; it != ite; ++it)
+      if (*it != T(0)) add(scaled(mat_const_col(l1, it.index()), *it), l3);
+  }
+
+  template <typename L1, typename L2, typename L3> inline
+  void mult_spec(const L1& l1, const L2& l2, L3& l3, row_major)
+  { mult_by_row(l1, l2, l3, typename linalg_traits<L3>::storage_type()); }
+
+  template <typename L1, typename L2, typename L3> inline
+  void mult_spec(const L1& l1, const L2& l2, L3& l3, col_major)
+  { mult_by_col(l1, l2, l3, typename linalg_traits<L2>::storage_type()); }
+
+  template <typename L1, typename L2, typename L3> inline
+  void mult_spec(const L1& l1, const L2& l2, L3& l3, abstract_null_type)
+  { mult_ind(l1, l2, l3, typename linalg_traits<L1>::storage_type()); }
+
+  template <typename L1, typename L2, typename L3>
+  void mult_ind(const L1& l1, const L2& l2, L3& l3, abstract_indirect) {
+    GMM_ASSERT1(false, "gmm::mult(m, ., .) undefined for this kind of matrix");
+  }
+
+  template <typename L1, typename L2, typename L3, typename L4> inline
+  void mult(const L1& l1, const L2& l2, const L3& l3, L4& l4) {
+    size_type m = mat_nrows(l1), n = mat_ncols(l1);
+    copy(l3, l4);
+    if (!m || !n) { gmm::copy(l3, l4); return; }
+    GMM_ASSERT2(n==vect_size(l2) && m==vect_size(l4), "dimensions mismatch");
+    if (!same_origin(l2, l4)) {
+      mult_add_spec(l1, l2, l4, typename principal_orientation_type<typename
+		    linalg_traits<L1>::sub_orientation>::potype());
+    }
+    else {
+      GMM_WARNING2("Warning, A temporary is used for mult\n");
+      typename temporary_vector<L2>::vector_type temp(vect_size(l2));
+      copy(l2, temp);
+      mult_add_spec(l1,temp, l4, typename principal_orientation_type<typename
+		linalg_traits<L1>::sub_orientation>::potype());
+    }
+  }
+
+  template <typename L1, typename L2, typename L3, typename L4> inline
+  void mult(const L1& l1, const L2& l2, const L3& l3, const L4& l4)
+  { mult(l1, l2, l3, linalg_const_cast(l4)); } 
+
+  ///@endcond
+  /** Multiply-accumulate. l3 += l1*l2; */
+  template <typename L1, typename L2, typename L3> inline
+  void mult_add(const L1& l1, const L2& l2, L3& l3) {
+    size_type m = mat_nrows(l1), n = mat_ncols(l1);
+    if (!m || !n) return;
+    GMM_ASSERT2(n==vect_size(l2) && m==vect_size(l3), "dimensions mismatch");
+    if (!same_origin(l2, l3)) {
+      mult_add_spec(l1, l2, l3, typename principal_orientation_type<typename
+		    linalg_traits<L1>::sub_orientation>::potype());
+    }
+    else {
+      GMM_WARNING2("Warning, A temporary is used for mult\n");
+      typename temporary_vector<L3>::vector_type temp(vect_size(l2));
+      copy(l2, temp);
+      mult_add_spec(l1,temp, l3, typename principal_orientation_type<typename
+		linalg_traits<L1>::sub_orientation>::potype());
+    }
+  }
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+  template <typename L1, typename L2, typename L3> inline
+  void mult_add(const L1& l1, const L2& l2, const L3& l3)
+  { mult_add(l1, l2, linalg_const_cast(l3)); } 
+
+  template <typename L1, typename L2, typename L3>
+  void mult_add_by_row(const L1& l1, const L2& l2, L3& l3, abstract_sparse) {
+    typedef typename linalg_traits<L3>::value_type T;
+    size_type nr = mat_nrows(l1);
+    for (size_type i = 0; i < nr; ++i) {
+      T aux = vect_sp(mat_const_row(l1, i), l2);
+      if (aux != T(0)) l3[i] += aux;
+    }
+  }
+
+  template <typename L1, typename L2, typename L3>
+  void mult_add_by_row(const L1& l1, const L2& l2, L3& l3, abstract_skyline) {
+    typedef typename linalg_traits<L3>::value_type T;
+    size_type nr = mat_nrows(l1);
+    for (size_type i = 0; i < nr; ++i) {
+      T aux = vect_sp(mat_const_row(l1, i), l2);
+      if (aux != T(0)) l3[i] += aux;
+    }
+  }
+
+  template <typename L1, typename L2, typename L3>
+  void mult_add_by_row(const L1& l1, const L2& l2, L3& l3, abstract_dense) {
+    typename linalg_traits<L3>::iterator it=vect_begin(l3), ite=vect_end(l3);
+    typename linalg_traits<L1>::const_row_iterator
+      itr = mat_row_const_begin(l1);
+    for (; it != ite; ++it, ++itr)
+      *it += vect_sp(linalg_traits<L1>::row(itr), l2);
+  }
+
+  template <typename L1, typename L2, typename L3>
+  void mult_add_by_col(const L1& l1, const L2& l2, L3& l3, abstract_dense) {
+    size_type nc = mat_ncols(l1);
+    for (size_type i = 0; i < nc; ++i)
+      add(scaled(mat_const_col(l1, i), l2[i]), l3);
+  }
+
+  template <typename L1, typename L2, typename L3>
+  void mult_add_by_col(const L1& l1, const L2& l2, L3& l3, abstract_sparse) {
+    typename linalg_traits<L2>::const_iterator it = vect_const_begin(l2),
+      ite = vect_const_end(l2);
+    for (; it != ite; ++it)
+      if (*it != typename linalg_traits<L2>::value_type(0))
+	add(scaled(mat_const_col(l1, it.index()), *it), l3);
+  }
+
+  template <typename L1, typename L2, typename L3>
+  void mult_add_by_col(const L1& l1, const L2& l2, L3& l3, abstract_skyline) {
+    typename linalg_traits<L2>::const_iterator it = vect_const_begin(l2),
+      ite = vect_const_end(l2);
+    for (; it != ite; ++it)
+      if (*it != typename linalg_traits<L2>::value_type(0))
+	add(scaled(mat_const_col(l1, it.index()), *it), l3);
+  }
+
+  template <typename L1, typename L2, typename L3> inline
+  void mult_add_spec(const L1& l1, const L2& l2, L3& l3, row_major)
+  { mult_add_by_row(l1, l2, l3, typename linalg_traits<L3>::storage_type()); }
+
+  template <typename L1, typename L2, typename L3> inline
+  void mult_add_spec(const L1& l1, const L2& l2, L3& l3, col_major)
+  { mult_add_by_col(l1, l2, l3, typename linalg_traits<L2>::storage_type()); }
+
+  template <typename L1, typename L2, typename L3> inline
+  void mult_add_spec(const L1& l1, const L2& l2, L3& l3, abstract_null_type)
+  { mult_ind(l1, l2, l3, typename linalg_traits<L1>::storage_type()); }
+
+  template <typename L1, typename L2, typename L3>
+  void transposed_mult(const L1& l1, const L2& l2, const L3& l3)
+  { mult(gmm::transposed(l1), l2, l3); }
+
+
+  /* ******************************************************************** */
+  /*		Matrix-matrix mult                                    	  */
+  /* ******************************************************************** */
+  
+
+  struct g_mult {};  // generic mult, less optimized
+  struct c_mult {};  // col x col -> col mult
+  struct r_mult {};  // row x row -> row mult
+  struct rcmult {};  // row x col -> col mult
+  struct crmult {};  // col x row -> row mult
+
+
+  template<typename SO1, typename SO2, typename SO3> struct mult_t;
+  #define DEFMU__ template<> struct mult_t
+  DEFMU__<row_major  , row_major  , row_major  > { typedef r_mult t; };
+  DEFMU__<row_major  , row_major  , col_major  > { typedef g_mult t; };
+  DEFMU__<row_major  , row_major  , col_and_row> { typedef r_mult t; };
+  DEFMU__<row_major  , row_major  , row_and_col> { typedef r_mult t; };
+  DEFMU__<row_major  , col_major  , row_major  > { typedef rcmult t; };
+  DEFMU__<row_major  , col_major  , col_major  > { typedef rcmult t; };
+  DEFMU__<row_major  , col_major  , col_and_row> { typedef rcmult t; };
+  DEFMU__<row_major  , col_major  , row_and_col> { typedef rcmult t; };
+  DEFMU__<row_major  , col_and_row, row_major  > { typedef r_mult t; };
+  DEFMU__<row_major  , col_and_row, col_major  > { typedef rcmult t; };
+  DEFMU__<row_major  , col_and_row, col_and_row> { typedef rcmult t; };
+  DEFMU__<row_major  , col_and_row, row_and_col> { typedef rcmult t; };
+  DEFMU__<row_major  , row_and_col, row_major  > { typedef r_mult t; };
+  DEFMU__<row_major  , row_and_col, col_major  > { typedef rcmult t; };
+  DEFMU__<row_major  , row_and_col, col_and_row> { typedef r_mult t; };
+  DEFMU__<row_major  , row_and_col, row_and_col> { typedef r_mult t; };
+  DEFMU__<col_major  , row_major  , row_major  > { typedef crmult t; };
+  DEFMU__<col_major  , row_major  , col_major  > { typedef g_mult t; };
+  DEFMU__<col_major  , row_major  , col_and_row> { typedef crmult t; };
+  DEFMU__<col_major  , row_major  , row_and_col> { typedef crmult t; };
+  DEFMU__<col_major  , col_major  , row_major  > { typedef g_mult t; };
+  DEFMU__<col_major  , col_major  , col_major  > { typedef c_mult t; };
+  DEFMU__<col_major  , col_major  , col_and_row> { typedef c_mult t; };
+  DEFMU__<col_major  , col_major  , row_and_col> { typedef c_mult t; };
+  DEFMU__<col_major  , col_and_row, row_major  > { typedef crmult t; };
+  DEFMU__<col_major  , col_and_row, col_major  > { typedef c_mult t; };
+  DEFMU__<col_major  , col_and_row, col_and_row> { typedef c_mult t; };
+  DEFMU__<col_major  , col_and_row, row_and_col> { typedef c_mult t; };
+  DEFMU__<col_major  , row_and_col, row_major  > { typedef crmult t; };
+  DEFMU__<col_major  , row_and_col, col_major  > { typedef c_mult t; };
+  DEFMU__<col_major  , row_and_col, col_and_row> { typedef c_mult t; };
+  DEFMU__<col_major  , row_and_col, row_and_col> { typedef c_mult t; };
+  DEFMU__<col_and_row, row_major  , row_major  > { typedef r_mult t; };
+  DEFMU__<col_and_row, row_major  , col_major  > { typedef c_mult t; };
+  DEFMU__<col_and_row, row_major  , col_and_row> { typedef r_mult t; };
+  DEFMU__<col_and_row, row_major  , row_and_col> { typedef r_mult t; };
+  DEFMU__<col_and_row, col_major  , row_major  > { typedef rcmult t; };
+  DEFMU__<col_and_row, col_major  , col_major  > { typedef c_mult t; };
+  DEFMU__<col_and_row, col_major  , col_and_row> { typedef c_mult t; };
+  DEFMU__<col_and_row, col_major  , row_and_col> { typedef c_mult t; };
+  DEFMU__<col_and_row, col_and_row, row_major  > { typedef r_mult t; };
+  DEFMU__<col_and_row, col_and_row, col_major  > { typedef c_mult t; };
+  DEFMU__<col_and_row, col_and_row, col_and_row> { typedef c_mult t; };
+  DEFMU__<col_and_row, col_and_row, row_and_col> { typedef c_mult t; };
+  DEFMU__<col_and_row, row_and_col, row_major  > { typedef r_mult t; };
+  DEFMU__<col_and_row, row_and_col, col_major  > { typedef c_mult t; };
+  DEFMU__<col_and_row, row_and_col, col_and_row> { typedef c_mult t; };
+  DEFMU__<col_and_row, row_and_col, row_and_col> { typedef r_mult t; };
+  DEFMU__<row_and_col, row_major  , row_major  > { typedef r_mult t; };
+  DEFMU__<row_and_col, row_major  , col_major  > { typedef c_mult t; };
+  DEFMU__<row_and_col, row_major  , col_and_row> { typedef r_mult t; };
+  DEFMU__<row_and_col, row_major  , row_and_col> { typedef r_mult t; };
+  DEFMU__<row_and_col, col_major  , row_major  > { typedef rcmult t; };
+  DEFMU__<row_and_col, col_major  , col_major  > { typedef c_mult t; };
+  DEFMU__<row_and_col, col_major  , col_and_row> { typedef c_mult t; };
+  DEFMU__<row_and_col, col_major  , row_and_col> { typedef c_mult t; };
+  DEFMU__<row_and_col, col_and_row, row_major  > { typedef rcmult t; };
+  DEFMU__<row_and_col, col_and_row, col_major  > { typedef rcmult t; };
+  DEFMU__<row_and_col, col_and_row, col_and_row> { typedef rcmult t; };
+  DEFMU__<row_and_col, col_and_row, row_and_col> { typedef rcmult t; };
+  DEFMU__<row_and_col, row_and_col, row_major  > { typedef r_mult t; };
+  DEFMU__<row_and_col, row_and_col, col_major  > { typedef c_mult t; };
+  DEFMU__<row_and_col, row_and_col, col_and_row> { typedef r_mult t; };
+  DEFMU__<row_and_col, row_and_col, row_and_col> { typedef r_mult t; };
+
+  template <typename L1, typename L2, typename L3>
+  void mult_dispatch(const L1& l1, const L2& l2, L3& l3, abstract_matrix) {
+    typedef typename temporary_matrix<L3>::matrix_type temp_mat_type;
+    size_type m = mat_nrows(l1), n = mat_ncols(l1), k = mat_ncols(l2);
+    if (n == 0) { gmm::clear(l3); return; }
+    GMM_ASSERT2(n == mat_nrows(l2) && m == mat_nrows(l3) && k == mat_ncols(l3),
+		"dimensions mismatch");
+
+    if (same_origin(l2, l3) || same_origin(l1, l3)) {
+      GMM_WARNING2("A temporary is used for mult");
+      temp_mat_type temp(mat_nrows(l3), mat_ncols(l3));
+      mult_spec(l1, l2, temp, typename mult_t<
+		typename linalg_traits<L1>::sub_orientation,
+		typename linalg_traits<L2>::sub_orientation,
+		typename linalg_traits<temp_mat_type>::sub_orientation>::t());
+      copy(temp, l3);
+    }
+    else
+      mult_spec(l1, l2, l3, typename mult_t<
+		typename linalg_traits<L1>::sub_orientation,
+		typename linalg_traits<L2>::sub_orientation,
+		typename linalg_traits<L3>::sub_orientation>::t());
+  }
+
+  // Completely generic but inefficient
+
+  template <typename L1, typename L2, typename L3>
+  void mult_spec(const L1& l1, const L2& l2, L3& l3, g_mult) {
+    typedef typename linalg_traits<L3>::value_type T;
+    GMM_WARNING2("Inefficient generic matrix-matrix mult is used");
+    for (size_type i = 0; i < mat_nrows(l3) ; ++i)
+      for (size_type j = 0; j < mat_ncols(l3) ; ++j) {
+	T a(0);
+	for (size_type k = 0; k < mat_nrows(l2) ; ++k) a += l1(i, k)*l2(k, j);
+	l3(i, j) = a;
+      }
+  }
+
+  // row x col matrix-matrix mult
+
+  template <typename L1, typename L2, typename L3>
+  void mult_row_col_with_temp(const L1& l1, const L2& l2, L3& l3, col_major) {
+    typedef typename temporary_col_matrix<L1>::matrix_type temp_col_mat;
+    temp_col_mat temp(mat_nrows(l1), mat_ncols(l1));
+    copy(l1, temp);
+    mult(temp, l2, l3);
+  }
+
+  template <typename L1, typename L2, typename L3>
+  void mult_row_col_with_temp(const L1& l1, const L2& l2, L3& l3, row_major) {
+    typedef typename temporary_row_matrix<L2>::matrix_type temp_row_mat;
+    temp_row_mat temp(mat_nrows(l2), mat_ncols(l2));
+    copy(l2, temp);
+    mult(l1, temp, l3);
+  }
+
+  template <typename L1, typename L2, typename L3>
+  void mult_spec(const L1& l1, const L2& l2, L3& l3, rcmult) {
+    if (is_sparse(l1) && is_sparse(l2)) {
+      GMM_WARNING3("Inefficient row matrix - col matrix mult for "
+		  "sparse matrices, using temporary");
+      mult_row_col_with_temp(l1, l2, l3, 
+			     typename principal_orientation_type<typename
+			     linalg_traits<L3>::sub_orientation>::potype());
+    }
+    else {
+      typename linalg_traits<L2>::const_col_iterator
+	it2b = linalg_traits<L2>::col_begin(l2), it2,
+	ite = linalg_traits<L2>::col_end(l2);
+      size_type i,j, k = mat_nrows(l1);
+      
+      for (i = 0; i < k; ++i) {
+	typename linalg_traits<L1>::const_sub_row_type r1=mat_const_row(l1, i);
+	for (it2 = it2b, j = 0; it2 != ite; ++it2, ++j)
+	  l3(i,j) = vect_sp(r1, linalg_traits<L2>::col(it2));
+      }
+    }
+  }
+
+  // row - row matrix-matrix mult
+
+  template <typename L1, typename L2, typename L3> inline
+  void mult_spec(const L1& l1, const L2& l2, L3& l3, r_mult) {
+    mult_spec(l1, l2, l3,r_mult(),typename linalg_traits<L1>::storage_type());
+  }
+
+  template <typename L1, typename L2, typename L3>
+  void mult_spec(const L1& l1, const L2& l2, L3& l3, r_mult, abstract_dense) {
+    // optimizable
+    clear(l3);
+    size_type nn = mat_nrows(l3), mm = mat_nrows(l2);
+    for (size_type i = 0; i < nn; ++i) {
+      for (size_type j = 0; j < mm; ++j) {
+	add(scaled(mat_const_row(l2, j), l1(i, j)), mat_row(l3, i));
+      }
+    }
+  }
+
+  template <typename L1, typename L2, typename L3>
+  void mult_spec(const L1& l1, const L2& l2, L3& l3, r_mult, abstract_sparse) {
+    // optimizable
+    clear(l3);
+    size_type nn = mat_nrows(l3);
+    for (size_type i = 0; i < nn; ++i) {
+      typename linalg_traits<L1>::const_sub_row_type rl1=mat_const_row(l1, i);
+      typename linalg_traits<typename linalg_traits<L1>::const_sub_row_type>::
+	const_iterator it = vect_const_begin(rl1), ite = vect_const_end(rl1);
+      for (; it != ite; ++it)
+	add(scaled(mat_const_row(l2, it.index()), *it), mat_row(l3, i));
+    }
+  }
+
+  template <typename L1, typename L2, typename L3>
+  void mult_spec(const L1& l1, const L2& l2, L3& l3, r_mult, abstract_skyline)
+  { mult_spec(l1, l2, l3, r_mult(), abstract_sparse()); }
+
+  // col - col matrix-matrix mult
+
+  template <typename L1, typename L2, typename L3> inline
+  void mult_spec(const L1& l1, const L2& l2, L3& l3, c_mult) {
+    mult_spec(l1, l2,l3,c_mult(),typename linalg_traits<L2>::storage_type(),
+	      typename linalg_traits<L2>::sub_orientation());
+  }
+
+
+  template <typename L1, typename L2, typename L3, typename ORIEN>
+  void mult_spec(const L1& l1, const L2& l2, L3& l3, c_mult,
+		 abstract_dense, ORIEN) {
+    typedef typename linalg_traits<L2>::value_type T;
+    size_type nn = mat_ncols(l3), mm = mat_ncols(l1);
+
+    for (size_type i = 0; i < nn; ++i) {
+      clear(mat_col(l3, i));
+      for (size_type j = 0; j < mm; ++j) {
+	T b = l2(j, i);
+	if (b != T(0)) add(scaled(mat_const_col(l1, j), b), mat_col(l3, i));
+      }
+    }
+  }
+
+  template <typename L1, typename L2, typename L3, typename ORIEN>
+  void mult_spec(const L1& l1, const L2& l2, L3& l3, c_mult,
+		 abstract_sparse, ORIEN) {
+    // optimizable
+    clear(l3);
+    size_type nn = mat_ncols(l3);
+    for (size_type i = 0; i < nn; ++i) {
+      typename linalg_traits<L2>::const_sub_col_type rc2=mat_const_col(l2, i);
+      typename linalg_traits<typename linalg_traits<L2>::const_sub_col_type>::
+	const_iterator it = vect_const_begin(rc2), ite = vect_const_end(rc2);
+      for (; it != ite; ++it)
+	add(scaled(mat_const_col(l1, it.index()), *it), mat_col(l3, i));
+    }
+  }
+
+  template <typename L1, typename L2, typename L3>
+  void mult_spec(const L1& l1, const L2& l2, L3& l3, c_mult,
+		 abstract_sparse, row_major) {
+     typedef typename linalg_traits<L2>::value_type T;
+     GMM_WARNING3("Inefficient matrix-matrix mult for sparse matrices");
+     clear(l3);
+     size_type mm = mat_nrows(l2), nn = mat_ncols(l3);
+     for (size_type i = 0; i < nn; ++i)
+       for (size_type j = 0; j < mm; ++j) {
+	 T a = l2(i,j);
+	 if (a != T(0)) add(scaled(mat_const_col(l1, j), a), mat_col(l3, i));
+       }
+   }
+
+  template <typename L1, typename L2, typename L3, typename ORIEN> inline
+  void mult_spec(const L1& l1, const L2& l2, L3& l3, c_mult,
+		 abstract_skyline, ORIEN)
+  { mult_spec(l1, l2, l3, c_mult(), abstract_sparse(), ORIEN()); }
+
+  
+  // col - row matrix-matrix mult
+
+  template <typename L1, typename L2, typename L3> inline
+  void mult_spec(const L1& l1, const L2& l2, L3& l3, crmult)
+  { mult_spec(l1,l2,l3,crmult(), typename linalg_traits<L1>::storage_type()); }
+
+
+  template <typename L1, typename L2, typename L3>
+  void mult_spec(const L1& l1, const L2& l2, L3& l3, crmult, abstract_dense) {
+    // optimizable
+    clear(l3);
+    size_type nn = mat_ncols(l1), mm = mat_nrows(l1);
+    for (size_type i = 0; i < nn; ++i) {
+      for (size_type j = 0; j < mm; ++j)
+      add(scaled(mat_const_row(l2, i), l1(j, i)), mat_row(l3, j));
+    }
+  }
+
+  template <typename L1, typename L2, typename L3>
+  void mult_spec(const L1& l1, const L2& l2, L3& l3, crmult, abstract_sparse) {
+    // optimizable
+    clear(l3);
+    size_type nn = mat_ncols(l1);
+    for (size_type i = 0; i < nn; ++i) {
+      typename linalg_traits<L1>::const_sub_col_type rc1=mat_const_col(l1, i);
+      typename linalg_traits<typename linalg_traits<L1>::const_sub_col_type>::
+	const_iterator it = vect_const_begin(rc1), ite = vect_const_end(rc1);
+      for (; it != ite; ++it)
+	add(scaled(mat_const_row(l2, i), *it), mat_row(l3, it.index()));
+    }
+  }
+
+  template <typename L1, typename L2, typename L3> inline
+  void mult_spec(const L1& l1, const L2& l2, L3& l3, crmult, abstract_skyline)
+  { mult_spec(l1, l2, l3, crmult(), abstract_sparse()); }
+  
+
+  /* ******************************************************************** */
+  /*		Symmetry test.                                     	  */
+  /* ******************************************************************** */
+
+  ///@endcond
+  /** test if A is symmetric.
+      @param A a matrix.
+      @param tol a threshold.
+  */
+  template <typename MAT> inline
+  bool is_symmetric(const MAT &A, magnitude_of_linalg(MAT) tol
+		    = magnitude_of_linalg(MAT)(-1)) {
+    typedef magnitude_of_linalg(MAT) R;
+    if (tol < R(0)) tol = default_tol(R()) * mat_maxnorm(A);
+    if (mat_nrows(A) != mat_ncols(A)) return false;
+    return is_symmetric(A, tol, typename linalg_traits<MAT>::storage_type());
+  }
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+  template <typename MAT> 
+  bool is_symmetric(const MAT &A, magnitude_of_linalg(MAT) tol, 
+		    abstract_dense) {
+    size_type m = mat_nrows(A);
+    for (size_type i = 1; i < m; ++i)
+      for (size_type j = 0; j < i; ++j)
+	if (gmm::abs(A(i, j)-A(j, i)) > tol) return false;
+    return true;
+  }
+
+  template <typename MAT> 
+  bool is_symmetric(const MAT &A, magnitude_of_linalg(MAT) tol, 
+		    abstract_sparse) {
+    return is_symmetric(A, tol, typename principal_orientation_type<typename
+			linalg_traits<MAT>::sub_orientation>::potype());
+  }
+
+  template <typename MAT> 
+  bool is_symmetric(const MAT &A, magnitude_of_linalg(MAT) tol, 
+		    row_major) {
+    for (size_type i = 0; i < mat_nrows(A); ++i) {
+      typedef typename linalg_traits<MAT>::const_sub_row_type row_type;
+      row_type row = mat_const_row(A, i);
+      typename linalg_traits<row_type>::const_iterator
+	it = vect_const_begin(row), ite = vect_const_end(row);
+      for (; it != ite; ++it)
+	if (gmm::abs(*it - A(it.index(), i)) > tol) return false;
+    }
+    return true;
+  }
+
+  template <typename MAT> 
+  bool is_symmetric(const MAT &A, magnitude_of_linalg(MAT) tol, 
+		    col_major) {
+    for (size_type i = 0; i < mat_ncols(A); ++i) {
+      typedef typename linalg_traits<MAT>::const_sub_col_type col_type;
+      col_type col = mat_const_col(A, i);
+      typename linalg_traits<col_type>::const_iterator
+	it = vect_const_begin(col), ite = vect_const_end(col);
+      for (; it != ite; ++it)
+	if (gmm::abs(*it - A(i, it.index())) > tol) return false;
+    }
+    return true;
+  }
+
+  template <typename MAT> 
+  bool is_symmetric(const MAT &A, magnitude_of_linalg(MAT) tol, 
+		    abstract_skyline)
+  { return is_symmetric(A, tol, abstract_sparse()); }
+
+  ///@endcond
+  /** test if A is Hermitian.
+      @param A a matrix.
+      @param tol a threshold.
+  */
+  template <typename MAT> inline
+  bool is_hermitian(const MAT &A, magnitude_of_linalg(MAT) tol
+		    = magnitude_of_linalg(MAT)(-1)) {
+    typedef magnitude_of_linalg(MAT) R;
+    if (tol < R(0)) tol = default_tol(R()) * mat_maxnorm(A);
+    if (mat_nrows(A) != mat_ncols(A)) return false;
+    return is_hermitian(A, tol, typename linalg_traits<MAT>::storage_type());
+  }
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+  template <typename MAT> 
+  bool is_hermitian(const MAT &A, magnitude_of_linalg(MAT) tol,
+		    abstract_dense) {
+    size_type m = mat_nrows(A);
+    for (size_type i = 1; i < m; ++i)
+      for (size_type j = 0; j < i; ++j)
+	if (gmm::abs(A(i, j)-gmm::conj(A(j, i))) > tol) return false;
+    return true;
+  }
+
+  template <typename MAT> 
+  bool is_hermitian(const MAT &A, magnitude_of_linalg(MAT) tol, 
+		    abstract_sparse) {
+    return is_hermitian(A, tol, typename principal_orientation_type<typename
+			linalg_traits<MAT>::sub_orientation>::potype());
+  }
+
+  template <typename MAT> 
+  bool is_hermitian(const MAT &A, magnitude_of_linalg(MAT) tol, 
+		    row_major) {
+    for (size_type i = 0; i < mat_nrows(A); ++i) {
+      typedef typename linalg_traits<MAT>::const_sub_row_type row_type;
+      row_type row = mat_const_row(A, i);
+      typename linalg_traits<row_type>::const_iterator
+	it = vect_const_begin(row), ite = vect_const_end(row);
+      for (; it != ite; ++it)
+	if (gmm::abs(gmm::conj(*it) - A(it.index(), i)) > tol) return false;
+    }
+    return true;
+  }
+
+  template <typename MAT> 
+  bool is_hermitian(const MAT &A, magnitude_of_linalg(MAT) tol, 
+		    col_major) {
+    for (size_type i = 0; i < mat_ncols(A); ++i) {
+      typedef typename linalg_traits<MAT>::const_sub_col_type col_type;
+      col_type col = mat_const_col(A, i);
+      typename linalg_traits<col_type>::const_iterator
+	it = vect_const_begin(col), ite = vect_const_end(col);
+      for (; it != ite; ++it)
+	if (gmm::abs(gmm::conj(*it) - A(i, it.index())) > tol) return false;
+    }
+    return true;
+  }
+
+  template <typename MAT> 
+  bool is_hermitian(const MAT &A, magnitude_of_linalg(MAT) tol, 
+		    abstract_skyline)
+  { return is_hermitian(A, tol, abstract_sparse()); }
+  ///@endcond
+}
+
+
+#endif //  GMM_BLAS_H__
diff --git a/Contrib/gmm/gmm_blas_interface.h b/Contrib/gmm/gmm_blas_interface.h
new file mode 100755
index 0000000..44e1dd8
--- /dev/null
+++ b/Contrib/gmm/gmm_blas_interface.h
@@ -0,0 +1,853 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_blas_interface.h
+   @author  Caroline Lecalvez, Caroline.Lecalvez at gmm.insa-tlse.fr, Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 7, 2003.
+   @brief gmm interface for fortran BLAS.
+*/
+
+#if defined(GETFEM_USES_BLAS) || defined(GMM_USES_BLAS) \
+  || defined(GMM_USES_LAPACK) || defined(GMM_USES_ATLAS)
+
+#ifndef GMM_BLAS_INTERFACE_H
+#define GMM_BLAS_INTERFACE_H
+
+#include "gmm_blas.h"
+#include "gmm_interface.h"
+#include "gmm_matrix.h"
+
+namespace gmm {
+
+#define GMMLAPACK_TRACE(f) 
+  // #define GMMLAPACK_TRACE(f) cout << "function " << f << " called" << endl;
+
+  /* ********************************************************************* */
+  /* Operations interfaced for T = float, double, std::complex<float>      */
+  /*    or std::complex<double> :                                          */
+  /*                                                                       */
+  /* vect_norm2(std::vector<T>)                                            */
+  /*                                                                       */
+  /* vect_sp(std::vector<T>, std::vector<T>)                               */
+  /* vect_sp(scaled(std::vector<T>), std::vector<T>)                       */
+  /* vect_sp(std::vector<T>, scaled(std::vector<T>))                       */
+  /* vect_sp(scaled(std::vector<T>), scaled(std::vector<T>))               */
+  /*                                                                       */
+  /* vect_hp(std::vector<T>, std::vector<T>)                               */
+  /* vect_hp(scaled(std::vector<T>), std::vector<T>)                       */
+  /* vect_hp(std::vector<T>, scaled(std::vector<T>))                       */
+  /* vect_hp(scaled(std::vector<T>), scaled(std::vector<T>))               */
+  /*                                                                       */
+  /* add(std::vector<T>, std::vector<T>)                                   */
+  /* add(scaled(std::vector<T>, a), std::vector<T>)                        */ 
+  /*                                                                       */
+  /* mult(dense_matrix<T>, dense_matrix<T>, dense_matrix<T>)               */
+  /* mult(transposed(dense_matrix<T>), dense_matrix<T>, dense_matrix<T>)   */
+  /* mult(dense_matrix<T>, transposed(dense_matrix<T>), dense_matrix<T>)   */
+  /* mult(transposed(dense_matrix<T>), transposed(dense_matrix<T>),        */
+  /*      dense_matrix<T>)                                                 */
+  /* mult(conjugated(dense_matrix<T>), dense_matrix<T>, dense_matrix<T>)   */
+  /* mult(dense_matrix<T>, conjugated(dense_matrix<T>), dense_matrix<T>)   */
+  /* mult(conjugated(dense_matrix<T>), conjugated(dense_matrix<T>),        */
+  /*      dense_matrix<T>)                                                 */
+  /*                                                                       */
+  /* mult(dense_matrix<T>, std::vector<T>, std::vector<T>)                 */
+  /* mult(transposed(dense_matrix<T>), std::vector<T>, std::vector<T>)     */
+  /* mult(conjugated(dense_matrix<T>), std::vector<T>, std::vector<T>)     */
+  /* mult(dense_matrix<T>, scaled(std::vector<T>), std::vector<T>)         */
+  /* mult(transposed(dense_matrix<T>), scaled(std::vector<T>),             */
+  /*      std::vector<T>)                                                  */
+  /* mult(conjugated(dense_matrix<T>), scaled(std::vector<T>),             */
+  /*      std::vector<T>)                                                  */
+  /*                                                                       */
+  /* mult_add(dense_matrix<T>, std::vector<T>, std::vector<T>)             */
+  /* mult_add(transposed(dense_matrix<T>), std::vector<T>, std::vector<T>) */
+  /* mult_add(conjugated(dense_matrix<T>), std::vector<T>, std::vector<T>) */
+  /* mult_add(dense_matrix<T>, scaled(std::vector<T>), std::vector<T>)     */
+  /* mult_add(transposed(dense_matrix<T>), scaled(std::vector<T>),         */
+  /*          std::vector<T>)                                              */
+  /* mult_add(conjugated(dense_matrix<T>), scaled(std::vector<T>),         */
+  /*          std::vector<T>)                                              */
+  /*                                                                       */
+  /* mult(dense_matrix<T>, std::vector<T>, std::vector<T>, std::vector<T>) */
+  /* mult(transposed(dense_matrix<T>), std::vector<T>, std::vector<T>,     */
+  /*      std::vector<T>)                                                  */
+  /* mult(conjugated(dense_matrix<T>), std::vector<T>, std::vector<T>,     */
+  /*      std::vector<T>)                                                  */
+  /* mult(dense_matrix<T>, scaled(std::vector<T>), std::vector<T>,         */
+  /*      std::vector<T>)                                                  */
+  /* mult(transposed(dense_matrix<T>), scaled(std::vector<T>),             */
+  /*      std::vector<T>, std::vector<T>)                                  */
+  /* mult(conjugated(dense_matrix<T>), scaled(std::vector<T>),             */
+  /*      std::vector<T>, std::vector<T>)                                  */
+  /* mult(dense_matrix<T>, std::vector<T>, scaled(std::vector<T>),         */
+  /*      std::vector<T>)                                                  */
+  /* mult(transposed(dense_matrix<T>), std::vector<T>,                     */
+  /*      scaled(std::vector<T>), std::vector<T>)                          */
+  /* mult(conjugated(dense_matrix<T>), std::vector<T>,                     */
+  /*      scaled(std::vector<T>), std::vector<T>)                          */
+  /* mult(dense_matrix<T>, scaled(std::vector<T>), scaled(std::vector<T>), */
+  /*   std::vector<T>)                                                     */
+  /* mult(transposed(dense_matrix<T>), scaled(std::vector<T>),             */
+  /*      scaled(std::vector<T>), std::vector<T>)                          */
+  /* mult(conjugated(dense_matrix<T>), scaled(std::vector<T>),             */
+  /*      scaled(std::vector<T>), std::vector<T>)                          */
+  /*                                                                       */
+  /* lower_tri_solve(dense_matrix<T>, std::vector<T>, k, b)                */
+  /* upper_tri_solve(dense_matrix<T>, std::vector<T>, k, b)                */
+  /* lower_tri_solve(transposed(dense_matrix<T>), std::vector<T>, k, b)    */
+  /* upper_tri_solve(transposed(dense_matrix<T>), std::vector<T>, k, b)    */
+  /* lower_tri_solve(conjugated(dense_matrix<T>), std::vector<T>, k, b)    */
+  /* upper_tri_solve(conjugated(dense_matrix<T>), std::vector<T>, k, b)    */
+  /*                                                                       */
+  /* ********************************************************************* */
+
+  /* ********************************************************************* */
+  /* Basic defines.                                                        */
+  /* ********************************************************************* */
+
+# define BLAS_S float
+# define BLAS_D double
+# define BLAS_C std::complex<float>
+# define BLAS_Z std::complex<double>
+
+  /* ********************************************************************* */
+  /* BLAS functions used.                                                  */
+  /* ********************************************************************* */
+  extern "C" void daxpy_(const int *n, const double *alpha, const double *x, const int *incx, double *y, const int *incy);
+  extern "C" {
+    void sgemm_(...); void dgemm_(...); void cgemm_(...); void zgemm_(...);
+    void sgemv_(...); void dgemv_(...); void cgemv_(...); void zgemv_(...);
+    void strsv_(...); void dtrsv_(...); void ctrsv_(...); void ztrsv_(...);
+    void saxpy_(...); /*void daxpy_(...); */void caxpy_(...); void zaxpy_(...);
+    BLAS_S sdot_ (...); BLAS_D ddot_ (...);
+    BLAS_C cdotu_(...); BLAS_Z zdotu_(...);
+    BLAS_C cdotc_(...); BLAS_Z zdotc_(...);
+    BLAS_S snrm2_(...); BLAS_D dnrm2_(...);
+    BLAS_S scnrm2_(...); BLAS_D dznrm2_(...);
+  }
+
+  /* ********************************************************************* */
+  /* vect_norm2(x).                                                        */
+  /* ********************************************************************* */
+
+  # define nrm2_interface(param1, trans1, blas_name, base_type)            \
+  inline number_traits<base_type >::magnitude_type                         \
+    vect_norm2(param1(base_type)) {                                        \
+    GMMLAPACK_TRACE("nrm2_interface");                                     \
+    int inc(1), n(vect_size(x)); trans1(base_type);                        \
+    return blas_name(&n, &x[0], &inc);                                     \
+  }
+
+# define nrm2_p1(base_type) const std::vector<base_type > &x
+# define nrm2_trans1(base_type)
+
+  nrm2_interface(nrm2_p1, nrm2_trans1, snrm2_ , BLAS_S)
+  nrm2_interface(nrm2_p1, nrm2_trans1, dnrm2_ , BLAS_D)
+  nrm2_interface(nrm2_p1, nrm2_trans1, scnrm2_, BLAS_C)
+  nrm2_interface(nrm2_p1, nrm2_trans1, dznrm2_, BLAS_Z)
+
+  /* ********************************************************************* */
+  /* vect_sp(x, y).                                                        */
+  /* ********************************************************************* */
+
+  # define dot_interface(param1, trans1, mult1, param2, trans2, mult2,     \
+                         blas_name, base_type)                             \
+  inline base_type vect_sp(param1(base_type), param2(base_type)) {         \
+    GMMLAPACK_TRACE("dot_interface");                                      \
+    trans1(base_type); trans2(base_type); int inc(1), n(vect_size(y));     \
+    return mult1 mult2 blas_name(&n, &x[0], &inc, &y[0], &inc);            \
+  }
+
+# define dot_p1(base_type) const std::vector<base_type > &x
+# define dot_trans1(base_type)
+# define dot_p1_s(base_type)                                               \
+    const scaled_vector_const_ref<std::vector<base_type >, base_type > &x_
+# define dot_trans1_s(base_type)                                           \
+         std::vector<base_type > &x =                                      \
+         const_cast<std::vector<base_type > &>(*(linalg_origin(x_)));      \
+         base_type a(x_.r)
+
+# define dot_p2(base_type) const std::vector<base_type > &y
+# define dot_trans2(base_type)
+# define dot_p2_s(base_type)                                               \
+    const scaled_vector_const_ref<std::vector<base_type >, base_type > &y_
+# define dot_trans2_s(base_type)                                           \
+         std::vector<base_type > &y =                                      \
+         const_cast<std::vector<base_type > &>(*(linalg_origin(y_)));      \
+         base_type b(y_.r)
+
+  dot_interface(dot_p1, dot_trans1, , dot_p2, dot_trans2, , sdot_ , BLAS_S)
+  dot_interface(dot_p1, dot_trans1, , dot_p2, dot_trans2, , ddot_ , BLAS_D)
+  dot_interface(dot_p1, dot_trans1, , dot_p2, dot_trans2, , cdotu_, BLAS_C)
+  dot_interface(dot_p1, dot_trans1, , dot_p2, dot_trans2, , zdotu_, BLAS_Z)
+  
+  dot_interface(dot_p1_s, dot_trans1_s, a*, dot_p2, dot_trans2, ,sdot_ ,BLAS_S)
+  dot_interface(dot_p1_s, dot_trans1_s, a*, dot_p2, dot_trans2, ,ddot_ ,BLAS_D)
+  dot_interface(dot_p1_s, dot_trans1_s, a*, dot_p2, dot_trans2, ,cdotu_,BLAS_C)
+  dot_interface(dot_p1_s, dot_trans1_s, a*, dot_p2, dot_trans2, ,zdotu_,BLAS_Z)
+  
+  dot_interface(dot_p1, dot_trans1, , dot_p2_s, dot_trans2_s, b*,sdot_ ,BLAS_S)
+  dot_interface(dot_p1, dot_trans1, , dot_p2_s, dot_trans2_s, b*,ddot_ ,BLAS_D)
+  dot_interface(dot_p1, dot_trans1, , dot_p2_s, dot_trans2_s, b*,cdotu_,BLAS_C)
+  dot_interface(dot_p1, dot_trans1, , dot_p2_s, dot_trans2_s, b*,zdotu_,BLAS_Z)
+
+  dot_interface(dot_p1_s,dot_trans1_s,a*,dot_p2_s,dot_trans2_s,b*,sdot_ ,
+		BLAS_S)
+  dot_interface(dot_p1_s,dot_trans1_s,a*,dot_p2_s,dot_trans2_s,b*,ddot_ ,
+		BLAS_D)
+  dot_interface(dot_p1_s,dot_trans1_s,a*,dot_p2_s,dot_trans2_s,b*,cdotu_,
+		BLAS_C)
+  dot_interface(dot_p1_s,dot_trans1_s,a*,dot_p2_s,dot_trans2_s,b*,zdotu_,
+		BLAS_Z)
+
+
+  /* ********************************************************************* */
+  /* vect_hp(x, y).                                                        */
+  /* ********************************************************************* */
+
+  # define dotc_interface(param1, trans1, mult1, param2, trans2, mult2,    \
+                         blas_name, base_type)                             \
+  inline base_type vect_hp(param1(base_type), param2(base_type)) {         \
+    GMMLAPACK_TRACE("dotc_interface");                                     \
+    trans1(base_type); trans2(base_type); int inc(1), n(vect_size(y));     \
+    return mult1 mult2 blas_name(&n, &x[0], &inc, &y[0], &inc);            \
+  }
+
+# define dotc_p1(base_type) const std::vector<base_type > &x
+# define dotc_trans1(base_type)
+# define dotc_p1_s(base_type)                                              \
+    const scaled_vector_const_ref<std::vector<base_type >, base_type > &x_
+# define dotc_trans1_s(base_type)                                          \
+         std::vector<base_type > &x =                                      \
+         const_cast<std::vector<base_type > &>(*(linalg_origin(x_)));      \
+         base_type a(x_.r)
+
+# define dotc_p2(base_type) const std::vector<base_type > &y
+# define dotc_trans2(base_type)
+# define dotc_p2_s(base_type)                                              \
+    const scaled_vector_const_ref<std::vector<base_type >, base_type > &y_
+# define dotc_trans2_s(base_type)                                          \
+         std::vector<base_type > &y =                                      \
+         const_cast<std::vector<base_type > &>(*(linalg_origin(y_)));      \
+         base_type b(gmm::conj(y_.r))
+
+  dotc_interface(dotc_p1, dotc_trans1, , dotc_p2, dotc_trans2, ,sdot_ ,BLAS_S)
+  dotc_interface(dotc_p1, dotc_trans1, , dotc_p2, dotc_trans2, ,ddot_ ,BLAS_D)
+  dotc_interface(dotc_p1, dotc_trans1, , dotc_p2, dotc_trans2, ,cdotc_,BLAS_C)
+  dotc_interface(dotc_p1, dotc_trans1, , dotc_p2, dotc_trans2, ,zdotc_,BLAS_Z)
+  
+  dotc_interface(dotc_p1_s, dotc_trans1_s, a*, dotc_p2, dotc_trans2, ,sdot_,
+		 BLAS_S)
+  dotc_interface(dotc_p1_s, dotc_trans1_s, a*, dotc_p2, dotc_trans2, ,ddot_ ,
+		 BLAS_D)
+  dotc_interface(dotc_p1_s, dotc_trans1_s, a*, dotc_p2, dotc_trans2, ,cdotc_,
+		 BLAS_C)
+  dotc_interface(dotc_p1_s, dotc_trans1_s, a*, dotc_p2, dotc_trans2, ,zdotc_,
+		 BLAS_Z)
+  
+  dotc_interface(dotc_p1, dotc_trans1, , dotc_p2_s, dotc_trans2_s, b*,sdot_ ,
+		 BLAS_S)
+  dotc_interface(dotc_p1, dotc_trans1, , dotc_p2_s, dotc_trans2_s, b*,ddot_ ,
+		 BLAS_D)
+  dotc_interface(dotc_p1, dotc_trans1, , dotc_p2_s, dotc_trans2_s, b*,cdotc_,
+		 BLAS_C)
+  dotc_interface(dotc_p1, dotc_trans1, , dotc_p2_s, dotc_trans2_s, b*,zdotc_,
+		 BLAS_Z)
+
+  dotc_interface(dotc_p1_s,dotc_trans1_s,a*,dotc_p2_s,dotc_trans2_s,b*,sdot_ ,
+		 BLAS_S)
+  dotc_interface(dotc_p1_s,dotc_trans1_s,a*,dotc_p2_s,dotc_trans2_s,b*,ddot_ ,
+		 BLAS_D)
+  dotc_interface(dotc_p1_s,dotc_trans1_s,a*,dotc_p2_s,dotc_trans2_s,b*,cdotc_,
+		 BLAS_C)
+  dotc_interface(dotc_p1_s,dotc_trans1_s,a*,dotc_p2_s,dotc_trans2_s,b*,zdotc_,
+		 BLAS_Z)
+
+  /* ********************************************************************* */
+  /* add(x, y).                                                            */
+  /* ********************************************************************* */
+
+# define axpy_interface(param1, trans1, blas_name, base_type)              \
+  inline void add(param1(base_type), std::vector<base_type > &y) {         \
+    GMMLAPACK_TRACE("axpy_interface");                                     \
+    int inc(1), n(vect_size(y)); trans1(base_type);                        \
+    blas_name(&n, &a, &x[0], &inc, &y[0], &inc);                           \
+  }
+
+# define axpy_p1(base_type) const std::vector<base_type > &x
+# define axpy_trans1(base_type) base_type a(1)
+# define axpy_p1_s(base_type)                                              \
+    const scaled_vector_const_ref<std::vector<base_type >, base_type > &x_
+# define axpy_trans1_s(base_type)                                          \
+         std::vector<base_type > &x =                                      \
+         const_cast<std::vector<base_type > &>(*(linalg_origin(x_)));      \
+         base_type a(x_.r)
+
+  axpy_interface(axpy_p1, axpy_trans1, saxpy_, BLAS_S)
+  axpy_interface(axpy_p1, axpy_trans1, daxpy_, BLAS_D)
+  axpy_interface(axpy_p1, axpy_trans1, caxpy_, BLAS_C)
+  axpy_interface(axpy_p1, axpy_trans1, zaxpy_, BLAS_Z)
+  
+  axpy_interface(axpy_p1_s, axpy_trans1_s, saxpy_, BLAS_S)
+  axpy_interface(axpy_p1_s, axpy_trans1_s, daxpy_, BLAS_D)
+  axpy_interface(axpy_p1_s, axpy_trans1_s, caxpy_, BLAS_C)
+  axpy_interface(axpy_p1_s, axpy_trans1_s, zaxpy_, BLAS_Z)
+  
+
+  /* ********************************************************************* */
+  /* mult_add(A, x, z).                                                    */
+  /* ********************************************************************* */
+  
+# define gemv_interface(param1, trans1, param2, trans2, blas_name,         \
+			base_type, orien)                                  \
+  inline void mult_add_spec(param1(base_type), param2(base_type),          \
+              std::vector<base_type > &z, orien) {                         \
+    GMMLAPACK_TRACE("gemv_interface");                                     \
+    trans1(base_type); trans2(base_type); base_type beta(1);               \
+    int m(mat_nrows(A)), lda(m), n(mat_ncols(A)), inc(1);                  \
+    if (m && n) blas_name(&t, &m, &n, &alpha, &A(0,0), &lda, &x[0], &inc,  \
+                          &beta, &z[0], &inc);                             \
+    else gmm::clear(z);                                                    \
+  }
+
+  // First parameter
+# define gem_p1_n(base_type)  const dense_matrix<base_type > &A
+# define gem_trans1_n(base_type) const char t = 'N'
+# define gem_p1_t(base_type)                                               \
+         const transposed_col_ref<dense_matrix<base_type > *> &A_
+# define gem_trans1_t(base_type) dense_matrix<base_type > &A =             \
+         const_cast<dense_matrix<base_type > &>(*(linalg_origin(A_)));     \
+         const char t = 'T'
+# define gem_p1_tc(base_type)                                              \
+         const transposed_col_ref<const dense_matrix<base_type > *> &A_
+# define gem_p1_c(base_type)                                               \
+         const conjugated_col_matrix_const_ref<dense_matrix<base_type > > &A_
+# define gem_trans1_c(base_type) dense_matrix<base_type > &A =             \
+         const_cast<dense_matrix<base_type > &>(*(linalg_origin(A_)));     \
+         const char t = 'C'
+
+  // second parameter 
+# define gemv_p2_n(base_type)  const std::vector<base_type > &x
+# define gemv_trans2_n(base_type) base_type alpha(1)
+# define gemv_p2_s(base_type)                                              \
+    const scaled_vector_const_ref<std::vector<base_type >, base_type > &x_
+# define gemv_trans2_s(base_type) std::vector<base_type > &x =             \
+         const_cast<std::vector<base_type > &>(*(linalg_origin(x_)));      \
+         base_type alpha(x_.r)
+
+  // Z <- AX + Z.
+  gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, sgemv_,
+		 BLAS_S, col_major)
+  gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, dgemv_,
+		 BLAS_D, col_major)
+  gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, cgemv_,
+		 BLAS_C, col_major)
+  gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, zgemv_,
+		 BLAS_Z, col_major)
+
+  // Z <- transposed(A)X + Z.
+  gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, sgemv_,
+		 BLAS_S, row_major)
+  gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, dgemv_,
+		 BLAS_D, row_major)
+  gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, cgemv_,
+		 BLAS_C, row_major)
+  gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, zgemv_,
+		 BLAS_Z, row_major)
+  
+  // Z <- transposed(const A)X + Z.
+  gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, sgemv_,
+		 BLAS_S, row_major)
+  gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, dgemv_,
+		 BLAS_D, row_major)
+  gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, cgemv_,
+		 BLAS_C, row_major)
+  gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, zgemv_,
+		 BLAS_Z, row_major)
+  
+  // Z <- conjugated(A)X + Z.
+  gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, sgemv_,
+		 BLAS_S, row_major)
+  gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, dgemv_,
+		 BLAS_D, row_major)
+  gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, cgemv_,
+		 BLAS_C, row_major)
+  gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, zgemv_,
+		 BLAS_Z, row_major)
+
+  // Z <- A scaled(X) + Z.
+  gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, sgemv_,
+		 BLAS_S, col_major)
+  gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, dgemv_,
+		 BLAS_D, col_major)
+  gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, cgemv_,
+		 BLAS_C, col_major)
+  gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, zgemv_,
+		 BLAS_Z, col_major)
+
+  // Z <- transposed(A) scaled(X) + Z.
+  gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, sgemv_,
+		 BLAS_S, row_major)
+  gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, dgemv_,
+		 BLAS_D, row_major)
+  gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, cgemv_,
+		 BLAS_C, row_major)
+  gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, zgemv_,
+		 BLAS_Z, row_major)
+  
+  // Z <- transposed(const A) scaled(X) + Z.
+  gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, sgemv_,
+		 BLAS_S, row_major)
+  gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, dgemv_,
+		 BLAS_D, row_major)
+  gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, cgemv_,
+		 BLAS_C, row_major)
+  gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, zgemv_,
+		 BLAS_Z, row_major)
+  
+  // Z <- conjugated(A) scaled(X) + Z.
+  gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, sgemv_,
+		 BLAS_S, row_major)
+  gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, dgemv_,
+		 BLAS_D, row_major)
+  gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, cgemv_,
+		 BLAS_C, row_major)
+  gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, zgemv_,
+		 BLAS_Z, row_major)
+
+
+  /* ********************************************************************* */
+  /* mult(A, x, y).                                                        */
+  /* ********************************************************************* */
+  
+# define gemv_interface2(param1, trans1, param2, trans2, blas_name,        \
+                         base_type, orien)                                 \
+  inline void mult_spec(param1(base_type), param2(base_type),              \
+              std::vector<base_type > &z, orien) {                         \
+    GMMLAPACK_TRACE("gemv_interface2");                                    \
+    trans1(base_type); trans2(base_type); base_type beta(0);               \
+    int m(mat_nrows(A)), lda(m), n(mat_ncols(A)), inc(1);                  \
+    if (m && n)                                                            \
+      blas_name(&t, &m, &n, &alpha, &A(0,0), &lda, &x[0], &inc, &beta,     \
+                &z[0], &inc);                                              \
+    else gmm::clear(z);                                                    \
+  }
+
+  // Y <- AX.
+  gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, sgemv_,
+		  BLAS_S, col_major)
+  gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, dgemv_,
+		  BLAS_D, col_major)
+  gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, cgemv_,
+		  BLAS_C, col_major)
+  gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, zgemv_,
+		  BLAS_Z, col_major)
+
+  // Y <- transposed(A)X.
+  gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, sgemv_,
+		  BLAS_S, row_major)
+  gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, dgemv_,
+		  BLAS_D, row_major)
+  gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, cgemv_,
+		  BLAS_C, row_major)
+  gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, zgemv_,
+		  BLAS_Z, row_major)
+  
+  // Y <- transposed(const A)X.
+  gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, sgemv_,
+		  BLAS_S, row_major)
+  gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, dgemv_,
+		  BLAS_D, row_major)
+  gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, cgemv_,
+		  BLAS_C, row_major)
+  gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, zgemv_,
+		  BLAS_Z, row_major)
+  
+  // Y <- conjugated(A)X.
+  gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, sgemv_,
+		  BLAS_S, row_major)
+  gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, dgemv_,
+		  BLAS_D, row_major)
+  gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, cgemv_,
+		  BLAS_C, row_major)
+  gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, zgemv_,
+		  BLAS_Z, row_major)
+
+  // Y <- A scaled(X).
+  gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, sgemv_,
+		  BLAS_S, col_major)
+  gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, dgemv_,
+		  BLAS_D, col_major)
+  gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, cgemv_,
+		  BLAS_C, col_major)
+  gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, zgemv_,
+		  BLAS_Z, col_major)
+
+  // Y <- transposed(A) scaled(X).
+  gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, sgemv_,
+		  BLAS_S, row_major)
+  gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, dgemv_,
+		  BLAS_D, row_major)
+  gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, cgemv_,
+		  BLAS_C, row_major)
+  gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, zgemv_,
+		  BLAS_Z, row_major)
+  
+  // Y <- transposed(const A) scaled(X).
+  gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, sgemv_,
+		  BLAS_S, row_major)
+  gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, dgemv_,
+		  BLAS_D, row_major)
+  gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, cgemv_,
+		  BLAS_C, row_major)
+  gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, zgemv_,
+		  BLAS_Z, row_major)
+  
+  // Y <- conjugated(A) scaled(X).
+  gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, sgemv_,
+		  BLAS_S, row_major)
+  gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, dgemv_,
+		  BLAS_D, row_major)
+  gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, cgemv_,
+		  BLAS_C, row_major)
+  gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, zgemv_,
+		  BLAS_Z, row_major)
+
+  /* ********************************************************************* */
+  /* dense matrix x dense matrix multiplication.                           */
+  /* ********************************************************************* */
+
+# define gemm_interface_nn(blas_name, base_type)                           \
+  inline void mult_spec(const dense_matrix<base_type > &A,                 \
+            const dense_matrix<base_type > &B,                             \
+            dense_matrix<base_type > &C, c_mult) {                         \
+    GMMLAPACK_TRACE("gemm_interface_nn");                                  \
+    const char t = 'N';                                                    \
+    int m = mat_nrows(A), lda = m, k = mat_ncols(A), n = mat_ncols(B);     \
+    int ldb = k, ldc = m;                                                  \
+    base_type alpha(1), beta(0);                                           \
+    if (m && k && n)                                                       \
+      blas_name(&t, &t, &m, &n, &k, &alpha,                                \
+	          &A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc);     \
+    else gmm::clear(C);                                                    \
+  }
+
+  gemm_interface_nn(sgemm_, BLAS_S)
+  gemm_interface_nn(dgemm_, BLAS_D)
+  gemm_interface_nn(cgemm_, BLAS_C)
+  gemm_interface_nn(zgemm_, BLAS_Z)
+  
+  /* ********************************************************************* */
+  /* transposed(dense matrix) x dense matrix multiplication.               */
+  /* ********************************************************************* */
+
+# define gemm_interface_tn(blas_name, base_type, is_const)                 \
+  inline void mult_spec(                                                   \
+         const transposed_col_ref<is_const dense_matrix<base_type > *> &A_,\
+         const dense_matrix<base_type > &B,                                \
+         dense_matrix<base_type > &C, rcmult) {                            \
+    GMMLAPACK_TRACE("gemm_interface_tn");                                  \
+    dense_matrix<base_type > &A                                            \
+         = const_cast<dense_matrix<base_type > &>(*(linalg_origin(A_)));   \
+    const char t = 'T', u = 'N';                                           \
+    int m = mat_ncols(A), k = mat_nrows(A), n = mat_ncols(B), lda = k;     \
+    int ldb = k, ldc = m;                                                  \
+    base_type alpha(1), beta(0);                                           \
+    if (m && k && n)                                                       \
+      blas_name(&t, &u, &m, &n, &k, &alpha,                                \
+	          &A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc);     \
+    else gmm::clear(C);                                                    \
+  }
+
+  gemm_interface_tn(sgemm_, BLAS_S,)
+  gemm_interface_tn(dgemm_, BLAS_D,)
+  gemm_interface_tn(cgemm_, BLAS_C,)
+  gemm_interface_tn(zgemm_, BLAS_Z,)
+  gemm_interface_tn(sgemm_, BLAS_S, const)
+  gemm_interface_tn(dgemm_, BLAS_D, const)
+  gemm_interface_tn(cgemm_, BLAS_C, const)
+  gemm_interface_tn(zgemm_, BLAS_Z, const)
+
+  /* ********************************************************************* */
+  /* dense matrix x transposed(dense matrix) multiplication.               */
+  /* ********************************************************************* */
+
+# define gemm_interface_nt(blas_name, base_type, is_const)                 \
+  inline void mult_spec(const dense_matrix<base_type > &A,                 \
+         const transposed_col_ref<is_const dense_matrix<base_type > *> &B_,\
+         dense_matrix<base_type > &C, r_mult) {                            \
+    GMMLAPACK_TRACE("gemm_interface_nt");                                  \
+    dense_matrix<base_type > &B                                            \
+        = const_cast<dense_matrix<base_type > &>(*(linalg_origin(B_)));    \
+    const char t = 'N', u = 'T';                                           \
+    int m = mat_nrows(A), lda = m, k = mat_ncols(A), n = mat_nrows(B);     \
+    int ldb = n, ldc = m;                                                  \
+    base_type alpha(1), beta(0);                                           \
+    if (m && k && n)                                                       \
+      blas_name(&t, &u, &m, &n, &k, &alpha,                                \
+	        &A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc);       \
+    else gmm::clear(C);                                                    \
+  }
+
+  gemm_interface_nt(sgemm_, BLAS_S,)
+  gemm_interface_nt(dgemm_, BLAS_D,)
+  gemm_interface_nt(cgemm_, BLAS_C,)
+  gemm_interface_nt(zgemm_, BLAS_Z,)
+  gemm_interface_nt(sgemm_, BLAS_S, const)
+  gemm_interface_nt(dgemm_, BLAS_D, const)
+  gemm_interface_nt(cgemm_, BLAS_C, const)
+  gemm_interface_nt(zgemm_, BLAS_Z, const)
+
+  /* ********************************************************************* */
+  /* transposed(dense matrix) x transposed(dense matrix) multiplication.   */
+  /* ********************************************************************* */
+
+# define gemm_interface_tt(blas_name, base_type, isA_const, isB_const)     \
+  inline void mult_spec(                                                   \
+        const transposed_col_ref<isA_const dense_matrix<base_type > *> &A_,\
+        const transposed_col_ref<isB_const dense_matrix<base_type > *> &B_,\
+        dense_matrix<base_type > &C, r_mult) {                             \
+    GMMLAPACK_TRACE("gemm_interface_tt");                                  \
+    dense_matrix<base_type > &A                                            \
+        = const_cast<dense_matrix<base_type > &>(*(linalg_origin(A_)));    \
+    dense_matrix<base_type > &B                                            \
+        = const_cast<dense_matrix<base_type > &>(*(linalg_origin(B_)));    \
+    const char t = 'T', u = 'T';                                           \
+    int m = mat_ncols(A), k = mat_nrows(A), n = mat_nrows(B), lda = k;     \
+    int ldb = n, ldc = m;                                                  \
+    base_type alpha(1), beta(0);                                           \
+    if (m && k && n)                                                       \
+      blas_name(&t, &u, &m, &n, &k, &alpha,                                \
+	        &A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc);       \
+    else gmm::clear(C);                                                    \
+  }
+
+  gemm_interface_tt(sgemm_, BLAS_S,,)
+  gemm_interface_tt(dgemm_, BLAS_D,,)
+  gemm_interface_tt(cgemm_, BLAS_C,,)
+  gemm_interface_tt(zgemm_, BLAS_Z,,)
+  gemm_interface_tt(sgemm_, BLAS_S, const,)
+  gemm_interface_tt(dgemm_, BLAS_D, const,)
+  gemm_interface_tt(cgemm_, BLAS_C, const,)
+  gemm_interface_tt(zgemm_, BLAS_Z, const,)
+  gemm_interface_tt(sgemm_, BLAS_S,, const)
+  gemm_interface_tt(dgemm_, BLAS_D,, const)
+  gemm_interface_tt(cgemm_, BLAS_C,, const)
+  gemm_interface_tt(zgemm_, BLAS_Z,, const)
+  gemm_interface_tt(sgemm_, BLAS_S, const, const)
+  gemm_interface_tt(dgemm_, BLAS_D, const, const)
+  gemm_interface_tt(cgemm_, BLAS_C, const, const)
+  gemm_interface_tt(zgemm_, BLAS_Z, const, const)
+
+
+  /* ********************************************************************* */
+  /* conjugated(dense matrix) x dense matrix multiplication.               */
+  /* ********************************************************************* */
+
+# define gemm_interface_cn(blas_name, base_type)                           \
+  inline void mult_spec(                                                   \
+      const conjugated_col_matrix_const_ref<dense_matrix<base_type > > &A_,\
+      const dense_matrix<base_type > &B,                                   \
+      dense_matrix<base_type > &C, rcmult) {                               \
+    GMMLAPACK_TRACE("gemm_interface_cn");                                  \
+    dense_matrix<base_type > &A                                            \
+          = const_cast<dense_matrix<base_type > &>(*(linalg_origin(A_)));  \
+    const char t = 'C', u = 'N';                                           \
+    int m = mat_ncols(A), k = mat_nrows(A), n = mat_ncols(B), lda = k;     \
+    int ldb = k, ldc = m;                                                  \
+    base_type alpha(1), beta(0);                                           \
+    if (m && k && n)                                                       \
+      blas_name(&t, &u, &m, &n, &k, &alpha,                                \
+	        &A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc);       \
+    else gmm::clear(C);                                                    \
+  }
+
+  gemm_interface_cn(sgemm_, BLAS_S)
+  gemm_interface_cn(dgemm_, BLAS_D)
+  gemm_interface_cn(cgemm_, BLAS_C)
+  gemm_interface_cn(zgemm_, BLAS_Z)
+
+  /* ********************************************************************* */
+  /* dense matrix x conjugated(dense matrix) multiplication.               */
+  /* ********************************************************************* */
+
+# define gemm_interface_nc(blas_name, base_type)                           \
+  inline void mult_spec(const dense_matrix<base_type > &A,                 \
+      const conjugated_col_matrix_const_ref<dense_matrix<base_type > > &B_,\
+      dense_matrix<base_type > &C, c_mult, row_major) {                    \
+    GMMLAPACK_TRACE("gemm_interface_nc");                                  \
+    dense_matrix<base_type > &B                                            \
+         = const_cast<dense_matrix<base_type > &>(*(linalg_origin(B_)));   \
+    const char t = 'N', u = 'C';                                           \
+    int m = mat_nrows(A), lda = m, k = mat_ncols(A), n = mat_nrows(B);     \
+    int ldb = n, ldc = m;                                                  \
+    base_type alpha(1), beta(0);                                           \
+    if (m && k && n)                                                       \
+      blas_name(&t, &u, &m, &n, &k, &alpha,                                \
+	        &A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc);       \
+    else gmm::clear(C);                                                    \
+  }
+
+  gemm_interface_nc(sgemm_, BLAS_S)
+  gemm_interface_nc(dgemm_, BLAS_D)
+  gemm_interface_nc(cgemm_, BLAS_C)
+  gemm_interface_nc(zgemm_, BLAS_Z)
+
+  /* ********************************************************************* */
+  /* conjugated(dense matrix) x conjugated(dense matrix) multiplication.   */
+  /* ********************************************************************* */
+
+# define gemm_interface_cc(blas_name, base_type)                           \
+  inline void mult_spec(                                                   \
+      const conjugated_col_matrix_const_ref<dense_matrix<base_type > > &A_,\
+      const conjugated_col_matrix_const_ref<dense_matrix<base_type > > &B_,\
+      dense_matrix<base_type > &C, r_mult) {                               \
+    GMMLAPACK_TRACE("gemm_interface_cc");                                  \
+    dense_matrix<base_type > &A                                            \
+        = const_cast<dense_matrix<base_type > &>(*(linalg_origin(A_)));    \
+    dense_matrix<base_type > &B                                            \
+        = const_cast<dense_matrix<base_type > &>(*(linalg_origin(B_)));    \
+    const char t = 'C', u = 'C';                                           \
+    int m = mat_ncols(A), k = mat_nrows(A), lda = k, n = mat_nrows(B);     \
+    int ldb = n, ldc = m;                                                  \
+    base_type alpha(1), beta(0);                                           \
+    if (m && k && n)                                                       \
+      blas_name(&t, &u, &m, &n, &k, &alpha,                                \
+	        &A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc);       \
+    else gmm::clear(C);                                                    \
+  }
+
+  gemm_interface_cc(sgemm_, BLAS_S)
+  gemm_interface_cc(dgemm_, BLAS_D)
+  gemm_interface_cc(cgemm_, BLAS_C)
+  gemm_interface_cc(zgemm_, BLAS_Z)
+   
+  /* ********************************************************************* */
+  /* Tri solve.                                                            */
+  /* ********************************************************************* */
+
+# define trsv_interface(f_name, loru, param1, trans1, blas_name, base_type)\
+  inline void f_name(param1(base_type), std::vector<base_type > &x,        \
+                              size_type k, bool is_unit) {                 \
+    GMMLAPACK_TRACE("trsv_interface");                                     \
+    loru; trans1(base_type); char d = is_unit ? 'U' : 'N';                 \
+    int lda(mat_nrows(A)), inc(1), n(k);                                   \
+    if (lda) blas_name(&l, &t, &d, &n, &A(0,0), &lda, &x[0], &inc);        \
+  }
+
+# define trsv_upper const char l = 'U'
+# define trsv_lower const char l = 'L'
+
+  // X <- LOWER(A)^{-1}X.
+  trsv_interface(lower_tri_solve, trsv_lower, gem_p1_n, gem_trans1_n,
+		 strsv_, BLAS_S)
+  trsv_interface(lower_tri_solve, trsv_lower, gem_p1_n, gem_trans1_n,
+		 dtrsv_, BLAS_D) 
+  trsv_interface(lower_tri_solve, trsv_lower, gem_p1_n, gem_trans1_n,
+		 ctrsv_, BLAS_C) 
+  trsv_interface(lower_tri_solve, trsv_lower, gem_p1_n, gem_trans1_n,
+		 ztrsv_, BLAS_Z)
+  
+  // X <- UPPER(A)^{-1}X.
+  trsv_interface(upper_tri_solve, trsv_upper, gem_p1_n, gem_trans1_n,
+		 strsv_, BLAS_S)
+  trsv_interface(upper_tri_solve, trsv_upper, gem_p1_n, gem_trans1_n,
+		 dtrsv_, BLAS_D) 
+  trsv_interface(upper_tri_solve, trsv_upper, gem_p1_n, gem_trans1_n,
+		 ctrsv_, BLAS_C) 
+  trsv_interface(upper_tri_solve, trsv_upper, gem_p1_n, gem_trans1_n,
+		 ztrsv_, BLAS_Z)
+  
+  // X <- LOWER(transposed(A))^{-1}X.
+  trsv_interface(lower_tri_solve, trsv_upper, gem_p1_t, gem_trans1_t,
+		 strsv_, BLAS_S)
+  trsv_interface(lower_tri_solve, trsv_upper, gem_p1_t, gem_trans1_t,
+		 dtrsv_, BLAS_D) 
+  trsv_interface(lower_tri_solve, trsv_upper, gem_p1_t, gem_trans1_t,
+		 ctrsv_, BLAS_C) 
+  trsv_interface(lower_tri_solve, trsv_upper, gem_p1_t, gem_trans1_t,
+		 ztrsv_, BLAS_Z)
+  
+  // X <- UPPER(transposed(A))^{-1}X.
+  trsv_interface(upper_tri_solve, trsv_lower, gem_p1_t, gem_trans1_t,
+		 strsv_, BLAS_S)
+  trsv_interface(upper_tri_solve, trsv_lower, gem_p1_t, gem_trans1_t,
+		 dtrsv_, BLAS_D) 
+  trsv_interface(upper_tri_solve, trsv_lower, gem_p1_t, gem_trans1_t,
+		 ctrsv_, BLAS_C) 
+  trsv_interface(upper_tri_solve, trsv_lower, gem_p1_t, gem_trans1_t,
+		 ztrsv_, BLAS_Z)
+
+  // X <- LOWER(transposed(const A))^{-1}X.
+  trsv_interface(lower_tri_solve, trsv_upper, gem_p1_tc, gem_trans1_t,
+		 strsv_, BLAS_S)
+  trsv_interface(lower_tri_solve, trsv_upper, gem_p1_tc, gem_trans1_t,
+		 dtrsv_, BLAS_D) 
+  trsv_interface(lower_tri_solve, trsv_upper, gem_p1_tc, gem_trans1_t,
+		 ctrsv_, BLAS_C) 
+  trsv_interface(lower_tri_solve, trsv_upper, gem_p1_tc, gem_trans1_t,
+		 ztrsv_, BLAS_Z)
+  
+  // X <- UPPER(transposed(const A))^{-1}X.
+  trsv_interface(upper_tri_solve, trsv_lower, gem_p1_tc, gem_trans1_t,
+		 strsv_, BLAS_S)
+  trsv_interface(upper_tri_solve, trsv_lower, gem_p1_tc, gem_trans1_t,
+		 dtrsv_, BLAS_D) 
+  trsv_interface(upper_tri_solve, trsv_lower, gem_p1_tc, gem_trans1_t,
+		 ctrsv_, BLAS_C) 
+  trsv_interface(upper_tri_solve, trsv_lower, gem_p1_tc, gem_trans1_t,
+		 ztrsv_, BLAS_Z)
+
+  // X <- LOWER(conjugated(A))^{-1}X.
+  trsv_interface(lower_tri_solve, trsv_upper, gem_p1_c, gem_trans1_c,
+		 strsv_, BLAS_S)
+  trsv_interface(lower_tri_solve, trsv_upper, gem_p1_c, gem_trans1_c,
+		 dtrsv_, BLAS_D) 
+  trsv_interface(lower_tri_solve, trsv_upper, gem_p1_c, gem_trans1_c,
+		 ctrsv_, BLAS_C) 
+  trsv_interface(lower_tri_solve, trsv_upper, gem_p1_c, gem_trans1_c,
+		 ztrsv_, BLAS_Z)
+  
+  // X <- UPPER(conjugated(A))^{-1}X.
+  trsv_interface(upper_tri_solve, trsv_lower, gem_p1_c, gem_trans1_c,
+		 strsv_, BLAS_S)
+  trsv_interface(upper_tri_solve, trsv_lower, gem_p1_c, gem_trans1_c,
+		 dtrsv_, BLAS_D) 
+  trsv_interface(upper_tri_solve, trsv_lower, gem_p1_c, gem_trans1_c,
+		 ctrsv_, BLAS_C) 
+  trsv_interface(upper_tri_solve, trsv_lower, gem_p1_c, gem_trans1_c,
+		 ztrsv_, BLAS_Z)
+  
+}
+
+#endif // GMM_BLAS_INTERFACE_H
+
+#endif // GMM_USES_BLAS
diff --git a/Contrib/gmm/gmm_condition_number.h b/Contrib/gmm/gmm_condition_number.h
new file mode 100755
index 0000000..4b9f250
--- /dev/null
+++ b/Contrib/gmm/gmm_condition_number.h
@@ -0,0 +1,142 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_condition_number.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>, Julien Pommier <Julien.Pommier at insa-toulouse.fr>
+   @date August 27, 2003.
+   @brief computation of the condition number of dense matrices.
+*/
+#ifndef GMM_CONDITION_NUMBER_H__
+#define GMM_CONDITION_NUMBER_H__
+
+#include "gmm_dense_qr.h"
+
+namespace gmm {
+
+  /** computation of the condition number of dense matrices using SVD.
+
+      Uses symmetric_qr_algorithm => dense matrices only.
+
+      @param M a matrix.
+      @param emin smallest (in magnitude) eigenvalue
+      @param emax largest eigenvalue.
+   */
+  template <typename MAT> 
+  typename number_traits<typename 
+  linalg_traits<MAT>::value_type>::magnitude_type
+  condition_number(const MAT& M, 
+	  typename number_traits<typename
+	  linalg_traits<MAT>::value_type>::magnitude_type& emin,
+	  typename number_traits<typename
+	  linalg_traits<MAT>::value_type>::magnitude_type& emax) {
+    typedef typename linalg_traits<MAT>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+
+    size_type m = mat_nrows(M), n = mat_ncols(M);
+    emax = emin = R(0);
+    std::vector<R> eig(m+n);
+
+    if (m+n == 0) return R(0);
+    if (is_hermitian(M)) {
+      eig.resize(m);
+      gmm::symmetric_qr_algorithm(M, eig);
+    }
+    else {
+      dense_matrix<T> B(m+n, m+n); // not very efficient ??
+      gmm::copy(conjugated(M), sub_matrix(B, sub_interval(m, n), sub_interval(0, m)));
+      gmm::copy(M, sub_matrix(B, sub_interval(0, m),
+					  sub_interval(m, n)));
+      gmm::symmetric_qr_algorithm(B, eig);
+    }
+    emin = emax = gmm::abs(eig[0]);
+    for (size_type i = 1; i < eig.size(); ++i) {
+      R e = gmm::abs(eig[i]); 
+      emin = std::min(emin, e);
+      emax = std::max(emax, e);
+    }
+    // cout << "emin = " << emin << " emax = " << emax << endl;
+    if (emin == R(0)) return gmm::default_max(R());
+    return emax / emin;
+  }
+
+  template <typename MAT> 
+  typename number_traits<typename 
+  linalg_traits<MAT>::value_type>::magnitude_type
+  condition_number(const MAT& M) { 
+    typename number_traits<typename
+      linalg_traits<MAT>::value_type>::magnitude_type emax, emin;
+    return condition_number(M, emin, emax);
+  }
+
+  template <typename MAT> 
+  typename number_traits<typename 
+  linalg_traits<MAT>::value_type>::magnitude_type
+  Frobenius_condition_number_sqr(const MAT& M) { 
+    typedef typename linalg_traits<MAT>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+    size_type m = mat_nrows(M), n = mat_ncols(M);
+    dense_matrix<T> B(std::min(m,n), std::min(m,n));
+    if (m < n) mult(M,gmm::conjugated(M),B);
+    else       mult(gmm::conjugated(M),M,B);
+    R trB = abs(mat_trace(B));
+    lu_inverse(B);
+    return trB*abs(mat_trace(B));
+  }
+
+  template <typename MAT> 
+  typename number_traits<typename 
+  linalg_traits<MAT>::value_type>::magnitude_type
+  Frobenius_condition_number(const MAT& M)
+  { return sqrt(Frobenius_condition_number_sqr(M)); }
+
+  /** estimation of the condition number (TO BE DONE...)
+   */
+  template <typename MAT> 
+  typename number_traits<typename 
+  linalg_traits<MAT>::value_type>::magnitude_type
+  condest(const MAT& M, 
+	  typename number_traits<typename
+	  linalg_traits<MAT>::value_type>::magnitude_type& emin,
+	  typename number_traits<typename
+	  linalg_traits<MAT>::value_type>::magnitude_type& emax) {
+    return condition_number(M, emin, emax);
+  }
+  
+  template <typename MAT> 
+  typename number_traits<typename 
+  linalg_traits<MAT>::value_type>::magnitude_type
+  condest(const MAT& M) { 
+    typename number_traits<typename
+      linalg_traits<MAT>::value_type>::magnitude_type emax, emin;
+    return condest(M, emin, emax);
+  }
+}
+
+#endif
diff --git a/Contrib/gmm/gmm_conjugated.h b/Contrib/gmm/gmm_conjugated.h
new file mode 100755
index 0000000..2f18837
--- /dev/null
+++ b/Contrib/gmm/gmm_conjugated.h
@@ -0,0 +1,395 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_conjugated.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date September 18, 2003.
+   @brief handle conjugation of complex matrices/vectors.
+*/
+#ifndef GMM_CONJUGATED_H__
+#define GMM_CONJUGATED_H__
+
+#include "gmm_def.h"
+
+namespace gmm {
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+  /* ********************************************************************* */
+  /*		Conjugated references on vectors            		   */
+  /* ********************************************************************* */
+
+  template <typename IT> struct conjugated_const_iterator {
+    typedef typename std::iterator_traits<IT>::value_type      value_type;
+    typedef typename std::iterator_traits<IT>::pointer         pointer;
+    typedef typename std::iterator_traits<IT>::reference       reference;
+    typedef typename std::iterator_traits<IT>::difference_type difference_type;
+    typedef typename std::iterator_traits<IT>::iterator_category
+    iterator_category;
+
+    IT it;
+    
+    conjugated_const_iterator(void) {}
+    conjugated_const_iterator(const IT &i) : it(i) {}
+    
+    inline size_type index(void) const { return it.index(); }
+    conjugated_const_iterator operator ++(int)
+    { conjugated_const_iterator tmp = *this; ++it; return tmp; }
+    conjugated_const_iterator operator --(int) 
+    { conjugated_const_iterator tmp = *this; --it; return tmp; }
+    conjugated_const_iterator &operator ++() { ++it; return *this; }
+    conjugated_const_iterator &operator --() { --it; return *this; }
+    conjugated_const_iterator &operator +=(difference_type i)
+      { it += i; return *this; }
+    conjugated_const_iterator &operator -=(difference_type i)
+      { it -= i; return *this; }
+    conjugated_const_iterator operator +(difference_type i) const
+      { conjugated_const_iterator itb = *this; return (itb += i); }
+    conjugated_const_iterator operator -(difference_type i) const
+      { conjugated_const_iterator itb = *this; return (itb -= i); }
+    difference_type operator -(const conjugated_const_iterator &i) const
+      { return difference_type(it - i.it); }
+    
+    value_type operator  *() const { return gmm::conj(*it); }
+    value_type operator [](size_type ii) const { return gmm::conj(it[ii]); }
+    
+    bool operator ==(const conjugated_const_iterator &i) const
+      { return (i.it == it); }
+    bool operator !=(const conjugated_const_iterator &i) const
+      { return (i.it != it); }
+    bool operator < (const conjugated_const_iterator &i) const
+      { return (it < i.it); }
+  };
+
+  template <typename V> struct conjugated_vector_const_ref {
+    typedef conjugated_vector_const_ref<V> this_type;
+    typedef typename linalg_traits<V>::value_type value_type;
+    typedef typename linalg_traits<V>::const_iterator iterator;
+    typedef typename linalg_traits<this_type>::reference reference;
+    typedef typename linalg_traits<this_type>::origin_type origin_type;
+
+    iterator begin_, end_;
+    const origin_type *origin;
+    size_type size_;
+
+    conjugated_vector_const_ref(const V &v)
+      : begin_(vect_const_begin(v)), end_(vect_const_end(v)),
+	origin(linalg_origin(v)),
+	size_(vect_size(v)) {}
+
+    reference operator[](size_type i) const
+    { return gmm::conj(linalg_traits<V>::access(origin, begin_, end_, i)); }
+  };
+
+  template <typename V> struct linalg_traits<conjugated_vector_const_ref<V> > {
+    typedef conjugated_vector_const_ref<V> this_type;
+    typedef typename linalg_traits<V>::origin_type origin_type;
+    typedef linalg_const is_reference;
+    typedef abstract_vector linalg_type;
+    typedef typename linalg_traits<V>::value_type value_type;
+    typedef value_type reference;
+    typedef abstract_null_type iterator;
+    typedef conjugated_const_iterator<typename
+                   linalg_traits<V>::const_iterator> const_iterator;
+    typedef typename linalg_traits<V>::storage_type storage_type;
+    typedef typename linalg_traits<V>::index_sorted index_sorted;
+    static size_type size(const this_type &v) { return v.size_; }
+    static iterator begin(this_type &v) { return iterator(v.begin_); }
+    static const_iterator begin(const this_type &v)
+    { return const_iterator(v.begin_); }
+    static iterator end(this_type &v)
+    { return iterator(v.end_); }
+    static const_iterator end(const this_type &v)
+    { return const_iterator(v.end_); }
+    static value_type access(const origin_type *o, const const_iterator &it,
+			     const const_iterator &ite, size_type i)
+    { return gmm::conj(linalg_traits<V>::access(o, it.it, ite.it, i)); }
+    static const origin_type* origin(const this_type &v) { return v.origin; }
+  };
+
+  template<typename V> std::ostream &operator <<
+    (std::ostream &o, const conjugated_vector_const_ref<V>& m)
+  { gmm::write(o,m); return o; }
+
+  /* ********************************************************************* */
+  /*		Conjugated references on matrices            		   */
+  /* ********************************************************************* */
+
+  template <typename M> struct conjugated_row_const_iterator {
+    typedef conjugated_row_const_iterator<M> iterator;
+    typedef typename linalg_traits<M>::const_row_iterator ITER;
+    typedef typename linalg_traits<M>::value_type value_type;
+    typedef ptrdiff_t difference_type;
+    typedef size_t size_type;
+
+    ITER it;
+
+    iterator operator ++(int) { iterator tmp = *this; it++; return tmp; }
+    iterator operator --(int) { iterator tmp = *this; it--; return tmp; }
+    iterator &operator ++()   { it++; return *this; }
+    iterator &operator --()   { it--; return *this; }
+    iterator &operator +=(difference_type i) { it += i; return *this; }
+    iterator &operator -=(difference_type i) { it -= i; return *this; }
+    iterator operator +(difference_type i) const 
+    { iterator itt = *this; return (itt += i); }
+    iterator operator -(difference_type i) const
+    { iterator itt = *this; return (itt -= i); }
+    difference_type operator -(const iterator &i) const
+    { return it - i.it; }
+
+    ITER operator *() const { return it; }
+    ITER operator [](int i) { return it + i; }
+
+    bool operator ==(const iterator &i) const { return (it == i.it); }
+    bool operator !=(const iterator &i) const { return !(i == *this); }
+    bool operator < (const iterator &i) const { return (it < i.it); }
+
+    conjugated_row_const_iterator(void) {}
+    conjugated_row_const_iterator(const ITER &i) : it(i) { }
+
+  };
+
+  template <typename M> struct  conjugated_row_matrix_const_ref {
+    
+    typedef conjugated_row_matrix_const_ref<M> this_type;
+    typedef typename linalg_traits<M>::const_row_iterator iterator;
+    typedef typename linalg_traits<M>::value_type value_type;
+    typedef typename linalg_traits<this_type>::origin_type origin_type;
+
+    iterator begin_, end_;
+    const origin_type *origin;
+    size_type nr, nc;
+
+    conjugated_row_matrix_const_ref(const M &m)
+      : begin_(mat_row_begin(m)), end_(mat_row_end(m)),
+	origin(linalg_origin(m)), nr(mat_ncols(m)), nc(mat_nrows(m)) {}
+
+    value_type operator()(size_type i, size_type j) const
+    { return gmm::conj(linalg_traits<M>::access(begin_+j, i)); }
+  };
+
+  template <typename M>
+  struct linalg_traits<conjugated_row_matrix_const_ref<M> > {
+    typedef conjugated_row_matrix_const_ref<M> this_type;
+    typedef typename linalg_traits<M>::origin_type origin_type;
+    typedef linalg_const is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef typename linalg_traits<M>::value_type value_type;
+    typedef value_type reference;
+    typedef typename linalg_traits<M>::storage_type storage_type;
+    typedef typename linalg_traits<M>::const_sub_row_type vector_type;
+    typedef conjugated_vector_const_ref<vector_type> sub_col_type;
+    typedef conjugated_vector_const_ref<vector_type> const_sub_col_type;
+    typedef conjugated_row_const_iterator<M> col_iterator;
+    typedef conjugated_row_const_iterator<M> const_col_iterator;
+    typedef abstract_null_type const_sub_row_type;
+    typedef abstract_null_type sub_row_type;
+    typedef abstract_null_type const_row_iterator;
+    typedef abstract_null_type row_iterator;
+    typedef col_major sub_orientation;
+    typedef typename linalg_traits<M>::index_sorted index_sorted;
+    static inline size_type ncols(const this_type &m) { return m.nc; }
+    static inline size_type nrows(const this_type &m) { return m.nr; }
+    static inline const_sub_col_type col(const const_col_iterator &it)
+    { return conjugated(linalg_traits<M>::row(it.it)); }
+    static inline const_col_iterator col_begin(const this_type &m)
+    { return const_col_iterator(m.begin_); }
+    static inline const_col_iterator col_end(const this_type &m)
+    { return const_col_iterator(m.end_); }
+    static inline const origin_type* origin(const this_type &m)
+    { return m.origin; }
+    static value_type access(const const_col_iterator &it, size_type i)
+    { return gmm::conj(linalg_traits<M>::access(it.it, i)); }
+  };
+
+  template<typename M> std::ostream &operator <<
+  (std::ostream &o, const conjugated_row_matrix_const_ref<M>& m)
+  { gmm::write(o,m); return o; }
+
+
+  template <typename M> struct conjugated_col_const_iterator {
+    typedef conjugated_col_const_iterator<M> iterator;
+    typedef typename linalg_traits<M>::const_col_iterator ITER;
+    typedef typename linalg_traits<M>::value_type value_type;
+    typedef ptrdiff_t difference_type;
+    typedef size_t size_type;
+
+    ITER it;
+
+    iterator operator ++(int) { iterator tmp = *this; it++; return tmp; }
+    iterator operator --(int) { iterator tmp = *this; it--; return tmp; }
+    iterator &operator ++()   { it++; return *this; }
+    iterator &operator --()   { it--; return *this; }
+    iterator &operator +=(difference_type i) { it += i; return *this; }
+    iterator &operator -=(difference_type i) { it -= i; return *this; }
+    iterator operator +(difference_type i) const 
+    { iterator itt = *this; return (itt += i); }
+    iterator operator -(difference_type i) const
+    { iterator itt = *this; return (itt -= i); }
+    difference_type operator -(const iterator &i) const
+    { return it - i.it; }
+
+    ITER operator *() const { return it; }
+    ITER operator [](int i) { return it + i; }
+
+    bool operator ==(const iterator &i) const { return (it == i.it); }
+    bool operator !=(const iterator &i) const { return !(i == *this); }
+    bool operator < (const iterator &i) const { return (it < i.it); }
+
+    conjugated_col_const_iterator(void) {}
+    conjugated_col_const_iterator(const ITER &i) : it(i) { }
+
+  };
+
+  template <typename M> struct  conjugated_col_matrix_const_ref {
+    
+    typedef conjugated_col_matrix_const_ref<M> this_type;
+    typedef typename linalg_traits<M>::const_col_iterator iterator;
+    typedef typename linalg_traits<M>::value_type value_type;
+    typedef typename linalg_traits<this_type>::origin_type origin_type;
+
+    iterator begin_, end_;
+    const origin_type *origin;
+    size_type nr, nc;
+
+    conjugated_col_matrix_const_ref(const M &m)
+      : begin_(mat_col_begin(m)), end_(mat_col_end(m)),
+	origin(linalg_origin(m)), nr(mat_ncols(m)), nc(mat_nrows(m)) {}
+
+    value_type operator()(size_type i, size_type j) const
+    { return gmm::conj(linalg_traits<M>::access(begin_+i, j)); }
+  };
+
+  template <typename M>
+  struct linalg_traits<conjugated_col_matrix_const_ref<M> > {
+    typedef conjugated_col_matrix_const_ref<M> this_type;
+    typedef typename linalg_traits<M>::origin_type origin_type;
+    typedef linalg_const is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef typename linalg_traits<M>::value_type value_type;
+    typedef value_type reference;
+    typedef typename linalg_traits<M>::storage_type storage_type;
+    typedef typename linalg_traits<M>::const_sub_col_type vector_type;
+    typedef conjugated_vector_const_ref<vector_type> sub_row_type;
+    typedef conjugated_vector_const_ref<vector_type> const_sub_row_type;
+    typedef conjugated_col_const_iterator<M> row_iterator;
+    typedef conjugated_col_const_iterator<M> const_row_iterator;
+    typedef abstract_null_type const_sub_col_type;
+    typedef abstract_null_type sub_col_type;
+    typedef abstract_null_type const_col_iterator;
+    typedef abstract_null_type col_iterator;
+    typedef row_major sub_orientation;
+    typedef typename linalg_traits<M>::index_sorted index_sorted;
+    static inline size_type nrows(const this_type &m) { return m.nr; }
+    static inline size_type ncols(const this_type &m) { return m.nc; }
+    static inline const_sub_row_type row(const const_row_iterator &it)
+    { return conjugated(linalg_traits<M>::col(it.it)); }
+    static inline const_row_iterator row_begin(const this_type &m)
+    { return const_row_iterator(m.begin_); }
+    static inline const_row_iterator row_end(const this_type &m)
+    { return const_row_iterator(m.end_); }
+    static inline const origin_type* origin(const this_type &m)
+    { return m.origin; }
+    static value_type access(const const_row_iterator &it, size_type i)
+    { return gmm::conj(linalg_traits<M>::access(it.it, i)); }
+  };
+
+  template<typename M> std::ostream &operator <<
+  (std::ostream &o, const conjugated_col_matrix_const_ref<M>& m)
+  { gmm::write(o,m); return o; }
+
+
+  template <typename L, typename SO> struct conjugated_return__ {
+    typedef conjugated_row_matrix_const_ref<L> return_type;
+  };
+  template <typename L> struct conjugated_return__<L, col_major> {
+    typedef conjugated_col_matrix_const_ref<L> return_type;
+  };
+  template <typename L, typename T, typename LT> struct conjugated_return_ {
+    typedef const L & return_type;
+  };
+  template <typename L, typename T>
+  struct conjugated_return_<L, std::complex<T>, abstract_vector> {
+    typedef conjugated_vector_const_ref<L> return_type;
+  };
+  template <typename L, typename T>
+  struct conjugated_return_<L, T, abstract_matrix> {
+    typedef typename conjugated_return__<L,
+    typename principal_orientation_type<typename
+    linalg_traits<L>::sub_orientation>::potype
+    >::return_type return_type;
+  };
+  template <typename L> struct conjugated_return {
+    typedef typename
+    conjugated_return_<L, typename linalg_traits<L>::value_type,
+		       typename linalg_traits<L>::linalg_type		       
+		       >::return_type return_type;
+  };
+
+  ///@endcond
+  /** return a conjugated view of the input matrix or vector. */
+  template <typename L> inline
+  typename conjugated_return<L>::return_type
+  conjugated(const L &v) {
+    return conjugated(v, typename linalg_traits<L>::value_type(),
+		      typename linalg_traits<L>::linalg_type());
+  }
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+  template <typename L, typename T, typename LT> inline
+  const L & conjugated(const L &v, T, LT) { return v; }
+
+  template <typename L, typename T> inline
+  conjugated_vector_const_ref<L> conjugated(const L &v, std::complex<T>,
+					    abstract_vector)
+  { return conjugated_vector_const_ref<L>(v); }
+
+  template <typename L, typename T> inline
+  typename conjugated_return__<L,
+    typename principal_orientation_type<typename
+    linalg_traits<L>::sub_orientation>::potype>::return_type
+  conjugated(const L &v, T, abstract_matrix) {
+    return conjugated(v, typename principal_orientation_type<typename
+		      linalg_traits<L>::sub_orientation>::potype());
+  }
+
+  template <typename L> inline
+  conjugated_row_matrix_const_ref<L> conjugated(const L &v, row_major)
+  { return conjugated_row_matrix_const_ref<L>(v); }
+
+  template <typename L> inline
+  conjugated_col_matrix_const_ref<L> conjugated(const L &v, col_major)
+  { return conjugated_col_matrix_const_ref<L>(v); }
+  
+  ///@endcond
+  
+
+}
+
+#endif //  GMM_CONJUGATED_H__
diff --git a/Contrib/gmm/gmm_def.h b/Contrib/gmm/gmm_def.h
new file mode 100755
index 0000000..e71e33d
--- /dev/null
+++ b/Contrib/gmm/gmm_def.h
@@ -0,0 +1,1117 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_def.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 13, 2002.
+   @brief Basic definitions and tools of GMM.
+*/
+#ifndef GMM_DEF_H__
+#define GMM_DEF_H__
+
+#include "gmm_ref.h"
+#include <complex>
+
+#ifndef M_PI
+# define	M_E		2.7182818284590452354       /* e          */
+# define	M_LOG2E		1.4426950408889634074       /* 1/ln(2)    */
+# define	M_LOG10E	0.43429448190325182765      /* 1/ln(10)   */
+# define	M_LN2		0.69314718055994530942      /* ln(2)      */
+# define	M_LN10		2.30258509299404568402      /* ln(10)     */
+# define	M_PI		3.14159265358979323846      /* pi         */
+# define	M_PI_2		1.57079632679489661923      /* pi/2       */
+# define	M_PI_4		0.78539816339744830962      /* pi/4       */
+# define	M_1_PI		0.31830988618379067154      /* 1/pi       */
+# define	M_2_PI		0.63661977236758134308      /* 2/pi       */
+# define	M_2_SQRTPI	1.12837916709551257390      /* 2/sqrt(pi) */
+# define	M_SQRT2		1.41421356237309504880      /* sqrt(2)    */
+# define	M_SQRT1_2	0.70710678118654752440      /* sqrt(2)/2  */
+#endif 
+
+#ifndef M_PIl
+# define M_PIl       3.1415926535897932384626433832795029L  /* pi         */
+# define M_PI_2l     1.5707963267948966192313216916397514L  /* pi/2       */
+# define M_PI_4l     0.7853981633974483096156608458198757L  /* pi/4       */
+# define M_1_PIl     0.3183098861837906715377675267450287L  /* 1/pi       */
+# define M_2_PIl     0.6366197723675813430755350534900574L  /* 2/pi       */
+# define M_2_SQRTPIl 1.1283791670955125738961589031215452L  /* 2/sqrt(pi) */
+#endif
+
+namespace gmm {
+
+  typedef size_t size_type;
+
+  /* ******************************************************************** */
+  /*		Specifier types                             		  */
+  /* ******************************************************************** */
+  /* not perfectly null, required by aCC 3.33                             */
+  struct abstract_null_type { 
+    abstract_null_type(int=0) {}
+    template <typename A,typename B,typename C> void operator()(A,B,C) {}
+  }; // specify an information lake.
+
+  struct linalg_true {};
+  struct linalg_false {};
+
+  template <typename V, typename W> struct linalg_and
+  { typedef linalg_false bool_type; };
+  template <> struct linalg_and<linalg_true, linalg_true>
+  { typedef linalg_true bool_type; };
+  template <typename V, typename W> struct linalg_or
+  { typedef linalg_true bool_type; };
+  template <> struct linalg_and<linalg_false, linalg_false>
+  { typedef linalg_false bool_type; };
+
+  struct linalg_const {};       // A reference is either linalg_const,
+  struct linalg_modifiable {};  //  linalg_modifiable or linalg_false.
+
+  struct abstract_vector {};    // The object is a vector
+  struct abstract_matrix {};    // The object is a matrix
+  
+  struct abstract_sparse {};    // sparse matrix or vector
+  struct abstract_skyline {};   // 'sky-line' matrix or vector
+  struct abstract_dense {};     // dense matrix or vector
+  struct abstract_indirect {};  // matrix given by the product with a vector
+
+  struct row_major {};          // matrix with a row access.
+  struct col_major {};          // matrix with a column access
+  struct row_and_col {};        // both accesses but row preference
+  struct col_and_row {};        // both accesses but column preference
+
+  template <typename T> struct transposed_type;
+  template<> struct transposed_type<row_major>   {typedef col_major   t_type;};
+  template<> struct transposed_type<col_major>   {typedef row_major   t_type;};
+  template<> struct transposed_type<row_and_col> {typedef col_and_row t_type;};
+  template<> struct transposed_type<col_and_row> {typedef row_and_col t_type;};
+
+  template <typename T> struct principal_orientation_type
+  { typedef abstract_null_type potype; };
+  template<> struct principal_orientation_type<row_major>
+  { typedef row_major potype; };
+  template<> struct principal_orientation_type<col_major>
+  { typedef col_major potype; };
+  template<> struct principal_orientation_type<row_and_col>
+  { typedef row_major potype; };
+  template<> struct principal_orientation_type<col_and_row>
+  { typedef col_major potype; };
+
+  //  template <typename V> struct linalg_traits;
+  template <typename V> struct linalg_traits {    
+    typedef abstract_null_type this_type;
+    typedef abstract_null_type linalg_type;
+    typedef abstract_null_type value_type;
+    typedef abstract_null_type is_reference;
+    typedef abstract_null_type& reference;
+    typedef abstract_null_type* iterator;
+    typedef const abstract_null_type* const_iterator;
+    typedef abstract_null_type index_sorted;
+    typedef abstract_null_type storage_type;
+    typedef abstract_null_type origin_type;
+    typedef abstract_null_type const_sub_row_type;
+    typedef abstract_null_type sub_row_type;
+    typedef abstract_null_type const_row_iterator;
+    typedef abstract_null_type row_iterator;
+    typedef abstract_null_type const_sub_col_type;
+    typedef abstract_null_type sub_col_type;
+    typedef abstract_null_type const_col_iterator;
+    typedef abstract_null_type col_iterator;
+    typedef abstract_null_type sub_orientation;    
+  };
+
+  template <typename PT, typename V> struct vect_ref_type;
+  template <typename P, typename V> struct vect_ref_type<P *, V> {
+    typedef typename linalg_traits<V>::reference access_type;
+    typedef typename linalg_traits<V>::iterator iterator;
+  };
+  template <typename P, typename V> struct vect_ref_type<const P *, V> {
+    typedef typename linalg_traits<V>::value_type access_type;
+    typedef typename linalg_traits<V>::const_iterator iterator;
+  };
+  
+  template <typename PT> struct const_pointer;
+  template <typename P> struct const_pointer<P *>
+  { typedef const P* pointer; };
+  template <typename P> struct const_pointer<const P *>
+  { typedef const P* pointer; };
+
+  template <typename PT> struct modifiable_pointer;
+  template <typename P> struct modifiable_pointer<P *>
+  { typedef P* pointer; };
+  template <typename P> struct modifiable_pointer<const P *>
+  { typedef P* pointer; };
+
+  template <typename R> struct const_reference;
+  template <typename R> struct const_reference<R &>
+  { typedef const R &reference; };
+  template <typename R> struct const_reference<const R &>
+  { typedef const R  &reference; };
+
+
+  inline bool is_sparse(abstract_sparse)   { return true;  }
+  inline bool is_sparse(abstract_dense)    { return false; }
+  inline bool is_sparse(abstract_skyline)  { return true;  }
+  inline bool is_sparse(abstract_indirect) { return false; }
+
+  template <typename L> inline bool is_sparse(const L &) 
+  { return is_sparse(typename linalg_traits<L>::storage_type()); }
+
+  inline bool is_row_matrix_(row_major)     { return true;  }
+  inline bool is_row_matrix_(col_major)     { return false; }
+  inline bool is_row_matrix_(row_and_col)   { return true;  }
+  inline bool is_row_matrix_(col_and_row)   { return true;  }
+
+  template <typename L> inline bool is_row_matrix(const L &) 
+  { return is_row_matrix_(typename linalg_traits<L>::sub_orientation()); }
+
+  inline bool is_col_matrix_(row_major)     { return false; }
+  inline bool is_col_matrix_(col_major)     { return true;  }
+  inline bool is_col_matrix_(row_and_col)   { return true;  }
+  inline bool is_col_matrix_(col_and_row)   { return true;  }
+
+  template <typename L> inline bool is_col_matrix(const L &) 
+  { return is_col_matrix_(typename linalg_traits<L>::sub_orientation()); }
+
+  inline bool is_col_matrix(row_major) { return false; }
+  inline bool is_col_matrix(col_major) { return true; }
+  inline bool is_row_matrix(row_major) { return true; }
+  inline bool is_row_matrix(col_major) { return false; }
+
+  template <typename L> inline bool is_const_reference(L) { return false; }
+  inline bool is_const_reference(linalg_const) { return true; }  
+
+
+  template <typename T> struct is_gmm_interfaced_ {
+    typedef linalg_true result;
+  };
+  
+  template<> struct is_gmm_interfaced_<abstract_null_type> {
+    typedef linalg_false result;
+  };
+  
+  template <typename T> struct is_gmm_interfaced {
+    typedef typename is_gmm_interfaced_<typename gmm::linalg_traits<T>::this_type >::result result;
+  };
+
+  /* ******************************************************************** */
+  /*  types to deal with const object representing a modifiable reference */
+  /* ******************************************************************** */
+  
+  template <typename PT, typename R> struct mref_type_ 
+  { typedef abstract_null_type return_type; };
+  template <typename L, typename R> struct mref_type_<L *, R>
+  { typedef L & return_type; };
+  template <typename L, typename R> struct mref_type_<const L *, R>
+  { typedef const L & return_type; };
+  template <typename L> struct mref_type_<L *, linalg_const>
+  { typedef const L & return_type; };
+  template <typename L> struct mref_type_<const L *, linalg_const>
+  { typedef const L & return_type; };
+  template <typename L> struct mref_type_<const L *, linalg_modifiable>
+  { typedef L & return_type; };
+  template <typename L> struct mref_type_<L *, linalg_modifiable>
+  { typedef L & return_type; };
+
+  template <typename PT> struct mref_type {
+    typedef typename std::iterator_traits<PT>::value_type L;
+    typedef typename mref_type_<PT, 
+      typename linalg_traits<L>::is_reference>::return_type return_type;
+  };
+
+  template <typename L> typename mref_type<const L *>::return_type 
+  linalg_cast(const L &l)
+  { return const_cast<typename mref_type<const L *>::return_type>(l); }
+
+  template <typename L> typename mref_type<L *>::return_type linalg_cast(L &l)
+  { return const_cast<typename mref_type<L *>::return_type>(l); }
+
+  template <typename L, typename R> struct cref_type_
+  { typedef abstract_null_type return_type; };
+  template <typename L> struct cref_type_<L, linalg_modifiable>
+  { typedef L & return_type; };
+  template <typename L> struct cref_type {
+    typedef typename cref_type_<L, 
+      typename linalg_traits<L>::is_reference>::return_type return_type;
+  };
+
+  template <typename L> typename cref_type<L>::return_type 
+  linalg_const_cast(const L &l)
+  { return const_cast<typename cref_type<L>::return_type>(l); }
+
+
+  // To be used to select between a reference or a const refercence for
+  // the return type of a function
+  // select_return<C1, C2, L *> return C1 if L is a const reference,
+  //                                   C2 otherwise.
+  // select_return<C1, C2, const L *> return C2 if L is a modifiable reference
+  //                                         C1 otherwise. 
+  template <typename C1, typename C2, typename REF> struct select_return_ {
+    typedef abstract_null_type return_type;
+  };
+  template <typename C1, typename C2, typename L>
+  struct select_return_<C1, C2, const L &> { typedef C1 return_type; };
+  template <typename C1, typename C2, typename L>
+  struct select_return_<C1, C2, L &> { typedef C2 return_type; };
+  template <typename C1, typename C2, typename PT> struct select_return {
+    typedef typename std::iterator_traits<PT>::value_type L;
+    typedef typename select_return_<C1, C2, 
+      typename mref_type<PT>::return_type>::return_type return_type;
+  };
+
+  
+  // To be used to select between a reference or a const refercence inside
+  // a structure or a linagl_traits
+  // select_ref<C1, C2, L *> return C1 if L is a const reference,
+  //                                C2 otherwise.
+  // select_ref<C1, C2, const L *> return C2 in any case. 
+  template <typename C1, typename C2, typename REF> struct select_ref_
+  { typedef abstract_null_type ref_type; };
+  template <typename C1, typename C2, typename L>
+  struct select_ref_<C1, C2, const L &> { typedef C1 ref_type; };
+  template <typename C1, typename C2, typename L>
+  struct select_ref_<C1, C2, L &> { typedef C2 ref_type; };
+  template <typename C1, typename C2, typename PT> struct select_ref {
+    typedef typename std::iterator_traits<PT>::value_type L;
+    typedef typename select_ref_<C1, C2, 
+      typename mref_type<PT>::return_type>::ref_type ref_type;
+  };
+  template <typename C1, typename C2, typename L>
+  struct select_ref<C1, C2, const L *>
+  { typedef C1 ref_type; };
+
+
+  template<typename R> struct is_a_reference_
+  { typedef linalg_true reference; };
+  template<> struct is_a_reference_<linalg_false>
+  { typedef linalg_false reference; };
+
+  template<typename L> struct is_a_reference {
+    typedef typename is_a_reference_<typename linalg_traits<L>::is_reference>
+      ::reference reference;
+  };
+
+
+  template <typename L> inline bool is_original_linalg(const L &) 
+  { return is_original_linalg(typename is_a_reference<L>::reference()); }
+  inline bool is_original_linalg(linalg_false) { return true; }
+  inline bool is_original_linalg(linalg_true) { return false; }
+
+
+  template <typename PT> struct which_reference 
+  { typedef abstract_null_type is_reference; };
+  template <typename PT> struct which_reference<PT *>
+  { typedef linalg_modifiable is_reference; };
+  template <typename PT> struct which_reference<const PT *>
+  { typedef linalg_const is_reference; };
+
+
+  template <typename C1, typename C2, typename R> struct select_orientation_
+  { typedef abstract_null_type return_type; };
+  template <typename C1, typename C2>
+  struct select_orientation_<C1, C2, row_major>
+  { typedef C1 return_type; };
+  template <typename C1, typename C2>
+  struct select_orientation_<C1, C2, col_major>
+  { typedef C2 return_type; };
+  template <typename C1, typename C2, typename L> struct select_orientation {
+    typedef typename select_orientation_<C1, C2,
+      typename principal_orientation_type<typename
+      linalg_traits<L>::sub_orientation>::potype>::return_type return_type;
+  };
+  
+  /* ******************************************************************** */
+  /*		Operations on scalars                         		  */
+  /* ******************************************************************** */
+
+  template <typename T> inline T sqr(T a) { return a * a; }
+  template <typename T> inline T abs(T a) { return (a < T(0)) ? T(-a) : a; }
+  template <typename T> inline T abs(std::complex<T> a)
+  { T x = a.real(), y = a.imag(); return ::sqrt(x*x+y*y); }
+  template <typename T> inline T abs_sqr(T a) { return a*a; }
+  template <typename T> inline T abs_sqr(std::complex<T> a)
+  { return gmm::sqr(a.real()) + gmm::sqr(a.imag()); }
+  template <typename T> inline T pos(T a) { return (a < T(0)) ? T(0) : a; }
+  template <typename T> inline T neg(T a) { return (a < T(0)) ? T(-a) : T(0); }
+  template <typename T> inline T sgn(T a) { return (a < T(0)) ? T(-1) : T(1); }
+  inline double random() { return double(rand())/(RAND_MAX+0.5); }
+  template <typename T> inline T random(T)
+  { return T(rand()*2.0)/(T(RAND_MAX)+T(1)/T(2)) - T(1); }
+  template <typename T> inline std::complex<T> random(std::complex<T>)
+  { return std::complex<T>(gmm::random(T()), gmm::random(T())); }
+  template <typename T> inline T irandom(T max)
+  { return T(gmm::random() * max); }
+  template <typename T> inline T conj(T a) { return a; }
+  template <typename T> inline std::complex<T> conj(std::complex<T> a)
+  { return std::conj(a); }
+  template <typename T> inline T real(T a) { return a; }
+  template <typename T> inline T real(std::complex<T> a) { return a.real(); }
+  template <typename T> inline T imag(T ) { return T(0); }
+  template <typename T> inline T imag(std::complex<T> a) { return a.imag(); }  
+  template <typename T> inline T sqrt(T a) { return ::sqrt(a); }
+  template <typename T> inline std::complex<T> sqrt(std::complex<T> a) {
+    T x = a.real(), y = a.imag();
+    if (x == T(0)) {
+      T t = ::sqrt(gmm::abs(y) / T(2));
+      return std::complex<T>(t, y < T(0) ? -t : t);
+    }
+    T t = ::sqrt(T(2) * (gmm::abs(a) + gmm::abs(x))), u = t / T(2);
+    return x > T(0) ? std::complex<T>(u, y / t)
+      : std::complex<T>(gmm::abs(y) / t, y < T(0) ? -u : u);
+  }
+  using std::swap;
+
+
+  template <typename T> struct number_traits {
+    typedef T magnitude_type;
+  };
+ 
+  template <typename T> struct number_traits<std::complex<T> > {
+    typedef T magnitude_type;
+  };
+
+  template <typename T> inline T conj_product(T a, T b) { return a * b; }
+  template <typename T> inline
+  std::complex<T> conj_product(std::complex<T> a, std::complex<T> b)
+  { return std::conj(a) * b; } // to be optimized ?
+
+  template <typename T> inline bool is_complex(T) { return false; }
+  template <typename T> inline bool is_complex(std::complex<T> )
+  { return true; }
+
+# define magnitude_of_linalg(M) typename number_traits<typename \
+                    linalg_traits<M>::value_type>::magnitude_type
+  
+  template<typename T> inline std::complex<T> operator*(const std::complex<T>& a, int b) {
+    return a*T(b);
+  }
+  template<typename T> inline std::complex<T> operator*(int b, const std::complex<T>& a) {
+    return a*T(b);
+  }
+
+  /* ******************************************************************** */
+  /*  types promotion                                                     */
+  /* ******************************************************************** */
+
+  /* should be completed for more specific cases <unsigned int, float> etc */
+  template <typename T1, typename T2, bool c>
+  struct strongest_numeric_type_aux {
+    typedef T1 T;
+  };
+  template <typename T1, typename T2>
+  struct strongest_numeric_type_aux<T1,T2,false> {
+    typedef T2 T;
+  };
+
+  template <typename T1, typename T2>
+  struct strongest_numeric_type {
+    typedef typename
+    strongest_numeric_type_aux<T1,T2,(sizeof(T1)>sizeof(T2))>::T T;
+  };
+  template <typename T1, typename T2>
+  struct strongest_numeric_type<T1,std::complex<T2> > {
+    typedef typename number_traits<T1>::magnitude_type R1;
+    typedef std::complex<typename strongest_numeric_type<R1,T2>::T > T;
+  };
+  template <typename T1, typename T2>
+  struct strongest_numeric_type<std::complex<T1>,T2 > {
+    typedef typename number_traits<T2>::magnitude_type R2;
+    typedef std::complex<typename strongest_numeric_type<T1,R2>::T > T;
+  };
+  template <typename T1, typename T2> 
+  struct strongest_numeric_type<std::complex<T1>,std::complex<T2> > {
+    typedef std::complex<typename strongest_numeric_type<T1,T2>::T > T;
+  };
+
+  template<> struct strongest_numeric_type<int,float>   { typedef float T;  };
+  template<> struct strongest_numeric_type<float,int>   { typedef float T;  };
+  template<> struct strongest_numeric_type<long,float>  { typedef float T;  };
+  template<> struct strongest_numeric_type<float,long>  { typedef float T;  };
+  template<> struct strongest_numeric_type<long,double> { typedef double T; };
+  template<> struct strongest_numeric_type<double,long> { typedef double T; };
+
+  template <typename V1, typename V2>
+  struct strongest_value_type {
+    typedef typename
+    strongest_numeric_type<typename linalg_traits<V1>::value_type,
+			   typename linalg_traits<V2>::value_type>::T
+    value_type;
+  };
+  template <typename V1, typename V2, typename V3>
+  struct strongest_value_type3 {
+    typedef typename
+    strongest_value_type<V1, typename
+			 strongest_value_type<V2,V3>::value_type>::value_type
+    value_type;
+  };
+
+  
+
+  /* ******************************************************************** */
+  /*		Basic vectors used                         		  */
+  /* ******************************************************************** */
+  
+  template<typename T> struct dense_vector_type 
+  { typedef std::vector<T> vector_type; };
+
+  template <typename T> class wsvector;
+  template <typename T> class rsvector;
+  template<typename T> struct sparse_vector_type 
+  { typedef wsvector<T> vector_type; };
+
+  template <typename T> class slvector;
+  template <typename T> class dense_matrix;
+  template <typename VECT> class row_matrix;
+  template <typename VECT> class col_matrix;
+  
+
+  /* ******************************************************************** */
+  /*   Selects a temporary vector type                                    */
+  /*   V if V is a valid vector type,                                     */
+  /*   wsvector if V is a reference on a sparse vector,                   */
+  /*   std::vector if V is a reference on a dense vector.                 */
+  /* ******************************************************************** */
+
+  
+  template <typename R, typename S, typename L, typename V>
+  struct temporary_vector_ {
+    typedef abstract_null_type vector_type;
+  };
+  template <typename V, typename L>
+  struct temporary_vector_<linalg_true, abstract_sparse, L, V>
+  { typedef wsvector<typename linalg_traits<V>::value_type> vector_type; };
+  template <typename V, typename L>
+  struct temporary_vector_<linalg_true, abstract_skyline, L, V>
+  { typedef slvector<typename linalg_traits<V>::value_type> vector_type; };
+  template <typename V, typename L>
+  struct temporary_vector_<linalg_true, abstract_dense, L, V>
+  { typedef std::vector<typename linalg_traits<V>::value_type> vector_type; };
+  template <typename S, typename V>
+  struct temporary_vector_<linalg_false, S, abstract_vector, V>
+  { typedef V vector_type; };
+  template <typename V>
+  struct temporary_vector_<linalg_false, abstract_dense, abstract_matrix, V>
+  { typedef std::vector<typename linalg_traits<V>::value_type> vector_type; };
+  template <typename V>
+  struct temporary_vector_<linalg_false, abstract_sparse, abstract_matrix, V>
+  { typedef wsvector<typename linalg_traits<V>::value_type> vector_type; };
+
+  template <typename V> struct temporary_vector {
+    typedef typename temporary_vector_<typename is_a_reference<V>::reference,
+				       typename linalg_traits<V>::storage_type,
+				       typename linalg_traits<V>::linalg_type,
+				       V>::vector_type vector_type;
+  };
+
+  /* ******************************************************************** */
+  /*   Selects a temporary matrix type                                    */
+  /*   M if M is a valid matrix type,                                     */
+  /*   row_matrix<wsvector> if M is a reference on a sparse matrix,       */
+  /*   dense_matrix if M is a reference on a dense matrix.                */
+  /* ******************************************************************** */
+
+  
+  template <typename R, typename S, typename L, typename V>
+  struct temporary_matrix_ { typedef abstract_null_type matrix_type; };
+  template <typename V, typename L>
+  struct temporary_matrix_<linalg_true, abstract_sparse, L, V> {
+    typedef typename linalg_traits<V>::value_type T;
+    typedef row_matrix<wsvector<T> > matrix_type;
+  };
+  template <typename V, typename L>
+  struct temporary_matrix_<linalg_true, abstract_skyline, L, V> {
+    typedef typename linalg_traits<V>::value_type T;
+    typedef row_matrix<slvector<T> > matrix_type;
+  };
+  template <typename V, typename L>
+  struct temporary_matrix_<linalg_true, abstract_dense, L, V>
+  { typedef dense_matrix<typename linalg_traits<V>::value_type> matrix_type; };
+  template <typename S, typename V>
+  struct temporary_matrix_<linalg_false, S, abstract_matrix, V>
+  { typedef V matrix_type; };
+
+  template <typename V> struct temporary_matrix {
+    typedef typename temporary_matrix_<typename is_a_reference<V>::reference,
+				       typename linalg_traits<V>::storage_type,
+				       typename linalg_traits<V>::linalg_type,
+				       V>::matrix_type matrix_type;
+  };
+
+  
+  template <typename S, typename L, typename V>
+  struct temporary_col_matrix_ { typedef abstract_null_type matrix_type; };
+  template <typename V, typename L>
+  struct temporary_col_matrix_<abstract_sparse, L, V> {
+    typedef typename linalg_traits<V>::value_type T;
+    typedef col_matrix<wsvector<T> > matrix_type;
+  };
+  template <typename V, typename L>
+  struct temporary_col_matrix_<abstract_skyline, L, V> {
+    typedef typename linalg_traits<V>::value_type T;
+    typedef col_matrix<slvector<T> > matrix_type;
+  };
+  template <typename V, typename L>
+  struct temporary_col_matrix_<abstract_dense, L, V>
+  { typedef dense_matrix<typename linalg_traits<V>::value_type> matrix_type; };
+
+  template <typename V> struct temporary_col_matrix {
+    typedef typename temporary_col_matrix_<
+      typename linalg_traits<V>::storage_type,
+      typename linalg_traits<V>::linalg_type,
+      V>::matrix_type matrix_type;
+  };
+
+
+
+
+  template <typename S, typename L, typename V>
+  struct temporary_row_matrix_ { typedef abstract_null_type matrix_type; };
+  template <typename V, typename L>
+  struct temporary_row_matrix_<abstract_sparse, L, V> {
+    typedef typename linalg_traits<V>::value_type T;
+    typedef row_matrix<wsvector<T> > matrix_type;
+  };
+  template <typename V, typename L>
+  struct temporary_row_matrix_<abstract_skyline, L, V> {
+    typedef typename linalg_traits<V>::value_type T;
+    typedef row_matrix<slvector<T> > matrix_type;
+  };
+  template <typename V, typename L>
+  struct temporary_row_matrix_<abstract_dense, L, V>
+  { typedef dense_matrix<typename linalg_traits<V>::value_type> matrix_type; };
+
+  template <typename V> struct temporary_row_matrix {
+    typedef typename temporary_row_matrix_<
+      typename linalg_traits<V>::storage_type,
+      typename linalg_traits<V>::linalg_type,
+      V>::matrix_type matrix_type;
+  };
+
+
+
+  /* ******************************************************************** */
+  /*   Selects a temporary dense vector type                              */
+  /*   V if V is a valid dense vector type,                               */
+  /*   std::vector if V is a reference or another type of vector          */
+  /* ******************************************************************** */
+
+  template <typename R, typename S, typename V>
+  struct temporary_dense_vector_ { typedef abstract_null_type vector_type; };
+  template <typename S, typename V>
+  struct temporary_dense_vector_<linalg_true, S, V>
+  { typedef std::vector<typename linalg_traits<V>::value_type> vector_type; };
+  template <typename V>
+  struct temporary_dense_vector_<linalg_false, abstract_sparse, V>
+  { typedef std::vector<typename linalg_traits<V>::value_type> vector_type; };
+  template <typename V>
+  struct temporary_dense_vector_<linalg_false, abstract_skyline, V>
+  { typedef std::vector<typename linalg_traits<V>::value_type> vector_type; };
+  template <typename V>
+  struct temporary_dense_vector_<linalg_false, abstract_dense, V>
+  { typedef V vector_type; };
+
+  template <typename V> struct temporary_dense_vector {
+    typedef typename temporary_dense_vector_<typename
+    is_a_reference<V>::reference,
+    typename linalg_traits<V>::storage_type, V>::vector_type vector_type;
+  };
+
+  /* ******************************************************************** */
+  /*   Selects a temporary sparse vector type                             */
+  /*   V if V is a valid sparse vector type,                              */
+  /*   wsvector if V is a reference or another type of vector             */
+  /* ******************************************************************** */
+
+  template <typename R, typename S, typename V>
+  struct temporary_sparse_vector_ { typedef abstract_null_type vector_type; };
+  template <typename S, typename V>
+  struct temporary_sparse_vector_<linalg_true, S, V>
+  { typedef wsvector<typename linalg_traits<V>::value_type> vector_type; };
+  template <typename V>
+  struct temporary_sparse_vector_<linalg_false, abstract_sparse, V>
+  { typedef V vector_type; };
+  template <typename V>
+  struct temporary_sparse_vector_<linalg_false, abstract_dense, V>
+  { typedef wsvector<typename linalg_traits<V>::value_type> vector_type; };
+  template <typename V>
+  struct temporary_sparse_vector_<linalg_false, abstract_skyline, V>
+  { typedef wsvector<typename linalg_traits<V>::value_type> vector_type; };
+
+  template <typename V> struct temporary_sparse_vector {
+    typedef typename temporary_sparse_vector_<typename
+    is_a_reference<V>::reference,
+    typename linalg_traits<V>::storage_type, V>::vector_type vector_type;
+  };
+
+  /* ******************************************************************** */
+  /*   Selects a temporary sky-line vector type                           */
+  /*   V if V is a valid sky-line vector type,                            */
+  /*   slvector if V is a reference or another type of vector             */
+  /* ******************************************************************** */
+
+  template <typename R, typename S, typename V>
+  struct temporary_skyline_vector_
+  { typedef abstract_null_type vector_type; };
+  template <typename S, typename V>
+  struct temporary_skyline_vector_<linalg_true, S, V>
+  { typedef slvector<typename linalg_traits<V>::value_type> vector_type; };
+  template <typename V>
+  struct temporary_skyline_vector_<linalg_false, abstract_skyline, V>
+  { typedef V vector_type; };
+  template <typename V>
+  struct temporary_skyline_vector_<linalg_false, abstract_dense, V>
+  { typedef slvector<typename linalg_traits<V>::value_type> vector_type; };
+  template <typename V>
+  struct temporary_skyline_vector_<linalg_false, abstract_sparse, V>
+  { typedef slvector<typename linalg_traits<V>::value_type> vector_type; };
+
+  template <typename V> struct temporary_skylines_vector {
+    typedef typename temporary_skyline_vector_<typename
+    is_a_reference<V>::reference,
+    typename linalg_traits<V>::storage_type, V>::vector_type vector_type;
+  };
+
+  /* ********************************************************************* */
+  /*  Definition & Comparison of origins.                                  */
+  /* ********************************************************************* */
+
+  template <typename L> 
+  typename select_return<const typename linalg_traits<L>::origin_type *,
+			 typename linalg_traits<L>::origin_type *,
+			 L *>::return_type
+  linalg_origin(L &l)
+  { return linalg_traits<L>::origin(linalg_cast(l)); }
+
+  template <typename L> 
+  typename select_return<const typename linalg_traits<L>::origin_type *,
+			 typename linalg_traits<L>::origin_type *,
+			 const L *>::return_type
+  linalg_origin(const L &l)
+  { return linalg_traits<L>::origin(linalg_cast(l)); }
+
+  template <typename PT1, typename PT2>
+  bool same_porigin(PT1, PT2) { return false; }
+
+  template <typename PT>
+  bool same_porigin(PT pt1, PT pt2) { return (pt1 == pt2); }
+
+  template <typename L1, typename L2>
+  bool same_origin(const L1 &l1, const L2 &l2)
+  { return same_porigin(linalg_origin(l1), linalg_origin(l2)); }
+
+
+  /* ******************************************************************** */
+  /*		Miscellaneous                           		  */
+  /* ******************************************************************** */
+
+  template <typename V> inline size_type vect_size(const V &v)
+  { return linalg_traits<V>::size(v); }
+
+  template <typename MAT> inline size_type mat_nrows(const MAT &m)
+  { return linalg_traits<MAT>::nrows(m); }
+
+  template <typename MAT> inline size_type mat_ncols(const MAT &m)
+  { return linalg_traits<MAT>::ncols(m); }
+
+
+  template <typename V> inline
+  typename select_return<typename linalg_traits<V>::const_iterator,
+           typename linalg_traits<V>::iterator, V *>::return_type
+  vect_begin(V &v)
+  { return linalg_traits<V>::begin(linalg_cast(v)); }
+
+  template <typename V> inline
+  typename select_return<typename linalg_traits<V>::const_iterator,
+	   typename linalg_traits<V>::iterator, const V *>::return_type
+  vect_begin(const V &v)
+  { return linalg_traits<V>::begin(linalg_cast(v)); }
+
+  template <typename V> inline
+  typename linalg_traits<V>::const_iterator
+  vect_const_begin(const V &v)
+  { return linalg_traits<V>::begin(v); }
+
+  template <typename V> inline
+  typename select_return<typename linalg_traits<V>::const_iterator,
+    typename linalg_traits<V>::iterator, V *>::return_type
+  vect_end(V &v)
+  { return linalg_traits<V>::end(linalg_cast(v)); }
+
+  template <typename V> inline
+  typename select_return<typename linalg_traits<V>::const_iterator,
+    typename linalg_traits<V>::iterator, const V *>::return_type
+  vect_end(const V &v)
+  { return linalg_traits<V>::end(linalg_cast(v)); }
+
+  template <typename V> inline
+  typename linalg_traits<V>::const_iterator
+  vect_const_end(const V &v)
+  { return linalg_traits<V>::end(v); }
+
+  template <typename M> inline
+  typename select_return<typename linalg_traits<M>::const_row_iterator,
+    typename linalg_traits<M>::row_iterator, M *>::return_type
+  mat_row_begin(M &m) { return linalg_traits<M>::row_begin(linalg_cast(m)); }
+  
+  template <typename M> inline
+  typename select_return<typename linalg_traits<M>::const_row_iterator,
+    typename linalg_traits<M>::row_iterator, const M *>::return_type
+  mat_row_begin(const M &m)
+  { return linalg_traits<M>::row_begin(linalg_cast(m)); }
+  
+  template <typename M> inline typename linalg_traits<M>::const_row_iterator
+  mat_row_const_begin(const M &m)
+  { return linalg_traits<M>::row_begin(m); }
+
+  template <typename M> inline
+  typename select_return<typename linalg_traits<M>::const_row_iterator,
+    typename linalg_traits<M>::row_iterator, M *>::return_type
+  mat_row_end(M &v) {
+    return linalg_traits<M>::row_end(linalg_cast(v));
+  }
+
+  template <typename M> inline
+  typename select_return<typename linalg_traits<M>::const_row_iterator,
+    typename linalg_traits<M>::row_iterator, const M *>::return_type
+  mat_row_end(const M &v) {
+    return linalg_traits<M>::row_end(linalg_cast(v));
+  }
+
+  template <typename M> inline
+  typename linalg_traits<M>::const_row_iterator
+  mat_row_const_end(const M &v)
+  { return linalg_traits<M>::row_end(v); }
+
+  template <typename M> inline
+  typename select_return<typename linalg_traits<M>::const_col_iterator,
+    typename linalg_traits<M>::col_iterator, M *>::return_type
+  mat_col_begin(M &v) {
+    return linalg_traits<M>::col_begin(linalg_cast(v));
+  }
+
+  template <typename M> inline
+  typename select_return<typename linalg_traits<M>::const_col_iterator,
+    typename linalg_traits<M>::col_iterator, const M *>::return_type
+  mat_col_begin(const M &v) {
+    return linalg_traits<M>::col_begin(linalg_cast(v));
+  }
+
+  template <typename M> inline
+  typename linalg_traits<M>::const_col_iterator
+  mat_col_const_begin(const M &v)
+  { return linalg_traits<M>::col_begin(v); }
+
+  template <typename M> inline
+  typename linalg_traits<M>::const_col_iterator
+  mat_col_const_end(const M &v)
+  { return linalg_traits<M>::col_end(v); }
+
+  template <typename M> inline
+  typename select_return<typename linalg_traits<M>::const_col_iterator,
+                         typename linalg_traits<M>::col_iterator,
+                         M *>::return_type
+  mat_col_end(M &m)
+  { return linalg_traits<M>::col_end(linalg_cast(m)); }
+
+  template <typename M> inline
+  typename select_return<typename linalg_traits<M>::const_col_iterator,
+                         typename linalg_traits<M>::col_iterator,
+                         const M *>::return_type
+  mat_col_end(const M &m)
+  { return linalg_traits<M>::col_end(linalg_cast(m)); }
+
+  template <typename MAT> inline
+  typename select_return<typename linalg_traits<MAT>::const_sub_row_type,
+                         typename linalg_traits<MAT>::sub_row_type,
+                         const MAT *>::return_type
+  mat_row(const MAT &m, size_type i)
+  { return linalg_traits<MAT>::row(mat_row_begin(m) + i); }
+
+  template <typename MAT> inline
+  typename select_return<typename linalg_traits<MAT>::const_sub_row_type,
+                         typename linalg_traits<MAT>::sub_row_type,
+                         MAT *>::return_type
+  mat_row(MAT &m, size_type i)
+  { return linalg_traits<MAT>::row(mat_row_begin(m) + i); }
+
+  template <typename MAT> inline
+  typename linalg_traits<MAT>::const_sub_row_type
+  mat_const_row(const MAT &m, size_type i)
+  { return linalg_traits<MAT>::row(mat_row_const_begin(m) + i); }
+
+  template <typename MAT> inline
+  typename select_return<typename linalg_traits<MAT>::const_sub_col_type,
+                         typename linalg_traits<MAT>::sub_col_type,
+                         const MAT *>::return_type
+  mat_col(const MAT &m, size_type i)
+  { return linalg_traits<MAT>::col(mat_col_begin(m) + i); }
+
+
+  template <typename MAT> inline
+  typename select_return<typename linalg_traits<MAT>::const_sub_col_type,
+                         typename linalg_traits<MAT>::sub_col_type,
+                         MAT *>::return_type
+  mat_col(MAT &m, size_type i)
+  { return linalg_traits<MAT>::col(mat_col_begin(m) + i); }
+  
+  template <typename MAT> inline
+  typename linalg_traits<MAT>::const_sub_col_type
+  mat_const_col(const MAT &m, size_type i)
+  { return linalg_traits<MAT>::col(mat_col_const_begin(m) + i); }
+  
+  /* ********************************************************************* */
+  /* Set to begin end set to end for iterators on non-const sparse vectors.*/
+  /* ********************************************************************* */
+
+  template <typename IT, typename ORG, typename VECT> inline
+  void set_to_begin(IT &it, ORG o, VECT *, linalg_false)
+  { it = vect_begin(*o); }
+
+  template <typename IT, typename ORG, typename VECT> inline
+  void set_to_begin(IT &it, ORG o, const VECT *, linalg_false) 
+  { it = vect_const_begin(*o); }
+
+  template <typename IT, typename ORG, typename VECT> inline
+  void set_to_end(IT &it, ORG o, VECT *, linalg_false)
+  { it = vect_end(*o); }
+  
+  template <typename IT, typename ORG, typename VECT> inline
+  void set_to_end(IT &it, ORG o, const VECT *, linalg_false)
+  { it = vect_const_end(*o); }
+
+
+  template <typename IT, typename ORG, typename VECT> inline
+  void set_to_begin(IT &, ORG, VECT *, linalg_const) { }
+
+  template <typename IT, typename ORG, typename VECT> inline
+  void set_to_begin(IT &, ORG, const VECT *, linalg_const) { }
+
+  template <typename IT, typename ORG, typename VECT> inline
+  void set_to_end(IT &, ORG, VECT *, linalg_const) { }
+  
+  template <typename IT, typename ORG, typename VECT> inline
+  void set_to_end(IT &, ORG, const VECT *, linalg_const) { }
+
+
+  template <typename IT, typename ORG, typename VECT> inline
+  void set_to_begin(IT &, ORG, VECT *v, linalg_modifiable)
+  { GMM_ASSERT3(!is_sparse(*v), "internal_error"); v = 0; }
+
+  template <typename IT, typename ORG, typename VECT> inline
+  void set_to_begin(IT &, ORG, const VECT *v, linalg_modifiable)
+  { GMM_ASSERT3(!is_sparse(*v), "internal_error"); v = 0; }
+ 
+  template <typename IT, typename ORG, typename VECT> inline
+  void set_to_end(IT &, ORG, VECT *v, linalg_modifiable)
+  { GMM_ASSERT3(!is_sparse(*v), "internal_error"); v = 0; }
+  
+  template <typename IT, typename ORG, typename VECT> inline
+  void set_to_end(IT &, ORG, const VECT *v, linalg_modifiable)
+  { GMM_ASSERT3(!is_sparse(*v), "internal_error"); v = 0; }
+
+  /* ******************************************************************** */
+  /*		General index for certain algorithms.         		  */
+  /* ******************************************************************** */
+
+  template<class IT> 
+  size_type index_of_it(const IT &it, size_type, abstract_sparse)
+  { return it.index(); }
+  template<class IT> 
+  size_type index_of_it(const IT &it, size_type, abstract_skyline)
+  { return it.index(); }
+  template<class IT> 
+  size_type index_of_it(const IT &, size_type k, abstract_dense)
+  { return k; }
+
+  /* ********************************************************************* */
+  /* Numeric limits.                                                       */
+  /* ********************************************************************* */
+  
+  template<typename T> inline T default_tol(T) {
+    using namespace std;
+    static T tol(10);
+    if (tol == T(10)) {
+      if (numeric_limits<T>::is_specialized)
+	tol = numeric_limits<T>::epsilon();
+      else {
+	int i=sizeof(T)/4; while(i-- > 0) tol*=T(1E-8); 
+	GMM_WARNING1("The numeric type " << typeid(T).name()
+		    << " has no numeric_limits defined !!\n"
+		    << "Taking " << tol << " as default tolerance");
+      }
+    }
+    return tol;
+  }
+  template<typename T> inline T default_tol(std::complex<T>)
+  { return default_tol(T()); }
+
+  template<typename T> inline T default_min(T) {
+    using namespace std;
+    static T mi(10);
+    if (mi == T(10)) {
+      if (numeric_limits<T>::is_specialized)
+	mi = std::numeric_limits<T>::min();
+      else {
+	mi = T(0);
+	GMM_WARNING1("The numeric type " << typeid(T).name()
+		    << " has no numeric_limits defined !!\n"
+		    << "Taking 0 as default minimum");
+      }
+    }
+    return mi;
+  }
+  template<typename T> inline T default_min(std::complex<T>)
+  { return default_min(T()); }
+
+  template<typename T> inline T default_max(T) {
+    using namespace std;
+    static T mi(10);
+    if (mi == T(10)) {
+      if (numeric_limits<T>::is_specialized)
+	mi = std::numeric_limits<T>::max();
+      else {
+	mi = T(1);
+	GMM_WARNING1("The numeric type " << typeid(T).name()
+		    << " has no numeric_limits defined !!\n"
+		    << "Taking 1 as default maximum !");
+      }
+    }
+    return mi;
+  }
+  template<typename T> inline T default_max(std::complex<T>)
+  { return default_max(T()); }
+
+  
+  /*
+    use safe_divide to avoid NaNs when dividing very small complex
+    numbers, for example
+    std::complex<float>(1e-23,1e-30)/std::complex<float>(1e-23,1e-30)
+  */
+  template<typename T> inline T safe_divide(T a, T b) { return a/b; }
+  template<typename T> inline std::complex<T>
+  safe_divide(std::complex<T> a, std::complex<T> b) {
+    T m = std::max(gmm::abs(b.real()), gmm::abs(b.imag()));
+    a = std::complex<T>(a.real()/m, a.imag()/m);
+    b = std::complex<T>(b.real()/m, b.imag()/m);
+    return a / b;
+  }
+
+
+  /* ******************************************************************** */
+  /*		Write                                   		  */
+  /* ******************************************************************** */
+
+  template <typename T> struct cast_char_type { typedef T return_type; };
+  template <> struct cast_char_type<signed char> { typedef int return_type; };
+  template <> struct cast_char_type<unsigned char>
+  { typedef unsigned int return_type; };
+  template <typename T> inline typename cast_char_type<T>::return_type
+  cast_char(const T &c) { return typename cast_char_type<T>::return_type(c); }
+
+
+  template <typename L> inline void write(std::ostream &o, const L &l)
+  { write(o, l, typename linalg_traits<L>::linalg_type()); }
+
+  template <typename L> void write(std::ostream &o, const L &l,
+				       abstract_vector) {
+    o << "vector(" << vect_size(l) << ") [";
+    write(o, l, typename linalg_traits<L>::storage_type());
+    o << " ]";
+  }
+
+  template <typename L> void write(std::ostream &o, const L &l,
+				       abstract_sparse) {
+    typename linalg_traits<L>::const_iterator it = vect_const_begin(l),
+      ite = vect_const_end(l);
+    for (; it != ite; ++it) 
+      o << " (r" << it.index() << "," << cast_char(*it) << ")";
+  }
+
+  template <typename L> void write(std::ostream &o, const L &l,
+				       abstract_dense) {
+    typename linalg_traits<L>::const_iterator it = vect_const_begin(l),
+      ite = vect_const_end(l);
+    if (it != ite) o << " " << cast_char(*it++);
+    for (; it != ite; ++it) o << ", " << cast_char(*it);
+  }
+
+  template <typename L> void write(std::ostream &o, const L &l,
+				       abstract_skyline) {
+    typedef typename linalg_traits<L>::const_iterator const_iterator;
+    const_iterator it = vect_const_begin(l), ite = vect_const_end(l);
+    if (it != ite) {
+      o << "<r+" << it.index() << ">";
+      if (it != ite) o << " " << cast_char(*it++);
+      for (; it != ite; ++it) { o << ", " << cast_char(*it); }
+    }
+  }
+
+  template <typename L> inline void write(std::ostream &o, const L &l,
+				       abstract_matrix) {
+    write(o, l, typename linalg_traits<L>::sub_orientation());
+  }
+
+
+  template <typename L> void write(std::ostream &o, const L &l,
+				       row_major) {
+    o << "matrix(" << mat_nrows(l) << ", " << mat_ncols(l) << ")" << endl;
+    for (size_type i = 0; i < mat_nrows(l); ++i) {
+      o << "(";
+      write(o, mat_const_row(l, i), typename linalg_traits<L>::storage_type());
+      o << " )\n";
+    }
+  }
+
+  template <typename L> inline
+  void write(std::ostream &o, const L &l, row_and_col) 
+  { write(o, l, row_major()); }
+
+  template <typename L> inline
+  void write(std::ostream &o, const L &l, col_and_row)
+  { write(o, l, row_major()); }
+
+  template <typename L> void write(std::ostream &o, const L &l, col_major) {
+    o << "matrix(" << mat_nrows(l) << ", " << mat_ncols(l) << ")" << endl;
+    for (size_type i = 0; i < mat_nrows(l); ++i) {
+      o << "(";
+      if (is_sparse(l)) { // not optimized ...
+	for (size_type j = 0; j < mat_ncols(l); ++j)
+	  if (l(i,j) != typename linalg_traits<L>::value_type(0)) 
+	    o << " (r" << j << ", " << l(i,j) << ")";
+      }
+      else {
+	if (mat_ncols(l) != 0) o << ' ' << l(i, 0);
+	for (size_type j = 1; j < mat_ncols(l); ++j) o << ", " << l(i, j); 
+      }
+      o << " )\n";
+    }
+  }
+
+}
+
+#endif //  GMM_DEF_H__
diff --git a/Contrib/gmm/gmm_dense_Householder.h b/Contrib/gmm/gmm_dense_Householder.h
new file mode 100755
index 0000000..9e34c1a
--- /dev/null
+++ b/Contrib/gmm/gmm_dense_Householder.h
@@ -0,0 +1,316 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_dense_Householder.h
+   @author Caroline Lecalvez <Caroline.Lecalvez at gmm.insa-toulouse.fr>
+   @author Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date June 5, 2003.
+   @brief Householder for dense matrices.
+*/
+
+#ifndef GMM_DENSE_HOUSEHOLDER_H
+#define GMM_DENSE_HOUSEHOLDER_H
+
+#include "gmm_kernel.h"
+
+namespace gmm {
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+  /* ********************************************************************* */
+  /*    Rank one update  (complex and real version)                        */
+  /* ********************************************************************* */
+
+  template <typename Matrix, typename VecX, typename VecY>
+  inline void rank_one_update(Matrix &A, const VecX& x,
+			      const VecY& y, row_major) {
+    typedef typename linalg_traits<Matrix>::value_type T;
+    size_type N = mat_nrows(A);
+    GMM_ASSERT2(N <= vect_size(x) && mat_ncols(A) <= vect_size(y),
+	       "dimensions mismatch");
+    typename linalg_traits<VecX>::const_iterator itx = vect_const_begin(x);
+    for (size_type i = 0; i < N; ++i, ++itx) {
+      typedef typename linalg_traits<Matrix>::sub_row_type row_type;
+      row_type row = mat_row(A, i);
+      typename linalg_traits<row_type>::iterator
+	it = vect_begin(row), ite = vect_end(row);
+      typename linalg_traits<VecY>::const_iterator ity = vect_const_begin(y);
+      T tx = *itx;
+      for (; it != ite; ++it, ++ity) *it += conj_product(*ity, tx);
+    }
+  }
+
+  template <typename Matrix, typename VecX, typename VecY>
+  inline void rank_one_update(Matrix &A, const VecX& x,
+			      const VecY& y, col_major) {
+    typedef typename linalg_traits<Matrix>::value_type T;
+    size_type M = mat_ncols(A);
+    GMM_ASSERT2(mat_nrows(A) <= vect_size(x) && M <= vect_size(y),
+		"dimensions mismatch");
+    typename linalg_traits<VecY>::const_iterator ity = vect_const_begin(y);
+    for (size_type i = 0; i < M; ++i, ++ity) {
+      typedef typename linalg_traits<Matrix>::sub_col_type col_type;
+      col_type col = mat_col(A, i);
+      typename linalg_traits<col_type>::iterator
+	it = vect_begin(col), ite = vect_end(col);
+      typename linalg_traits<VecX>::const_iterator itx = vect_const_begin(x);
+      T ty = *ity;
+      for (; it != ite; ++it, ++itx) *it += conj_product(ty, *itx);
+    }
+  }
+  
+  ///@endcond
+  template <typename Matrix, typename VecX, typename VecY>
+  inline void rank_one_update(const Matrix &AA, const VecX& x,
+			      const VecY& y) {
+    Matrix& A = const_cast<Matrix&>(AA);
+    rank_one_update(A, x, y, typename principal_orientation_type<typename
+		    linalg_traits<Matrix>::sub_orientation>::potype());
+  }
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+  /* ********************************************************************* */
+  /*    Rank two update  (complex and real version)                        */
+  /* ********************************************************************* */
+
+  template <typename Matrix, typename VecX, typename VecY>
+  inline void rank_two_update(Matrix &A, const VecX& x,
+			      const VecY& y, row_major) {
+    typedef typename linalg_traits<Matrix>::value_type value_type;
+    size_type N = mat_nrows(A);
+    GMM_ASSERT2(N <= vect_size(x) && mat_ncols(A) <= vect_size(y),
+		"dimensions mismatch");
+    typename linalg_traits<VecX>::const_iterator itx1 = vect_const_begin(x);
+    typename linalg_traits<VecY>::const_iterator ity2 = vect_const_begin(y);
+    for (size_type i = 0; i < N; ++i, ++itx1, ++ity2) {
+      typedef typename linalg_traits<Matrix>::sub_row_type row_type;
+      row_type row = mat_row(A, i);
+      typename linalg_traits<row_type>::iterator
+	it = vect_begin(row), ite = vect_end(row);
+      typename linalg_traits<VecX>::const_iterator itx2 = vect_const_begin(x);
+      typename linalg_traits<VecY>::const_iterator ity1 = vect_const_begin(y);
+      value_type tx = *itx1, ty = *ity2;
+      for (; it != ite; ++it, ++ity1, ++itx2)
+	*it += conj_product(*ity1, tx) + conj_product(*itx2, ty);
+    }
+  }
+
+  template <typename Matrix, typename VecX, typename VecY>
+  inline void rank_two_update(Matrix &A, const VecX& x,
+			      const VecY& y, col_major) {
+    typedef typename linalg_traits<Matrix>::value_type value_type;
+    size_type M = mat_ncols(A);
+    GMM_ASSERT2(mat_nrows(A) <= vect_size(x) && M <= vect_size(y),
+		"dimensions mismatch");
+    typename linalg_traits<VecX>::const_iterator itx2 = vect_const_begin(x);
+    typename linalg_traits<VecY>::const_iterator ity1 = vect_const_begin(y);
+    for (size_type i = 0; i < M; ++i, ++ity1, ++itx2) {
+      typedef typename linalg_traits<Matrix>::sub_col_type col_type;
+      col_type col = mat_col(A, i);
+      typename linalg_traits<col_type>::iterator
+	it = vect_begin(col), ite = vect_end(col);
+      typename linalg_traits<VecX>::const_iterator itx1 = vect_const_begin(x);
+      typename linalg_traits<VecY>::const_iterator ity2 = vect_const_begin(y);
+      value_type ty = *ity1, tx = *itx2;
+      for (; it != ite; ++it, ++itx1, ++ity2)
+	*it += conj_product(ty, *itx1) + conj_product(tx, *ity2); 
+    }
+  }
+  
+  ///@endcond
+  template <typename Matrix, typename VecX, typename VecY>
+  inline void rank_two_update(const Matrix &AA, const VecX& x,
+			      const VecY& y) {
+    Matrix& A = const_cast<Matrix&>(AA);
+    rank_two_update(A, x, y, typename principal_orientation_type<typename
+		    linalg_traits<Matrix>::sub_orientation>::potype());
+  }
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+
+  /* ********************************************************************* */
+  /*    Householder vector computation (complex and real version)          */
+  /* ********************************************************************* */
+
+  template <typename VECT> void house_vector(const VECT &VV) {
+    VECT &V = const_cast<VECT &>(VV);
+    typedef typename linalg_traits<VECT>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+    
+    R mu = vect_norm2(V), abs_v0 = gmm::abs(V[0]);
+    if (mu != R(0))
+      gmm::scale(V, (abs_v0 == R(0)) ? T(R(1) / mu)
+		 : (safe_divide(T(abs_v0), V[0]) / (abs_v0 + mu)));
+    if (gmm::real(V[vect_size(V)-1]) * R(0) != R(0)) gmm::clear(V);
+    V[0] = T(1);
+  }
+
+  template <typename VECT> void house_vector_last(const VECT &VV) {
+    VECT &V = const_cast<VECT &>(VV);
+    typedef typename linalg_traits<VECT>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+
+    size_type m = vect_size(V);
+    R mu = vect_norm2(V), abs_v0 = gmm::abs(V[m-1]);
+    if (mu != R(0))
+      gmm::scale(V, (abs_v0 == R(0)) ? T(R(1) / mu)
+		 : ((abs_v0 / V[m-1]) / (abs_v0 + mu)));
+    if (gmm::real(V[0]) * R(0) != R(0)) gmm::clear(V);
+    V[m-1] = T(1);
+  }
+  
+  /* ********************************************************************* */
+  /*    Householder updates  (complex and real version)                    */
+  /* ********************************************************************* */
+
+  // multiply A to the left by the reflector stored in V. W is a temporary.
+  template <typename MAT, typename VECT1, typename VECT2> inline
+    void row_house_update(const MAT &AA, const VECT1 &V, const VECT2 &WW) {
+    VECT2 &W = const_cast<VECT2 &>(WW); MAT &A = const_cast<MAT &>(AA);
+    typedef typename linalg_traits<MAT>::value_type value_type;
+    typedef typename number_traits<value_type>::magnitude_type magnitude_type;
+
+    gmm::mult(conjugated(A),
+	      scaled(V, value_type(magnitude_type(-2)/vect_norm2_sqr(V))), W);
+    rank_one_update(A, V, W);
+  }
+
+  // multiply A to the right by the reflector stored in V. W is a temporary.
+  template <typename MAT, typename VECT1, typename VECT2> inline
+    void col_house_update(const MAT &AA, const VECT1 &V, const VECT2 &WW) {
+    VECT2 &W = const_cast<VECT2 &>(WW); MAT &A = const_cast<MAT &>(AA);
+    typedef typename linalg_traits<MAT>::value_type value_type;
+    typedef typename number_traits<value_type>::magnitude_type magnitude_type;
+    
+    gmm::mult(A,
+	      scaled(V, value_type(magnitude_type(-2)/vect_norm2_sqr(V))), W);
+    rank_one_update(A, W, V);
+  }
+
+  ///@endcond
+
+  /* ********************************************************************* */
+  /*    Hessemberg reduction with Householder.                             */
+  /* ********************************************************************* */
+
+  template <typename MAT1, typename MAT2>
+    void Hessenberg_reduction(const MAT1& AA, const MAT2 &QQ, bool compute_Q){
+    MAT1& A = const_cast<MAT1&>(AA); MAT2& Q = const_cast<MAT2&>(QQ);
+    typedef typename linalg_traits<MAT1>::value_type value_type;
+    if (compute_Q) gmm::copy(identity_matrix(), Q);
+    size_type n = mat_nrows(A); if (n < 2) return;
+    std::vector<value_type> v(n), w(n);
+    sub_interval SUBK(0,n);
+    for (size_type k = 1; k+1 < n; ++k) {
+      sub_interval SUBI(k, n-k), SUBJ(k-1,n-k+1);
+      v.resize(n-k);
+      for (size_type j = k; j < n; ++j) v[j-k] = A(j, k-1);
+      house_vector(v);
+      row_house_update(sub_matrix(A, SUBI, SUBJ), v, sub_vector(w, SUBJ));
+      col_house_update(sub_matrix(A, SUBK, SUBI), v, w);
+      // is it possible to "unify" the two on the common part of the matrix?
+      if (compute_Q) col_house_update(sub_matrix(Q, SUBK, SUBI), v, w);
+    }
+  }
+
+  /* ********************************************************************* */
+  /*    Householder tridiagonalization for symmetric matrices              */
+  /* ********************************************************************* */
+
+  template <typename MAT1, typename MAT2> 
+  void Householder_tridiagonalization(const MAT1 &AA, const MAT2 &QQ,
+				     bool compute_q) {
+    MAT1 &A = const_cast<MAT1 &>(AA); MAT2 &Q = const_cast<MAT2 &>(QQ);
+    typedef typename linalg_traits<MAT1>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+
+    size_type n = mat_nrows(A); if (n < 2) return;
+    std::vector<T> v(n), p(n), w(n), ww(n);
+    sub_interval SUBK(0,n);
+
+    for (size_type k = 1; k+1 < n; ++k) { // not optimized ...
+      sub_interval SUBI(k, n-k);
+      v.resize(n-k); p.resize(n-k); w.resize(n-k); 
+      for (size_type l = k; l < n; ++l) 
+	{ v[l-k] = w[l-k] = A(l, k-1); A(l, k-1) = A(k-1, l) = T(0); }
+      house_vector(v);
+      R norm = vect_norm2_sqr(v);
+      A(k-1, k) = gmm::conj(A(k, k-1) = w[0] - T(2)*v[0]*vect_hp(w, v)/norm);
+
+      gmm::mult(sub_matrix(A, SUBI), gmm::scaled(v, T(-2) / norm), p);
+      gmm::add(p, gmm::scaled(v, -vect_hp(v, p) / norm), w);
+      rank_two_update(sub_matrix(A, SUBI), v, w);
+      // it should be possible to compute only the upper or lower part
+
+      if (compute_q) col_house_update(sub_matrix(Q, SUBK, SUBI), v, ww);
+    }
+  }
+
+  /* ********************************************************************* */
+  /*    Real and complex Givens rotations                                  */
+  /* ********************************************************************* */
+
+  template <typename T> void Givens_rotation(T a, T b, T &c, T &s) {
+    typedef typename number_traits<T>::magnitude_type R;
+    R aa = gmm::abs(a), bb = gmm::abs(b);
+    if (bb == R(0)) { c = T(1); s = T(0);   return; }
+    if (aa == R(0)) { c = T(0); s = b / bb; return; }
+    if (bb > aa)
+      { T t = -safe_divide(a,b); s = T(R(1) / (sqrt(R(1)+gmm::abs_sqr(t)))); c = s * t; }
+    else
+      { T t = -safe_divide(b,a); c = T(R(1) / (sqrt(R(1)+gmm::abs_sqr(t)))); s = c * t; }
+  }
+
+  // Apply Q* v
+  template <typename T> inline
+  void Apply_Givens_rotation_left(T &x, T &y, T c, T s)
+  { T t1=x, t2=y; x = gmm::conj(c)*t1 - gmm::conj(s)*t2; y = c*t2 + s*t1; }
+
+  // Apply v^T Q
+  template <typename T> inline
+  void Apply_Givens_rotation_right(T &x, T &y, T c, T s)
+  { T t1=x, t2=y; x = c*t1 - s*t2; y = gmm::conj(c)*t2 + gmm::conj(s)*t1; }
+
+  template <typename MAT, typename T>
+  void row_rot(const MAT &AA, T c, T s, size_type i, size_type k) {
+    MAT &A = const_cast<MAT &>(AA); // can be specialized for row matrices
+    for (size_type j = 0; j < mat_ncols(A); ++j)
+      Apply_Givens_rotation_left(A(i,j), A(k,j), c, s);
+  }
+
+  template <typename MAT, typename T>
+  void col_rot(const MAT &AA, T c, T s, size_type i, size_type k) {
+    MAT &A = const_cast<MAT &>(AA); // can be specialized for column matrices
+    for (size_type j = 0; j < mat_nrows(A); ++j)
+      Apply_Givens_rotation_right(A(j,i), A(j,k), c, s);
+  }
+  
+}
+
+#endif
+
diff --git a/Contrib/gmm/gmm_dense_lu.h b/Contrib/gmm/gmm_dense_lu.h
new file mode 100755
index 0000000..23ca9b8
--- /dev/null
+++ b/Contrib/gmm/gmm_dense_lu.h
@@ -0,0 +1,275 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+// This file is a modified version of lu.h from MTL.
+// See http://osl.iu.edu/research/mtl/
+// Following the corresponding Copyright notice.
+//===========================================================================
+// Copyright (c) 2001-2003 The Trustees of Indiana University.
+// All rights reserved.
+// Copyright (c) 1998-2001 University of Notre Dame. All rights reserved.
+// Authors: Andrew Lumsdaine, Jeremy G. Siek, Lie-Quan Lee
+//
+// This file is part of the Matrix Template Library
+//
+// Indiana University has the exclusive rights to license this product under
+// the following license.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//   1.  All redistributions of source code must retain the above  copyright
+//       notice, the list of authors in the original source code,  this list
+//       of conditions and the disclaimer listed in this license;
+//   2.  All redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the disclaimer listed
+//       in this license in the documentation and/or other materials provided
+//       with the distribution;
+//   3.  Any documentation included with all redistributions must include the
+//       following acknowledgement:
+//	"This product includes software developed at the University of
+//       Notre Dame and the Pervasive Technology Labs at Indiana University.
+//       For technical information contact Andrew Lumsdaine at the Pervasive
+//       Technology Labs at Indiana University. 
+//	 For administrative and license questions contact the Advanced
+//       Research and Technology Institute at 1100 Waterway Blvd.
+//       Indianapolis, Indiana 46202, phone 317-274-5905, fax  317-274-5902."
+//	 Alternatively, this acknowledgement may appear in the software
+//       itself, and wherever such third-party acknowledgments normally appear.
+//   4.  The name "MTL" shall not be used to endorse or promote  products
+//       derived from this software without prior written  permission from
+//       Indiana University. For written permission, please  contact Indiana
+//       University Advanced Research & Technology  Institute.
+//   5.  Products derived from this software may not be called "MTL", nor
+//       may "MTL" appear in their name, without  prior written permission
+//       of Indiana University Advanced Research & Technology Institute.
+//
+// Indiana University provides no reassurances that the source code provided
+// does not infringe the patent or any other intellectual property rights of
+// any other entity. Indiana University disclaims any liability to any
+// recipient for claims brought by any other entity based on infringement of 
+// intellectual property rights or otherwise.
+//
+// LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO
+// WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY
+// GIVES NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF
+// INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
+// INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS",
+// "VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.
+// LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR
+// ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF 
+// INFORMATION GENERATED USING SOFTWARE.
+//===========================================================================
+
+/**@file gmm_dense_lu.h
+   @author  Andrew Lumsdaine, Jeremy G. Siek, Lie-Quan Lee, Y. Renard
+   @date June 5, 2003.
+   @brief LU factorizations and determinant computation for dense matrices.
+*/
+#ifndef GMM_DENSE_LU_H
+#define GMM_DENSE_LU_H
+
+#include "gmm_dense_Householder.h"
+#include "gmm_opt.h"
+
+namespace gmm {
+
+
+  /** LU Factorization of a general (dense) matrix (real or complex).
+  
+  This is the outer product (a level-2 operation) form of the LU
+  Factorization with pivoting algorithm . This is equivalent to
+  LAPACK's dgetf2. Also see "Matrix Computations" 3rd Ed.  by Golub
+  and Van Loan section 3.2.5 and especially page 115.
+  
+  The pivot indices in ipvt are indexed starting from 1
+  so that this is compatible with LAPACK (Fortran).
+  */
+  template <typename DenseMatrix, typename Pvector>
+  size_type lu_factor(DenseMatrix& A, Pvector& ipvt) {
+    typedef typename linalg_traits<DenseMatrix>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+    size_type info(0), i, j, jp, M(mat_nrows(A)), N(mat_ncols(A));
+    size_type NN = std::min(M, N);
+    std::vector<T> c(M), r(N);
+    
+    GMM_ASSERT2(ipvt.size()+1 >= NN, "IPVT too small");
+    for (i = 0; i+1 < NN; ++i) ipvt[i] = i;
+      
+    if (M || N) {
+      for (j = 0; j+1 < NN; ++j) {
+	R max = gmm::abs(A(j,j)); jp = j;
+	for (i = j+1; i < M; ++i)		   /* find pivot.          */
+	  if (gmm::abs(A(i,j)) > max) { jp = i; max = gmm::abs(A(i,j)); }
+	ipvt[j] = jp + 1;
+	
+	if (max == R(0)) { info = j + 1; break; }
+        if (jp != j) for (i = 0; i < N; ++i) std::swap(A(jp, i), A(j, i));
+	
+        for (i = j+1; i < M; ++i) { A(i, j) /= A(j,j); c[i-j-1] = -A(i, j); }
+        for (i = j+1; i < N; ++i) r[i-j-1] = A(j, i);  // avoid the copy ?
+	rank_one_update(sub_matrix(A, sub_interval(j+1, M-j-1),
+				 sub_interval(j+1, N-j-1)), c, conjugated(r));
+      }
+      ipvt[j] = j + 1;
+    }
+    return info;
+  }
+  
+  /** LU Solve : Solve equation Ax=b, given an LU factored matrix.*/
+  //  Thanks to Valient Gough for this routine!
+  template <typename DenseMatrix, typename VectorB, typename VectorX,
+	    typename Pvector>
+  void lu_solve(const DenseMatrix &LU, const Pvector& pvector, 
+		VectorX &x, const VectorB &b) {
+    typedef typename linalg_traits<DenseMatrix>::value_type T;
+    copy(b, x);
+    for(size_type i = 0; i < pvector.size(); ++i) {
+      size_type perm = pvector[i]-1;     // permutations stored in 1's offset
+      if(i != perm) { T aux = x[i]; x[i] = x[perm]; x[perm] = aux; }
+    }
+    /* solve  Ax = b  ->  LUx = b  ->  Ux = L^-1 b.                        */
+    lower_tri_solve(LU, x, true);
+    upper_tri_solve(LU, x, false);
+  }
+
+  template <typename DenseMatrix, typename VectorB, typename VectorX>
+  void lu_solve(const DenseMatrix &A, VectorX &x, const VectorB &b) {
+    typedef typename linalg_traits<DenseMatrix>::value_type T;
+    dense_matrix<T> B(mat_nrows(A), mat_ncols(A));
+    std::vector<int> ipvt(mat_nrows(A));
+    gmm::copy(A, B);
+    size_type info = lu_factor(B, ipvt);
+    GMM_ASSERT1(!info, "Singular system, pivot = " << info);
+    lu_solve(B, ipvt, x, b);
+  }
+  
+  template <typename DenseMatrix, typename VectorB, typename VectorX,
+	    typename Pvector>
+  void lu_solve_transposed(const DenseMatrix &LU, const Pvector& pvector, 
+			   VectorX &x, const VectorB &b) {
+    typedef typename linalg_traits<DenseMatrix>::value_type T;
+    copy(b, x);
+    lower_tri_solve(transposed(LU), x, false);
+    upper_tri_solve(transposed(LU), x, true);
+    for(size_type i = pvector.size(); i > 0; --i) {
+      size_type perm = pvector[i-1]-1;    // permutations stored in 1's offset
+      if(i-1 != perm) { T aux = x[i-1]; x[i-1] = x[perm]; x[perm] = aux; }
+    }
+
+  }
+
+
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+  template <typename DenseMatrixLU, typename DenseMatrix, typename Pvector>
+  void lu_inverse(const DenseMatrixLU& LU, const Pvector& pvector,
+		  DenseMatrix& AInv, col_major) {
+    typedef typename linalg_traits<DenseMatrixLU>::value_type T;
+    std::vector<T> tmp(pvector.size(), T(0));
+    std::vector<T> result(pvector.size());
+    for(size_type i = 0; i < pvector.size(); ++i) {
+      tmp[i] = T(1);
+      lu_solve(LU, pvector, result, tmp);
+      copy(result, mat_col(AInv, i));
+      tmp[i] = T(0);
+    }
+  }
+
+  template <typename DenseMatrixLU, typename DenseMatrix, typename Pvector>
+  void lu_inverse(const DenseMatrixLU& LU, const Pvector& pvector,
+		  DenseMatrix& AInv, row_major) {
+    typedef typename linalg_traits<DenseMatrixLU>::value_type T;
+    std::vector<T> tmp(pvector.size(), T(0));
+    std::vector<T> result(pvector.size());
+    for(size_type i = 0; i < pvector.size(); ++i) {
+      tmp[i] = T(1); // to be optimized !!
+      // on peut sur le premier tri solve reduire le systeme
+      // et peut etre faire un solve sur une serie de vecteurs au lieu
+      // de vecteur a vecteur (accumulation directe de l'inverse dans la
+      // matrice au fur et a mesure du calcul ... -> evite la copie finale
+      lu_solve_transposed(LU, pvector, result, tmp);
+      copy(result, mat_row(AInv, i));
+      tmp[i] = T(0);
+    }
+  }
+  ///@endcond  
+
+  /** Given an LU factored matrix, build the inverse of the matrix. */
+  template <typename DenseMatrixLU, typename DenseMatrix, typename Pvector>
+  void lu_inverse(const DenseMatrixLU& LU, const Pvector& pvector,
+		  const DenseMatrix& AInv_) {
+    DenseMatrix& AInv = const_cast<DenseMatrix&>(AInv_);
+    lu_inverse(LU, pvector, AInv, typename principal_orientation_type<typename
+	       linalg_traits<DenseMatrix>::sub_orientation>::potype());
+  }
+
+  /** Given a dense matrix, build the inverse of the matrix, and
+      return the determinant */
+  template <typename DenseMatrix>
+  typename linalg_traits<DenseMatrix>::value_type
+  lu_inverse(const DenseMatrix& A_) {
+    typedef typename linalg_traits<DenseMatrix>::value_type T;
+    DenseMatrix& A = const_cast<DenseMatrix&>(A_);
+    dense_matrix<T> B(mat_nrows(A), mat_ncols(A));
+    std::vector<int> ipvt(mat_nrows(A));
+    gmm::copy(A, B);
+    size_type info = lu_factor(B, ipvt);
+    GMM_ASSERT1(!info, "Non invertible matrix, pivot = " << info);
+    lu_inverse(B, ipvt, A);
+    return lu_det(B, ipvt);
+  }
+
+  /** Compute the matrix determinant (via a LU factorization) */
+  template <typename DenseMatrixLU, typename Pvector>
+  typename linalg_traits<DenseMatrixLU>::value_type
+  lu_det(const DenseMatrixLU& LU, const Pvector &pvector) {
+    typedef typename linalg_traits<DenseMatrixLU>::value_type T;
+    T det(1);
+    for (size_type j = 0; j < std::min(mat_nrows(LU), mat_ncols(LU)); ++j)
+      det *= LU(j,j);
+    for(size_type i = 0; i < pvector.size(); ++i)
+      if (i != size_type(pvector[i]-1)) { det = -det; }
+    return det;
+  }
+
+  template <typename DenseMatrix>
+  typename linalg_traits<DenseMatrix>::value_type
+  lu_det(const DenseMatrix& A) {
+    typedef typename linalg_traits<DenseMatrix>::value_type T;
+    dense_matrix<T> B(mat_nrows(A), mat_ncols(A));
+    std::vector<int> ipvt(mat_nrows(A));
+    gmm::copy(A, B);
+    lu_factor(B, ipvt);
+    return lu_det(B, ipvt);
+  }
+
+}
+
+#endif
+
diff --git a/Contrib/gmm/gmm_dense_qr.h b/Contrib/gmm/gmm_dense_qr.h
new file mode 100755
index 0000000..d9effa2
--- /dev/null
+++ b/Contrib/gmm/gmm_dense_qr.h
@@ -0,0 +1,788 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_dense_qr.h
+   @author  Caroline Lecalvez, Caroline.Lecalvez at gmm.insa-tlse.fr, Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date September 12, 2003.
+   @brief Dense QR factorization.
+*/
+#ifndef GMM_DENSE_QR_H
+#define GMM_DENSE_QR_H
+
+#include "gmm_dense_Householder.h"
+
+namespace gmm {
+
+
+  /**
+     QR factorization using Householder method (complex and real version).
+  */
+  template <typename MAT1>
+  void qr_factor(const MAT1 &A_) { 
+    MAT1 &A = const_cast<MAT1 &>(A_);
+    typedef typename linalg_traits<MAT1>::value_type value_type;
+
+    size_type m = mat_nrows(A), n = mat_ncols(A);
+    GMM_ASSERT2(m >= n, "dimensions mismatch");
+
+    std::vector<value_type> W(m), V(m);
+
+    for (size_type j = 0; j < n; ++j) {
+      sub_interval SUBI(j, m-j), SUBJ(j, n-j);
+      V.resize(m-j); W.resize(n-j);
+
+      for (size_type i = j; i < m; ++i) V[i-j] = A(i, j);
+      house_vector(V);
+
+      row_house_update(sub_matrix(A, SUBI, SUBJ), V, W);
+      for (size_type i = j+1; i < m; ++i) A(i, j) = V[i-j];
+    }
+  }
+
+  
+  // QR comes from QR_factor(QR) where the upper triangular part stands for R
+  // and the lower part contains the Householder reflectors.
+  // A <- AQ
+  template <typename MAT1, typename MAT2>
+  void apply_house_right(const MAT1 &QR, const MAT2 &A_) { 
+    MAT2 &A = const_cast<MAT2 &>(A_);
+    typedef typename linalg_traits<MAT1>::value_type T;
+    size_type m = mat_nrows(QR), n = mat_ncols(QR);
+    GMM_ASSERT2(m == mat_ncols(A), "dimensions mismatch");
+    if (m == 0) return;
+    std::vector<T> V(m), W(mat_nrows(A));
+    V[0] = T(1);
+    for (size_type j = 0; j < n; ++j) {
+      V.resize(m-j);
+      for (size_type i = j+1; i < m; ++i) V[i-j] = QR(i, j);
+      col_house_update(sub_matrix(A, sub_interval(0, mat_nrows(A)),
+				  sub_interval(j, m-j)), V, W);
+    }
+  }
+
+  // QR comes from QR_factor(QR) where the upper triangular part stands for R
+  // and the lower part contains the Householder reflectors.
+  // A <- Q*A
+  template <typename MAT1, typename MAT2>
+  void apply_house_left(const MAT1 &QR, const MAT2 &A_) { 
+    MAT2 &A = const_cast<MAT2 &>(A_);
+    typedef typename linalg_traits<MAT1>::value_type T;
+    size_type m = mat_nrows(QR), n = mat_ncols(QR);
+    GMM_ASSERT2(m == mat_nrows(A), "dimensions mismatch");
+    if (m == 0) return;
+    std::vector<T> V(m), W(mat_ncols(A));
+    V[0] = T(1);
+    for (size_type j = 0; j < n; ++j) {
+      V.resize(m-j);
+      for (size_type i = j+1; i < m; ++i) V[i-j] = QR(i, j);
+      row_house_update(sub_matrix(A, sub_interval(j, m-j),
+				  sub_interval(0, mat_ncols(A))), V, W);
+    }
+  }  
+
+  /** Compute the QR factorization, where Q is assembled. */
+  template <typename MAT1, typename MAT2, typename MAT3>
+    void qr_factor(const MAT1 &A, const MAT2 &QQ, const MAT3 &RR) { 
+    MAT2 &Q = const_cast<MAT2 &>(QQ); MAT3 &R = const_cast<MAT3 &>(RR); 
+    typedef typename linalg_traits<MAT1>::value_type value_type;
+
+    size_type m = mat_nrows(A), n = mat_ncols(A);
+    GMM_ASSERT2(m >= n, "dimensions mismatch");
+    gmm::copy(A, Q);
+    
+    std::vector<value_type> W(m);
+    dense_matrix<value_type> VV(m, n);
+
+    for (size_type j = 0; j < n; ++j) {
+      sub_interval SUBI(j, m-j), SUBJ(j, n-j);
+
+      for (size_type i = j; i < m; ++i) VV(i,j) = Q(i, j);
+      house_vector(sub_vector(mat_col(VV,j), SUBI));
+
+      row_house_update(sub_matrix(Q, SUBI, SUBJ),
+		       sub_vector(mat_col(VV,j), SUBI), sub_vector(W, SUBJ));
+    }
+
+    gmm::copy(sub_matrix(Q, sub_interval(0, n), sub_interval(0, n)), R);
+    gmm::copy(identity_matrix(), Q);
+    
+    for (size_type j = n-1; j != size_type(-1); --j) {
+      sub_interval SUBI(j, m-j), SUBJ(j, n-j);
+      row_house_update(sub_matrix(Q, SUBI, SUBJ), 
+		       sub_vector(mat_col(VV,j), SUBI), sub_vector(W, SUBJ));
+    }
+  }
+
+  ///@cond DOXY_SHOW_ALL_FUNCTIONS
+  template <typename TA, typename TV, typename Ttol, 
+	    typename MAT, typename VECT>
+  void extract_eig(const MAT &A, VECT &V, Ttol tol, TA, TV) {
+    size_type n = mat_nrows(A);
+    if (n == 0) return;
+    tol *= Ttol(2);
+    Ttol tol_i = tol * gmm::abs(A(0,0)), tol_cplx = tol_i;
+    for (size_type i = 0; i < n; ++i) {
+      if (i < n-1) {
+	tol_i = (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol;
+	tol_cplx = std::max(tol_cplx, tol_i);
+      }
+      if ((i < n-1) && gmm::abs(A(i+1,i)) >= tol_i) {
+	TA tr = A(i,i) + A(i+1, i+1);
+	TA det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
+	TA delta = tr*tr - TA(4) * det;
+	if (delta < -tol_cplx) {
+	  GMM_WARNING1("A complex eigenvalue has been detected : "
+		      << std::complex<TA>(tr/TA(2), gmm::sqrt(-delta)/TA(2)));
+	  V[i] = V[i+1] = tr / TA(2);
+	}
+	else {
+	  delta = std::max(TA(0), delta);
+	  V[i  ] = TA(tr + gmm::sqrt(delta))/ TA(2);
+	  V[i+1] = TA(tr -  gmm::sqrt(delta))/ TA(2);
+	}
+	++i;
+      }
+      else
+	V[i] = TV(A(i,i));
+    }
+  }
+
+  template <typename TA, typename TV, typename Ttol, 
+	    typename MAT, typename VECT>
+  void extract_eig(const MAT &A, VECT &V, Ttol tol, TA, std::complex<TV>) {
+    size_type n = mat_nrows(A);
+    tol *= Ttol(2);
+    for (size_type i = 0; i < n; ++i)
+      if ((i == n-1) ||
+	  gmm::abs(A(i+1,i)) < (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol)
+	V[i] = std::complex<TV>(A(i,i));
+      else {
+	TA tr = A(i,i) + A(i+1, i+1);
+	TA det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
+	TA delta = tr*tr - TA(4) * det;
+	if (delta < TA(0)) {
+	  V[i] = std::complex<TV>(tr / TA(2), gmm::sqrt(-delta) / TA(2));
+	  V[i+1] = std::complex<TV>(tr / TA(2), -gmm::sqrt(-delta)/ TA(2));
+	}
+	else {
+	  V[i  ] = TA(tr + gmm::sqrt(delta)) / TA(2);
+	  V[i+1] = TA(tr -  gmm::sqrt(delta)) / TA(2);
+	}
+	++i;
+      }
+  }
+
+  template <typename TA, typename TV, typename Ttol,
+	    typename MAT, typename VECT>
+  void extract_eig(const MAT &A, VECT &V, Ttol tol, std::complex<TA>, TV) {
+    typedef std::complex<TA> T;
+    size_type n = mat_nrows(A);
+    if (n == 0) return;
+    tol *= Ttol(2);
+    Ttol tol_i = tol * gmm::abs(A(0,0)), tol_cplx = tol_i;
+    for (size_type i = 0; i < n; ++i) {
+      if (i < n-1) {
+	tol_i = (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol;
+	tol_cplx = std::max(tol_cplx, tol_i);
+      }
+      if ((i == n-1) || gmm::abs(A(i+1,i)) < tol_i) {
+	if (gmm::abs(std::imag(A(i,i))) > tol_cplx)
+	  GMM_WARNING1("A complex eigenvalue has been detected : "
+		      << T(A(i,i)) << " : "  << gmm::abs(std::imag(A(i,i)))
+		      / gmm::abs(std::real(A(i,i))) << " : " << tol_cplx);
+	V[i] = std::real(A(i,i));
+      }
+      else {
+	T tr = A(i,i) + A(i+1, i+1);
+	T det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
+	T delta = tr*tr - TA(4) * det;
+	T a1 = (tr + gmm::sqrt(delta)) / TA(2);
+	T a2 = (tr - gmm::sqrt(delta)) / TA(2);
+	if (gmm::abs(std::imag(a1)) > tol_cplx)
+	  GMM_WARNING1("A complex eigenvalue has been detected : " << a1);
+	if (gmm::abs(std::imag(a2)) > tol_cplx)
+	  GMM_WARNING1("A complex eigenvalue has been detected : " << a2);
+
+	V[i] = std::real(a1); V[i+1] = std::real(a2);
+	++i;
+      }
+    }
+  }
+
+  template <typename TA, typename TV, typename Ttol,
+	    typename MAT, typename VECT>
+  void extract_eig(const MAT &A, VECT &V, Ttol tol,
+		   std::complex<TA>, std::complex<TV>) {
+    size_type n = mat_nrows(A);
+    tol *= Ttol(2);
+    for (size_type i = 0; i < n; ++i)
+      if ((i == n-1) ||
+	  gmm::abs(A(i+1,i)) < (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol)
+	V[i] = std::complex<TV>(A(i,i));
+      else {
+	std::complex<TA> tr = A(i,i) + A(i+1, i+1);
+	std::complex<TA> det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
+	std::complex<TA> delta = tr*tr - TA(4) * det;
+	V[i] = (tr + gmm::sqrt(delta)) / TA(2);
+	V[i+1] = (tr - gmm::sqrt(delta)) / TA(2);
+	++i;
+      }
+  }
+
+  ///@endcond
+  /**
+     Compute eigenvalue vector.
+  */
+  template <typename MAT, typename Ttol, typename VECT> inline
+  void extract_eig(const MAT &A, const VECT &V, Ttol tol) {
+    extract_eig(A, const_cast<VECT&>(V), tol,
+		typename linalg_traits<MAT>::value_type(),
+		typename linalg_traits<VECT>::value_type());
+  }
+
+  /* ********************************************************************* */
+  /*    Stop criterion for QR algorithms                                   */
+  /* ********************************************************************* */
+
+  template <typename MAT, typename Ttol>
+  void qr_stop_criterion(MAT &A, size_type &p, size_type &q, Ttol tol) {
+    typedef typename linalg_traits<MAT>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+    R rmin = default_min(R()) * R(2);
+    size_type n = mat_nrows(A);
+    if (n <= 2) { q = n; p = 0; }
+    else {
+      for (size_type i = 1; i < n-q; ++i)
+	if (gmm::abs(A(i,i-1)) < (gmm::abs(A(i,i))+ gmm::abs(A(i-1,i-1)))*tol
+	    || gmm::abs(A(i,i-1)) < rmin)
+	  A(i,i-1) = T(0);
+      
+      while ((q < n-1 && A(n-1-q, n-2-q) == T(0)) ||
+	     (q < n-2 && A(n-2-q, n-3-q) == T(0))) ++q;
+      if (q >= n-2) q = n;
+      p = n-q; if (p) --p; if (p) --p;
+      while (p > 0 && A(p,p-1) != T(0)) --p;
+    }
+  }
+  
+  template <typename MAT, typename Ttol> inline
+  void symmetric_qr_stop_criterion(const MAT &AA, size_type &p, size_type &q,
+				Ttol tol) {
+    typedef typename linalg_traits<MAT>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+    R rmin = default_min(R()) * R(2);
+    MAT& A = const_cast<MAT&>(AA);
+    size_type n = mat_nrows(A);
+    if (n <= 1) { q = n; p = 0; }
+    else {
+      for (size_type i = 1; i < n-q; ++i)
+	if (gmm::abs(A(i,i-1)) < (gmm::abs(A(i,i))+ gmm::abs(A(i-1,i-1)))*tol
+	    || gmm::abs(A(i,i-1)) < rmin)
+	  A(i,i-1) = T(0);
+      
+      while (q < n-1 && A(n-1-q, n-2-q) == T(0)) ++q;
+      if (q >= n-1) q = n;
+      p = n-q; if (p) --p; if (p) --p;
+      while (p > 0 && A(p,p-1) != T(0)) --p;
+    }
+  }
+
+  template <typename VECT1, typename VECT2, typename Ttol> inline
+  void symmetric_qr_stop_criterion(const VECT1 &diag, const VECT2 &sdiag_,
+				   size_type &p, size_type &q, Ttol tol) {
+    typedef typename linalg_traits<VECT2>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+    R rmin = default_min(R()) * R(2);
+    VECT2 &sdiag = const_cast<VECT2 &>(sdiag_);
+    size_type n = vect_size(diag);
+    if (n <= 1) { q = n; p = 0; return; }
+    for (size_type i = 1; i < n-q; ++i)
+      if (gmm::abs(sdiag[i-1]) < (gmm::abs(diag[i])+ gmm::abs(diag[i-1]))*tol
+	  || gmm::abs(sdiag[i-1]) < rmin)
+	sdiag[i-1] = T(0);
+    while (q < n-1 && sdiag[n-2-q] == T(0)) ++q;
+    if (q >= n-1) q = n;
+    p = n-q; if (p) --p; if (p) --p;
+    while (p > 0 && sdiag[p-1] != T(0)) --p;
+  }
+
+  /* ********************************************************************* */
+  /*    2x2 blocks reduction for Schur vectors                             */
+  /* ********************************************************************* */
+
+  template <typename MATH, typename MATQ, typename Ttol>
+  void block2x2_reduction(MATH &H, MATQ &Q, Ttol tol) {
+    typedef typename linalg_traits<MATH>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+
+    size_type n = mat_nrows(H), nq = mat_nrows(Q);
+    sub_interval SUBQ(0, nq), SUBL(0, 2);
+    std::vector<T> v(2), w(std::max(n, nq)); v[0] = T(1);
+    if (n < 2) return;
+    tol *= Ttol(2);
+    Ttol tol_i = tol * gmm::abs(H(0,0)), tol_cplx = tol_i;
+    for (size_type i = 0; i < n-1; ++i) {
+      tol_i = (gmm::abs(H(i,i))+gmm::abs(H(i+1,i+1)))*tol;
+      tol_cplx = std::max(tol_cplx, tol_i);
+      
+      if (gmm::abs(H(i+1,i)) > tol_i) { // 2x2 block detected
+	T tr = (H(i+1, i+1) - H(i,i)) / T(2);
+	T delta = tr*tr + H(i,i+1)*H(i+1, i);
+	
+	if (is_complex(T()) || gmm::real(delta) >= R(0)) {
+	  sub_interval SUBI(i, 2);
+	  T theta = (tr - gmm::sqrt(delta)) / H(i+1,i);
+	  R a = gmm::abs(theta);
+	  v[1] = (a == R(0)) ? T(-1)
+	    : gmm::conj(theta) * (R(1) - gmm::sqrt(a*a + R(1)) / a);
+	  row_house_update(sub_matrix(H, SUBI), v, sub_vector(w, SUBL));
+	  col_house_update(sub_matrix(H, SUBI), v, sub_vector(w, SUBL));
+	  col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
+	}
+	++i;
+      }
+    }
+  }
+
+  /* ********************************************************************* */
+  /*    Basic qr algorithm.                                                */
+  /* ********************************************************************* */
+
+  #define tol_type_for_qr typename number_traits<typename \
+                          linalg_traits<MAT1>::value_type>::magnitude_type
+  #define default_tol_for_qr \
+    (gmm::default_tol(tol_type_for_qr()) *  tol_type_for_qr(3))
+
+  // QR method for real or complex square matrices based on QR factorisation.
+  // eigval has to be a complex vector if A has complex eigeinvalues.
+  // Very slow method. Use implicit_qr_method instead.
+  template <typename MAT1, typename VECT, typename MAT2>
+    void rudimentary_qr_algorithm(const MAT1 &A, const VECT &eigval_,
+				  const MAT2 &eigvect_,
+				  tol_type_for_qr tol = default_tol_for_qr,
+				  bool compvect = true) {
+    VECT &eigval = const_cast<VECT &>(eigval_);
+    MAT2 &eigvect = const_cast<MAT2 &>(eigvect_);
+
+    typedef typename linalg_traits<MAT1>::value_type value_type;
+
+    size_type n = mat_nrows(A), p, q = 0, ite = 0;
+    dense_matrix<value_type> Q(n, n), R(n,n), A1(n,n); 
+    gmm::copy(A, A1);
+
+    Hessenberg_reduction(A1, eigvect, compvect);
+    qr_stop_criterion(A1, p, q, tol);
+
+    while (q < n) {
+      qr_factor(A1, Q, R);
+      gmm::mult(R, Q, A1);
+      if (compvect) { gmm::mult(eigvect, Q, R); gmm::copy(R, eigvect); }
+      
+      qr_stop_criterion(A1, p, q, tol);
+      ++ite;
+      GMM_ASSERT1(ite < n*1000, "QR algorithm failed");
+    }
+    if (compvect) block2x2_reduction(A1, Q, tol);
+    extract_eig(A1, eigval, tol); 
+  }
+
+  template <typename MAT1, typename VECT>
+    void rudimentary_qr_algorithm(const MAT1 &a, VECT &eigval,
+				  tol_type_for_qr tol = default_tol_for_qr) {
+    dense_matrix<typename linalg_traits<MAT1>::value_type> m(0,0);
+    rudimentary_qr_algorithm(a, eigval, m, tol, false); 
+  }
+
+  /* ********************************************************************* */
+  /*    Francis QR step.                                                   */
+  /* ********************************************************************* */
+
+  template <typename MAT1, typename MAT2>
+    void Francis_qr_step(const MAT1& HH, const MAT2 &QQ, bool compute_Q) {
+    MAT1& H = const_cast<MAT1&>(HH); MAT2& Q = const_cast<MAT2&>(QQ);
+    typedef typename linalg_traits<MAT1>::value_type value_type;
+    size_type n = mat_nrows(H), nq = mat_nrows(Q); 
+    
+    std::vector<value_type> v(3), w(std::max(n, nq));
+
+    value_type s = H(n-2, n-2) + H(n-1, n-1);
+    value_type t = H(n-2, n-2) * H(n-1, n-1) - H(n-2, n-1) * H(n-1, n-2);
+    value_type x = H(0, 0) * H(0, 0) + H(0,1) * H(1, 0) - s * H(0,0) + t;
+    value_type y = H(1, 0) * (H(0,0) + H(1,1) - s);
+    value_type z = H(1, 0) * H(2, 1);
+
+    sub_interval SUBQ(0, nq);
+
+    for (size_type k = 0; k < n - 2; ++k) {
+      v[0] = x; v[1] = y; v[2] = z;
+      house_vector(v);
+      size_type r = std::min(k+4, n), q = (k==0) ? 0 : k-1;
+      sub_interval SUBI(k, 3), SUBJ(0, r), SUBK(q, n-q);
+      
+      row_house_update(sub_matrix(H, SUBI, SUBK),  v, sub_vector(w, SUBK));
+      col_house_update(sub_matrix(H, SUBJ, SUBI),  v, sub_vector(w, SUBJ));
+      
+      if (compute_Q)
+       	col_house_update(sub_matrix(Q, SUBQ, SUBI),  v, sub_vector(w, SUBQ));
+
+      x = H(k+1, k); y = H(k+2, k);
+      if (k < n-3) z = H(k+3, k);
+    }
+    sub_interval SUBI(n-2,2), SUBJ(0, n), SUBK(n-3,3), SUBL(0, 3);
+    v.resize(2);
+    v[0] = x; v[1] = y;
+    house_vector(v);
+    row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBL));
+    col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
+    if (compute_Q)
+      col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
+  }
+
+  /* ********************************************************************* */
+  /*    Wilkinson Double shift QR step (from Lapack).                      */
+  /* ********************************************************************* */
+
+  template <typename MAT1, typename MAT2, typename Ttol>
+  void Wilkinson_double_shift_qr_step(const MAT1& HH, const MAT2 &QQ,
+				      Ttol tol, bool exc, bool compute_Q) {
+    MAT1& H = const_cast<MAT1&>(HH); MAT2& Q = const_cast<MAT2&>(QQ);
+    typedef typename linalg_traits<MAT1>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+
+    size_type n = mat_nrows(H), nq = mat_nrows(Q), m;
+    std::vector<T> v(3), w(std::max(n, nq));
+    const R dat1(0.75), dat2(-0.4375);
+    T h33, h44, h43h34, v1(0), v2(0), v3(0);
+    
+    if (exc) {                    /* Exceptional shift.                    */
+      R s = gmm::abs(H(n-1, n-2)) + gmm::abs(H(n-2, n-3));
+      h33 = h44 = dat1 * s;
+      h43h34 = dat2*s*s;
+    }
+    else {                        /* Wilkinson double shift.               */
+      h44 = H(n-1,n-1); h33 = H(n-2, n-2);
+      h43h34 = H(n-1, n-2) * H(n-2, n-1);
+    }
+
+    /* Look for two consecutive small subdiagonal elements.                */
+    /* Determine the effect of starting the double-shift QR iteration at   */
+    /* row m, and see if this would make H(m-1, m-2) negligible.           */
+    for (m = n-2; m != 0; --m) {
+      T h11  = H(m-1, m-1), h22  = H(m, m);
+      T h21  = H(m, m-1),   h12  = H(m-1, m);
+      T h44s = h44 - h11,   h33s = h33 - h11;
+      v1 = (h33s*h44s-h43h34) / h21 + h12;
+      v2 = h22 - h11 - h33s - h44s;
+      v3 = H(m+1, m);
+      R s = gmm::abs(v1) + gmm::abs(v2) + gmm::abs(v3);
+      v1 /= s; v2 /= s; v3 /= s;
+      if (m == 1) break;
+      T h00 = H(m-2, m-2);
+      T h10 = H(m-1, m-2);
+      R tst1 = gmm::abs(v1)*(gmm::abs(h00)+gmm::abs(h11)+gmm::abs(h22));
+      if (gmm::abs(h10)*(gmm::abs(v2)+gmm::abs(v3)) <= tol * tst1) break;
+    }
+
+    /* Double shift QR step.                                               */
+    sub_interval SUBQ(0, nq);
+    for (size_type k = (m == 0) ? 0 : m-1; k < n-2; ++k) {
+      v[0] = v1; v[1] = v2; v[2] = v3;
+      house_vector(v);
+      size_type r = std::min(k+4, n), q = (k==0) ? 0 : k-1;
+      sub_interval SUBI(k, 3), SUBJ(0, r), SUBK(q, n-q);
+      
+      row_house_update(sub_matrix(H, SUBI, SUBK),  v, sub_vector(w, SUBK));
+      col_house_update(sub_matrix(H, SUBJ, SUBI),  v, sub_vector(w, SUBJ));
+      if (k > m-1) { H(k+1, k-1) = T(0); if (k < n-3) H(k+2, k-1) = T(0); }
+      
+      if (compute_Q)
+       	col_house_update(sub_matrix(Q, SUBQ, SUBI),  v, sub_vector(w, SUBQ));
+
+      v1 = H(k+1, k); v2 = H(k+2, k);
+      if (k < n-3) v3 = H(k+3, k);
+    }
+    sub_interval SUBI(n-2,2), SUBJ(0, n), SUBK(n-3,3), SUBL(0, 3);
+    v.resize(2); v[0] = v1; v[1] = v2;
+    house_vector(v);
+    row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBL));
+    col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
+    if (compute_Q)
+      col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
+  }
+
+  /* ********************************************************************* */
+  /*    Implicit QR algorithm.                                             */
+  /* ********************************************************************* */
+
+  // QR method for real or complex square matrices based on an
+  // implicit QR factorisation. eigval has to be a complex vector
+  // if A has complex eigeinvalues. complexity about 10n^3, 25n^3 if
+  // eigenvectors are computed
+  template <typename MAT1, typename VECT, typename MAT2>
+    void implicit_qr_algorithm(const MAT1 &A, const VECT &eigval_,
+			       const MAT2 &Q_, 
+			       tol_type_for_qr tol = default_tol_for_qr,
+			       bool compvect = true) {
+    VECT &eigval = const_cast<VECT &>(eigval_);
+    MAT2 &Q = const_cast<MAT2 &>(Q_);
+    typedef typename linalg_traits<MAT1>::value_type value_type;
+
+    size_type n(mat_nrows(A)), q(0), q_old, p(0), ite(0), its(0);
+    dense_matrix<value_type> H(n,n);
+    sub_interval SUBK(0,0);
+
+    gmm::copy(A, H);
+    Hessenberg_reduction(H, Q, compvect);
+    qr_stop_criterion(H, p, q, tol);
+    
+    while (q < n) {
+      sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(Q));
+      if (compvect) SUBK = SUBI;
+//       Francis_qr_step(sub_matrix(H, SUBI),
+// 		      sub_matrix(Q, SUBJ, SUBK), compvect);
+      Wilkinson_double_shift_qr_step(sub_matrix(H, SUBI), 
+				     sub_matrix(Q, SUBJ, SUBK),
+				     tol, (its == 10 || its == 20), compvect);
+      q_old = q;
+      qr_stop_criterion(H, p, q, tol*2);
+      if (q != q_old) its = 0;
+      ++its; ++ite;
+      GMM_ASSERT1(ite < n*100, "QR algorithm failed");
+    }
+    if (compvect) block2x2_reduction(H, Q, tol);
+    extract_eig(H, eigval, tol);
+  }
+
+
+  template <typename MAT1, typename VECT>
+    void implicit_qr_algorithm(const MAT1 &a, VECT &eigval,
+			       tol_type_for_qr tol = default_tol_for_qr) {
+    dense_matrix<typename linalg_traits<MAT1>::value_type> m(0,0);
+    implicit_qr_algorithm(a, eigval, m, tol, false); 
+  }
+
+  /* ********************************************************************* */
+  /*    Implicit symmetric QR step with Wilkinson Shift.                   */
+  /* ********************************************************************* */
+
+  template <typename MAT1, typename MAT2> 
+    void symmetric_Wilkinson_qr_step(const MAT1& MM, const MAT2 &ZZ,
+				     bool compute_z) {
+    MAT1& M = const_cast<MAT1&>(MM); MAT2& Z = const_cast<MAT2&>(ZZ);
+    typedef typename linalg_traits<MAT1>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+    size_type n = mat_nrows(M);
+
+    for (size_type i = 0; i < n; ++i) {
+      M(i, i) = T(gmm::real(M(i, i)));
+      if (i > 0) {
+	T a = (M(i, i-1) + gmm::conj(M(i-1, i)))/R(2);
+	M(i, i-1) = a; M(i-1, i) = gmm::conj(a);
+      }
+    }
+
+    R d = gmm::real(M(n-2, n-2) - M(n-1, n-1)) / R(2);
+    R e = gmm::abs_sqr(M(n-1, n-2));
+    R nu = d + gmm::sgn(d)*gmm::sqrt(d*d+e);
+    if (nu == R(0)) { M(n-1, n-2) = T(0); return; }
+    R mu = gmm::real(M(n-1, n-1)) - e / nu;
+    T x = M(0,0) - T(mu), z = M(1, 0), c, s;
+
+    for (size_type k = 1; k < n; ++k) {
+      Givens_rotation(x, z, c, s);
+
+      if (k > 1) Apply_Givens_rotation_left(M(k-1,k-2), M(k,k-2), c, s);
+      Apply_Givens_rotation_left(M(k-1,k-1), M(k,k-1), c, s);
+      Apply_Givens_rotation_left(M(k-1,k  ), M(k,k  ), c, s);
+      if (k < n-1) Apply_Givens_rotation_left(M(k-1,k+1), M(k,k+1), c, s);
+      if (k > 1) Apply_Givens_rotation_right(M(k-2,k-1), M(k-2,k), c, s);
+      Apply_Givens_rotation_right(M(k-1,k-1), M(k-1,k), c, s);
+      Apply_Givens_rotation_right(M(k  ,k-1), M(k,k)  , c, s);
+      if (k < n-1) Apply_Givens_rotation_right(M(k+1,k-1), M(k+1,k), c, s);
+
+      if (compute_z) col_rot(Z, c, s, k-1, k);
+      if (k < n-1) { x = M(k, k-1); z = M(k+1, k-1); }
+    }
+
+  }
+
+  template <typename VECT1, typename VECT2, typename MAT> 
+  void symmetric_Wilkinson_qr_step(const VECT1& diag_, const VECT2& sdiag_,
+				   const MAT &ZZ, bool compute_z) {
+    VECT1& diag = const_cast<VECT1&>(diag_);
+    VECT2& sdiag = const_cast<VECT2&>(sdiag_);
+    MAT& Z = const_cast<MAT&>(ZZ);
+    typedef typename linalg_traits<VECT2>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+
+    size_type n = vect_size(diag);
+    R d = (diag[n-2] - diag[n-1]) / R(2);
+    R e = gmm::abs_sqr(sdiag[n-2]);
+    R nu = d + gmm::sgn(d)*gmm::sqrt(d*d+e);
+    if (nu == R(0)) { sdiag[n-2] = T(0); return; }
+    R mu = diag[n-1] - e / nu;
+    T x = diag[0] - T(mu), z = sdiag[0], c, s;
+
+    T a01(0), a02(0);
+    T a10(0), a11(diag[0]), a12(gmm::conj(sdiag[0])), a13(0);
+    T a20(0), a21(sdiag[0]), a22(diag[1]), a23(gmm::conj(sdiag[1]));
+    T a31(0), a32(sdiag[1]);
+
+    for (size_type k = 1; k < n; ++k) {
+      Givens_rotation(x, z, c, s);
+
+      if (k > 1) Apply_Givens_rotation_left(a10, a20, c, s);
+      Apply_Givens_rotation_left(a11, a21, c, s);
+      Apply_Givens_rotation_left(a12, a22, c, s);
+      if (k < n-1) Apply_Givens_rotation_left(a13, a23, c, s);
+
+      if (k > 1) Apply_Givens_rotation_right(a01, a02, c, s);
+      Apply_Givens_rotation_right(a11, a12, c, s);
+      Apply_Givens_rotation_right(a21, a22, c, s);
+      if (k < n-1) Apply_Givens_rotation_right(a31, a32, c, s);
+
+      if (compute_z) col_rot(Z, c, s, k-1, k);
+
+      diag[k-1] = gmm::real(a11);
+      diag[k] = gmm::real(a22);
+      if (k > 1) sdiag[k-2] = (gmm::conj(a01) + a10) / R(2);
+      sdiag[k-1] = (gmm::conj(a12) + a21) / R(2);
+
+      x = sdiag[k-1]; z = (gmm::conj(a13) + a31) / R(2);
+
+      a01 = a12; a02 = a13;
+      a10 = a21; a11 = a22; a12 = a23; a13 = T(0);
+      a20 = a31; a21 = a32; a31 = T(0);
+
+      if (k < n-1) {
+	sdiag[k] = (gmm::conj(a23) + a32) / R(2);
+	a22 = T(diag[k+1]); a32 = sdiag[k+1]; a23 = gmm::conj(a32);
+      }
+    }
+  }
+
+  /* ********************************************************************* */
+  /*    Implicit QR algorithm for symmetric or hermitian matrices.         */
+  /* ********************************************************************* */
+
+  // implicit QR method for real square symmetric matrices or complex
+  // hermitian matrices.
+  // eigval has to be a complex vector if A has complex eigeinvalues.
+  // complexity about 4n^3/3, 9n^3 if eigenvectors are computed
+  template <typename MAT1, typename VECT, typename MAT2>
+  void symmetric_qr_algorithm_old(const MAT1 &A, const VECT &eigval_,
+			      const MAT2 &eigvect_,
+			      tol_type_for_qr tol = default_tol_for_qr,
+			      bool compvect = true) {
+    VECT &eigval = const_cast<VECT &>(eigval_);
+    MAT2 &eigvect = const_cast<MAT2 &>(eigvect_);
+    typedef typename linalg_traits<MAT1>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+
+    if (compvect) gmm::copy(identity_matrix(), eigvect);
+    size_type n = mat_nrows(A), q = 0, p, ite = 0;
+    dense_matrix<T> Tri(n, n);
+    gmm::copy(A, Tri);
+
+    Householder_tridiagonalization(Tri, eigvect, compvect);
+    
+    symmetric_qr_stop_criterion(Tri, p, q, tol);
+    
+    while (q < n) {
+
+      sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(eigvect)), SUBK(p, n-p-q);
+      if (!compvect) SUBK = sub_interval(0,0);
+      symmetric_Wilkinson_qr_step(sub_matrix(Tri, SUBI), 
+				  sub_matrix(eigvect, SUBJ, SUBK), compvect);
+      
+      symmetric_qr_stop_criterion(Tri, p, q, tol*R(2));
+      ++ite;
+      GMM_ASSERT1(ite < n*100, "QR algorithm failed. Probably, your matrix"
+		  " is not real symmetric or complex hermitian");
+    }
+    
+    extract_eig(Tri, eigval, tol);
+  }
+
+  template <typename MAT1, typename VECT, typename MAT2>
+  void symmetric_qr_algorithm(const MAT1 &A, const VECT &eigval_,
+			      const MAT2 &eigvect_,
+			      tol_type_for_qr tol = default_tol_for_qr,
+			      bool compvect = true) {
+    VECT &eigval = const_cast<VECT &>(eigval_);
+    MAT2 &eigvect = const_cast<MAT2 &>(eigvect_);
+    typedef typename linalg_traits<MAT1>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+
+    size_type n = mat_nrows(A), q = 0, p, ite = 0;
+    if (compvect) gmm::copy(identity_matrix(), eigvect);
+    if (n == 0) return;
+    if (n == 1) { eigval[0]=gmm::real(A(0,0)); return; }
+    dense_matrix<T> Tri(n, n);
+    gmm::copy(A, Tri);
+
+    Householder_tridiagonalization(Tri, eigvect, compvect);
+
+    std::vector<R> diag(n);
+    std::vector<T> sdiag(n);
+    for (size_type i = 0; i < n; ++i)
+      { diag[i] = gmm::real(Tri(i, i)); if (i+1 < n) sdiag[i] = Tri(i+1, i); }
+    
+    symmetric_qr_stop_criterion(diag, sdiag, p, q, tol);
+    
+    while (q < n) {
+      sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(eigvect)), SUBK(p, n-p-q);
+      if (!compvect) SUBK = sub_interval(0,0);
+      
+      symmetric_Wilkinson_qr_step(sub_vector(diag, SUBI),
+				  sub_vector(sdiag, SUBI),
+				  sub_matrix(eigvect, SUBJ, SUBK), compvect);
+
+      symmetric_qr_stop_criterion(diag, sdiag, p, q, tol*R(2));
+      ++ite;
+      GMM_ASSERT1(ite < n*100, "QR algorithm failed.");
+    }
+    
+    gmm::copy(diag, eigval);
+  }
+
+
+  template <typename MAT1, typename VECT>
+    void symmetric_qr_algorithm(const MAT1 &a, VECT &eigval,
+				tol_type_for_qr tol = default_tol_for_qr) {
+    dense_matrix<typename linalg_traits<MAT1>::value_type> m(0,0);
+    symmetric_qr_algorithm(a, eigval, m, tol, false);
+  }
+
+
+}
+
+#endif
+
diff --git a/Contrib/gmm/gmm_dense_sylvester.h b/Contrib/gmm/gmm_dense_sylvester.h
new file mode 100755
index 0000000..5a4c8fa
--- /dev/null
+++ b/Contrib/gmm/gmm_dense_sylvester.h
@@ -0,0 +1,173 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/** @file gmm_dense_sylvester.h
+    @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+    @date June 5, 2003.
+    @brief Sylvester equation solver.
+*/
+#ifndef GMM_DENSE_SYLVESTER_H
+#define GMM_DENSE_SYLVESTER_H
+
+#include "gmm_kernel.h"
+
+namespace gmm {
+
+  /* ********************************************************************* */
+  /*   Kronecker system matrix.                                            */
+  /* ********************************************************************* */
+  template <typename MAT1, typename MAT2, typename MAT3>
+  void kron(const MAT1 &m1, const MAT2 &m2, const MAT3 &m3_,
+	    bool init = true) {
+    MAT3 &m3 = const_cast<MAT3 &>(m3_);
+    size_type m = mat_nrows(m1), n = mat_ncols(m1);
+    size_type l = mat_nrows(m2), k = mat_ncols(m2);
+
+    GMM_ASSERT2(mat_nrows(m3) == m*l && mat_ncols(m3) == n*k,
+		"dimensions mismatch");
+
+    for (size_type i = 0; i < m; ++i)
+      for (size_type j = 0; j < m; ++j)
+	if (init)
+	  gmm::copy(gmm::scaled(m2, m1(i,j)),
+		    gmm::sub_matrix(m3, sub_interval(l*i, l),
+				    sub_interval(k*j, k)));
+	else
+	  gmm::add(gmm::scaled(m2, m1(i,j)),
+		    gmm::sub_matrix(m3, sub_interval(l*i, l),
+				    sub_interval(k*j, k)));
+  }
+	
+
+  /* ********************************************************************* */
+  /*   Copy a matrix into a vector.                                        */
+  /* ********************************************************************* */
+
+  template <typename MAT, typename VECT>
+  colmatrix_to_vector(const MAT &A, VECT &v, col_major) {
+    size_type m = mat_nrows(A), n = mat_ncols(A);
+    GMM_ASSERT2(m*n == vect_size(v), "dimensions mismatch");
+    for (size_type i = 0; i < n; ++i)
+      gmm::copy(mat_col(A, i), sub_vector(v, sub_interval(i*m, m)));
+  }
+
+  template <typename MAT, typename VECT>
+  colmatrix_to_vector(const MAT &A, VECT &v, row_and_col)
+  { colmatrix_to_vector(A, v, col_major()); }
+
+  template <typename MAT, typename VECT>
+  colmatrix_to_vector(const MAT &A, VECT &v, col_and_row)
+  { colmatrix_to_vector(A, v, col_major()); }
+
+  template <typename MAT, typename VECT>
+  colmatrix_to_vector(const MAT &A, VECT &v, row_major) {
+    size_type m = mat_nrows(mat), n = mat_ncols(A);
+    GMM_ASSERT2(m*n == vect_size(v), "dimensions mismatch");
+    for (size_type i = 0; i < m; ++i)
+      gmm::copy(mat_row(A, i), sub_vector(v, sub_slice(i, n, m)));
+  }
+
+  template <typename MAT, typename VECT> inline
+  colmatrix_to_vector(const MAT &A, const VECT &v_) {
+    VECT &v = const_cast<VECT &>(v_);
+    colmatrix_to_vector(A, v, typename linalg_traits<MAT>::sub_orientation());
+  }
+
+
+  /* ********************************************************************* */
+  /*   Copy a vector into a matrix.                                        */
+  /* ********************************************************************* */
+
+  template <typename MAT, typename VECT>
+  vector_to_colmatrix(const VECT &v, MAT &A, col_major) {
+    size_type m = mat_nrows(A), n = mat_ncols(A);
+    GMM_ASSERT2(m*n == vect_size(v), "dimensions mismatch");
+    for (size_type i = 0; i < n; ++i)
+      gmm::copy(sub_vector(v, sub_interval(i*m, m)), mat_col(A, i));
+  }
+
+  template <typename MAT, typename VECT>
+  vector_to_colmatrix(const VECT &v, MAT &A, row_and_col)
+  { vector_to_colmatrix(v, A, col_major()); }
+
+  template <typename MAT, typename VECT>
+  vector_to_colmatrix(const VECT &v, MAT &A, col_and_row)
+  { vector_to_colmatrix(v, A, col_major()); }
+
+  template <typename MAT, typename VECT>
+  vector_to_colmatrix(const VECT &v, MAT &A, row_major) {
+    size_type m = mat_nrows(mat), n = mat_ncols(A);
+    GMM_ASSERT2(m*n == vect_size(v), "dimensions mismatch");
+    for (size_type i = 0; i < m; ++i)
+      gmm::copy(sub_vector(v, sub_slice(i, n, m)), mat_row(A, i));
+  }
+
+  template <typename MAT, typename VECT> inline
+  vector_to_colmatrix(const VECT &v, const MAT &A_) {
+    MAT &A = const_cast<MAT &>(A_);
+    vector_to_colmatrix(v, A, typename linalg_traits<MAT>::sub_orientation());
+  }
+
+  /* ********************************************************************* */
+  /*   Solve sylvester equation.                                           */
+  /* ********************************************************************* */
+
+  // very prohibitive solver, to be replaced ... 
+  template <typename MAT1, typename MAT2, typename MAT3, typename MAT4 >
+  void sylvester(const MAT1 &m1, const MAT2 &m2, const MAT3 &m3,
+		 const MAT4 &m4_) {
+    typedef typename linalg_traits<Mat>::value_type T;
+    
+    MAT3 &m4 = const_cast<MAT4 &>(m4_);
+    size_type m = mat_nrows(m1), n = mat_ncols(m1);
+    size_type l = mat_nrows(m2), k = mat_ncols(m2);
+    
+    GMM_ASSERT2(m == n && l == k && m == mat_nrows(m3) &&
+		l == mat_ncols(m3) && m == mat_nrows(m4) && l == mat_ncols(m4),
+		"dimensions mismatch");
+
+    gmm::dense_matrix<T> akronb(m*l, m*l);
+    gmm::dense_matrix<T> idm(m, m), idl(l,l);
+    gmm::copy(identity_matrix(), idm);
+    gmm::copy(identity_matrix(), idl);
+    std::vector<T> x(m*l), c(m*l);
+    
+    kron(idl, m1, akronb);
+    kron(gmm::transposed(m2), idm, akronb, false);
+
+    colmatrix_to_vector(m3, c);
+    lu_solve(akronb, c, x);
+    vector_to_colmatrix(x, m4);
+
+  }
+}
+
+#endif
+
diff --git a/Contrib/gmm/gmm_domain_decomp.h b/Contrib/gmm/gmm_domain_decomp.h
new file mode 100755
index 0000000..a2f9d52
--- /dev/null
+++ b/Contrib/gmm/gmm_domain_decomp.h
@@ -0,0 +1,164 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2004-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/** @file gmm_domain_decomp.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date May 21, 2004.
+    @brief Domain decomposition.
+*/
+#ifndef GMM_DOMAIN_DECOMP_H__
+#define GMM_DOMAIN_DECOMP_H__
+
+#include "gmm_kernel.h"
+#include <map>
+
+
+namespace gmm {
+
+  /** This function separates into small boxes of size msize with a ratio
+   * of overlap (in [0,1[) a set of points. The result is given into a
+   * vector of sparse matrices vB.
+   */
+  template <typename Matrix, typename Point>
+  void rudimentary_regular_decomposition(std::vector<Point> pts,
+					 double msize,
+					 double overlap,
+					 std::vector<Matrix> &vB) {
+    typedef typename linalg_traits<Matrix>::value_type value_type;
+    typedef abstract_null_type void_type;
+    typedef std::map<size_type, void_type> map_type;
+
+    size_type nbpts = pts.size();
+    if (!nbpts || pts[0].size() == 0) { vB.resize(0); return; }
+    int dim = int(pts[0].size());
+
+    // computation of the global box and the number of sub-domains
+    Point pmin = pts[0], pmax = pts[0];
+    for (size_type i = 1; i < nbpts; ++i)
+      for (int k = 0; k < dim; ++k) {
+	pmin[k] = std::min(pmin[k], pts[i][k]);
+	pmax[k] = std::max(pmax[k], pts[i][k]);
+      }
+    
+    std::vector<size_type> nbsub(dim), mult(dim);
+    std::vector<int> pts1(dim), pts2(dim);
+    size_type nbtotsub = 1;
+    for (int k = 0; k < dim; ++k) {
+      nbsub[k] = size_type((pmax[k] - pmin[k]) / msize)+1;
+      mult[k] = nbtotsub; nbtotsub *= nbsub[k];
+    }
+    
+    std::vector<map_type> subs(nbtotsub);
+    // points ventilation
+    std::vector<size_type> ns(dim), na(dim), nu(dim);
+    for (size_type i = 0; i < nbpts; ++i) {
+      for (int k = 0; k < dim; ++k) {
+	register double a = (pts[i][k] - pmin[k]) / msize;
+	ns[k] = size_type(a) - 1; na[k] = 0;
+	pts1[k] = int(a + overlap); pts2[k] = int(ceil(a-1.0-overlap));
+      }
+      size_type sum = 0;
+      do {
+	bool ok = 1;
+	for (int k = 0; k < dim; ++k)
+	  if ((ns[k] >= nbsub[k]) || (pts1[k] < int(ns[k]))
+	      || (pts2[k] > int(ns[k]))) { ok = false; break; }
+	if (ok) {
+	  size_type ind = ns[0];
+	  for (int k=1; k < dim; ++k) ind += ns[k]*mult[k];
+	  subs[ind][i] = void_type();
+	}
+	for (int k = 0; k < dim; ++k) {
+	  if (na[k] < 2) { na[k]++; ns[k]++; ++sum; break; }
+	  na[k] = 0; ns[k] -= 2; sum -= 2;
+	}
+      } while (sum);
+    }
+    // delete too small domains.
+    size_type nbmaxinsub = 0;
+    for (size_type i = 0; i < nbtotsub; ++i)
+      nbmaxinsub = std::max(nbmaxinsub, subs[i].size());
+    
+    std::fill(ns.begin(), ns.end(), size_type(0));
+    for (size_type i = 0; i < nbtotsub; ++i) {
+      if (subs[i].size() > 0 && subs[i].size() < nbmaxinsub / 10) {
+	
+	for (int k = 0; k < dim; ++k) nu[k] = ns[k];
+	size_type nbmax = 0, imax = 0;
+	
+	for (int l = 0; l < dim; ++l) {
+	  nu[l]--;
+	  for (int m = 0; m < 2; ++m, nu[l]+=2) {
+	    bool ok = true;
+	    for (int k = 0; k < dim && ok; ++k) 
+	      if (nu[k] >= nbsub[k]) ok = false;
+	    if (ok) {
+	      size_type ind = ns[0];
+	      for (int k=1; k < dim; ++k) ind += ns[k]*mult[k];
+	      if (subs[ind].size() > nbmax)
+		{ nbmax = subs[ind].size(); imax = ind; }
+	    }
+	  }
+	  nu[l]--;
+	}
+	
+	if (nbmax > subs[i].size()) {
+	  for (map_type::iterator it=subs[i].begin(); it!=subs[i].end(); ++it)
+	    subs[imax][it->first] = void_type();
+	  subs[i].clear();
+	}
+      }
+      for (int k = 0; k < dim; ++k)
+	{ ns[k]++; if (ns[k] < nbsub[k]) break; ns[k] = 0; }
+    }
+    
+    // delete empty domains.
+    size_type effnb = 0;
+    for (size_type i = 0; i < nbtotsub; ++i) {
+      if (subs[i].size() > 0)
+	{ if (i != effnb) std::swap(subs[i], subs[effnb]); ++effnb; }
+    }
+
+    // build matrices
+    subs.resize(effnb);
+    vB.resize(effnb);
+    for (size_type i = 0; i < effnb; ++i) {
+      clear(vB[i]); resize(vB[i], nbpts, subs[i].size());
+      size_type j = 0;
+      for (map_type::iterator it=subs[i].begin(); it!=subs[i].end(); ++it, ++j)
+	vB[i](it->first, j) = value_type(1);
+    }
+  }
+  
+
+}
+
+
+#endif
diff --git a/Contrib/gmm/gmm_except.h b/Contrib/gmm/gmm_except.h
new file mode 100755
index 0000000..24b4ab7
--- /dev/null
+++ b/Contrib/gmm/gmm_except.h
@@ -0,0 +1,333 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/** @file gmm_except.h 
+    @author Yves Renard <Yves.Renard at insa-lyon.fr>
+    @author Julien Pommier <Julien.Pommier at insa-toulouse.fr>
+    @date September 01, 2002.
+    @brief Definition of basic exceptions.
+*/
+
+#ifndef GMM_EXCEPT_H__
+#define GMM_EXCEPT_H__
+
+#include "gmm_std.h"
+
+namespace gmm {
+
+/* *********************************************************************** */
+/*	Getfem++ generic errors.                     			   */
+/* *********************************************************************** */
+
+  class gmm_error: public std::logic_error {
+  public:
+    gmm_error(const std::string& what_arg): std::logic_error (what_arg) {}
+  };
+
+#ifdef GETFEM_HAVE_PRETTY_FUNCTION
+#  define GMM_PRETTY_FUNCTION __PRETTY_FUNCTION__
+#else 
+#  define GMM_PRETTY_FUNCTION ""
+#endif
+
+  // Errors : GMM_THROW should not be used on its own.
+  //          GMM_ASSERT1 : Non-maskable errors. Typically for in/ouput and
+  //               when the test do not significantly reduces the performance.
+  //          GMM_ASSERT2 : All tests which are potentially performance
+  //               consuming. Not hidden by default. Hidden when NDEBUG is
+  //               defined.
+  //          GMM_ASSERT3 : For internal checks. Hidden by default. Active
+  //               only when DEBUG_MODE is defined.
+
+#ifdef __EXCEPTIONS
+  inline void short_error_throw(const char *file, int line, const char *func,
+				const char *errormsg) {
+    std::stringstream msg;
+    msg << "Error in " << file << ", line " << line << " " << func
+	<< ": \n" << errormsg << ends;
+    throw gmm::gmm_error(msg.str());	
+  }
+# define GMM_THROW_(type, errormsg) {					\
+    std::stringstream msg;						\
+    msg << "Error in "__FILE__ << ", line "				\
+	<< __LINE__ << " " << GMM_PRETTY_FUNCTION << ": \n"		\
+	<< errormsg << ends;						\
+    throw (type)(msg.str());						\
+  }
+#else
+  inline void short_error_throw(const char *file, int line, const char *func,
+				const char *errormsg) {
+    std::stringstream msg;
+    msg << "Error in " << file << ", line " << line << " " << func
+	<< ": \n" << errormsg << ends;
+    ::abort();	
+  }
+# define GMM_THROW_(type, errormsg) {					\
+    std::stringstream msg;						\
+    msg << "Error in "__FILE__ << ", line "				\
+	<< __LINE__ << " " << GMM_PRETTY_FUNCTION << ": \n"		\
+	<< errormsg   << ends;						\
+    ::abort();								\
+  }
+#endif
+  
+# define GMM_ASSERT1(test, errormsg)		        		\
+  { if (!(test)) GMM_THROW_(gmm::gmm_error, errormsg); }
+
+  // inline void GMM_THROW() IS_DEPRECATED;
+  inline void GMM_THROW() {}
+#define GMM_THROW(a, b) { GMM_THROW_(a,b); gmm::GMM_THROW(); }
+
+#if defined(NDEBUG)
+# define GMM_ASSERT2(test, errormsg)
+# define GMM_ASSERT3(test, errormsg)
+#elif !defined(GMM_FULL_NDEBUG)
+# define GMM_ASSERT2(test, errormsg)				        \
+  { if (!(test)) gmm::short_error_throw(__FILE__, __LINE__,		\
+				   GMM_PRETTY_FUNCTION, errormsg); }
+# define GMM_ASSERT3(test, errormsg)				        \
+  { if (!(test)) gmm::short_error_throw(__FILE__, __LINE__,		\
+				   GMM_PRETTY_FUNCTION, errormsg); }
+#else
+# define GMM_ASSERT2(test, errormsg)          				\
+  { if (!(test)) gmm::short_error_throw(__FILE__, __LINE__,		\
+				   GMM_PRETTY_FUNCTION, errormsg); }
+# define GMM_ASSERT3(test, errormsg)
+#endif
+
+/* *********************************************************************** */
+/*	Getfem++ warnings.                         			   */
+/* *********************************************************************** */
+
+  // This allows to dynamically hide warnings
+  struct warning_level {
+    static int level(int l = -2)
+    { static int level_ = 3; return (l != -2) ? (level_ = l) : level_; }
+  };
+
+  inline void set_warning_level(int l) { warning_level::level(std::max(0,l)); }
+  inline int  get_warning_level(void)  { return warning_level::level(-2); }
+
+  // This allow not too compile some Warnings
+#ifndef GMM_WARNING_LEVEL
+# define GMM_WARNING_LEVEL 4
+#endif
+
+  // Warning levels : 0 always printed
+  //                  1 very important : specify a possible error in the code.
+  //                  2 important : specify a default of optimization for inst.
+  //                  3 remark
+  //                  4 ignored by default.
+
+#define GMM_WARNING_MSG(level_, thestr)  {			       \
+      std::stringstream msg;                                           \
+      msg << "Level " << level_ << " Warning in "__FILE__ << ", line " \
+          << __LINE__ << ": " << thestr << ends;		       \
+       std::cerr << msg.str() << std::endl;                            \
+    }
+
+#define GMM_WARNING0(thestr) GMM_WARNING_MSG(0, thestr)
+
+#if GMM_WARNING_LEVEL > 0
+# define GMM_WARNING1(thestr)                                           \
+  { if (1 <= gmm::warning_level::level()) GMM_WARNING_MSG(1, thestr) }
+#else
+# define GMM_WARNING1(thestr) {}
+#endif
+
+#if GMM_WARNING_LEVEL > 1
+# define GMM_WARNING2(thestr)                                           \
+  { if (2 <= gmm::warning_level::level()) GMM_WARNING_MSG(2, thestr) } 
+#else
+# define GMM_WARNING1(thestr) {}
+#endif
+
+#if GMM_WARNING_LEVEL > 2
+# define GMM_WARNING3(thestr)                                           \
+  { if (3 <= gmm::warning_level::level()) GMM_WARNING_MSG(3, thestr) } 
+#else
+# define GMM_WARNING1(thestr) {}
+#endif
+
+#if GMM_WARNING_LEVEL > 3
+# define GMM_WARNING4(thestr)                                           \
+  { if (4 <= gmm::warning_level::level()) GMM_WARNING_MSG(4, thestr) } 
+#else
+# define GMM_WARNING1(thestr) {}
+#endif
+
+/* *********************************************************************** */
+/*	Getfem++ traces.                         			   */
+/* *********************************************************************** */
+
+  // This allows to dynamically hide traces
+  struct traces_level {
+    static int level(int l = -2)
+    { static int level_ = 3; return (l != -2) ? (level_ = l) : level_; }
+  };
+
+  inline void set_traces_level(int l) { traces_level::level(std::max(0,l)); }
+
+  // This allow not too compile some Warnings
+#ifndef GMM_TRACES_LEVEL
+# define GMM_TRACES_LEVEL 3
+#endif
+
+  // Traces levels : 0 always printed
+  //                 1 Susceptible to occur once in a program.
+  //                 2 Susceptible to occur occasionnaly in a program (10).
+  //                 3 Susceptible to occur often (100).
+  //                 4 Susceptible to occur very often (>1000).
+
+#define GMM_TRACE_MSG_MPI     // for Parallelized version
+#define GMM_TRACE_MSG(level_, thestr)  {			       \
+    GMM_TRACE_MSG_MPI {						       \
+      std::stringstream msg;                                           \
+      msg << "Trace " << level_ << " in "__FILE__ << ", line "         \
+          << __LINE__ << ": " << thestr				       \
+          << ends;						       \
+      std::cout << msg.str() << std::endl;			       \
+    }                                                                  \
+  }        
+
+#define GMM_TRACE0(thestr) GMM_TRACE_MSG(0, thestr)
+
+#if GMM_TRACES_LEVEL > 0
+# define GMM_TRACE1(thestr)						\
+  { if (1 <= gmm::traces_level::level()) GMM_TRACE_MSG(1, thestr) }
+#else
+# define GMM_TRACE1(thestr) {}
+#endif
+  
+#if GMM_TRACES_LEVEL > 1
+# define GMM_TRACE2(thestr)						\
+  { if (2 <= gmm::traces_level::level()) GMM_TRACE_MSG(2, thestr) } 
+#else
+# define GMM_TRACE2(thestr) {}
+#endif
+  
+#if GMM_TRACES_LEVEL > 2
+# define GMM_TRACE3(thestr)						\
+  { if (3 <= gmm::traces_level::level()) GMM_TRACE_MSG(3, thestr) } 
+#else
+# define GMM_TRACE3(thestr) {}
+#endif
+  
+#if GMM_TRACES_LEVEL > 3
+# define GMM_TRACE4(thestr)						\
+  { if (4 <= gmm::traces_level::level()) GMM_TRACE_MSG(4, thestr) } 
+#else
+# define GMM_TRACE4(thestr) {}
+#endif
+  
+  
+  /* ********************************************************************* */
+  /*    Definitions for compatibility with old versions.        	   */
+  /* ********************************************************************* */ 
+  
+  using std::invalid_argument;
+  
+  struct dimension_error : public std::logic_error
+  { dimension_error(const std::string& w): std::logic_error(w) {} };
+  struct file_not_found_error : public std::logic_error
+  { file_not_found_error(const std::string& w): std::logic_error (w) {} };
+  struct internal_error : public std::logic_error
+  { internal_error(const std::string& w): std::logic_error(w) {} };
+  struct failure_error : public std::logic_error
+  { failure_error(const std::string& w): std::logic_error (w) {} };
+  struct not_linear_error : public std::logic_error
+  { not_linear_error(const std::string& w): std::logic_error (w) {} };
+  struct to_be_done_error : public std::logic_error
+  { to_be_done_error(const std::string& w): std::logic_error (w) {} };
+
+#define GMM_STANDARD_CATCH_ERROR   catch(std::logic_error e)	\
+    {								\
+      cerr << "============================================\n";	\
+      cerr << "|      An error has been detected !!!      |\n";	\
+      cerr << "============================================\n";	\
+      cerr << e.what() << endl << endl;				\
+      exit(1);							\
+    }								\
+  catch(std::runtime_error e)					\
+    {								\
+      cerr << "============================================\n";	\
+      cerr << "|      An error has been detected !!!      |\n";	\
+      cerr << "============================================\n";	\
+      cerr << e.what() << endl << endl;				\
+      exit(1);							\
+    }								\
+  catch(std::bad_alloc) {					\
+    cerr << "============================================\n";	\
+    cerr << "|  A bad allocation has been detected !!!  |\n";	\
+    cerr << "============================================\n";	\
+    exit(1);							\
+  }								\
+  catch(std::bad_typeid) {					\
+    cerr << "============================================\n";	\
+    cerr << "|  A bad typeid     has been detected !!!  |\n";	\
+    cerr << "============================================\n";	\
+    exit(1);							\
+  }								\
+  catch(std::bad_exception) {					\
+    cerr << "============================================\n";	\
+    cerr << "|  A bad exception  has been detected !!!  |\n";	\
+    cerr << "============================================\n";	\
+    exit(1);							\
+  }								\
+  catch(std::bad_cast) {					\
+    cerr << "============================================\n";	\
+    cerr << "|    A bad cast  has been detected !!!     |\n";	\
+    cerr << "============================================\n";	\
+    exit(1);							\
+  }								\
+  catch(...) {							\
+    cerr << "============================================\n";	\
+    cerr << "|  An unknown error has been detected !!!  |\n";	\
+    cerr << "============================================\n";	\
+    exit(1);							\
+  }
+  //   catch(ios_base::failure) { 
+  //     cerr << "============================================\n";
+  //     cerr << "| A ios_base::failure has been detected !!!|\n";
+  //     cerr << "============================================\n";
+  //     exit(1);
+  //   } 
+
+#if defined(__GNUC__) && (__GNUC__ > 3)
+# define GMM_SET_EXCEPTION_DEBUG				\
+  std::set_terminate(__gnu_cxx::__verbose_terminate_handler);
+#else
+# define GMM_SET_EXCEPTION_DEBUG
+#endif
+
+}
+
+
+#endif /* GMM_EXCEPT_H__ */
diff --git a/Contrib/gmm/gmm_inoutput.h b/Contrib/gmm/gmm_inoutput.h
new file mode 100755
index 0000000..e2455d1
--- /dev/null
+++ b/Contrib/gmm/gmm_inoutput.h
@@ -0,0 +1,1131 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_inoutput.h
+   @author Yves Renard <Yves.Renard at insa-lyon.fr>
+   @author Julien Pommier <Julien.Pommier at insa-toulouse.fr>
+   @date July 8, 2003.
+   @brief Input/output on sparse matrices
+
+   Support Harwell-Boeing and Matrix-Market formats.
+*/
+#ifndef GMM_INOUTPUT_H
+#define GMM_INOUTPUT_H
+
+#include <stdio.h>
+#include "gmm_kernel.h"
+namespace gmm {
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  Functions to read and write Harwell Boeing format.                   */
+  /*                                                                       */
+  /*************************************************************************/
+
+  // Fri Aug 15 16:29:47 EDT 1997
+  // 
+  //                      Harwell-Boeing File I/O in C
+  //                               V. 1.0
+  // 
+  //          National Institute of Standards and Technology, MD.
+  //                            K.A. Remington
+  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+  //                                NOTICE
+  //
+  // Permission to use, copy, modify, and distribute this software and
+  // its documentation for any purpose and without fee is hereby granted
+  // provided that the above copyright notice appear in all copies and
+  // that both the copyright notice and this permission notice appear in
+  // supporting documentation.
+  //
+  // Neither the Author nor the Institution (National Institute of Standards
+  // and Technology) make any representations about the suitability of this 
+  // software for any purpose. This software is provided "as is" without 
+  // expressed or implied warranty.
+  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+  inline void IOHBTerminate(const char *a) { GMM_ASSERT1(false, a);}
+
+  inline bool is_complex_double__(std::complex<double>) { return true; }
+  inline bool is_complex_double__(double) { return false; }
+
+  inline int ParseIfmt(const char *fmt, int* perline, int* width) {
+    if (SECURE_NONCHAR_SSCANF(fmt, " (%dI%d)", perline, width) != 2) {
+      *perline = 1;
+      int s = SECURE_NONCHAR_SSCANF(fmt, " (I%d)", width);
+      GMM_ASSERT1(s == 1, "invalid HB I-format: " << fmt);
+    }
+    return *width;
+  }
+  
+  inline int ParseRfmt(const char *fmt, int* perline, int* width,
+		       int* prec, int* flag) {
+    char p;
+    *perline = *width = *flag = *prec = 0;
+#ifdef GMM_SECURE_CRT
+    if (sscanf_s(fmt, " (%d%c%d.%d)", perline, &p, sizeof(char), width, prec)
+	< 3 || !strchr("PEDF", p))
+#else
+    if (sscanf(fmt, " (%d%c%d.%d)", perline, &p, width, prec) < 3
+	|| !strchr("PEDF", p))
+#endif
+	{
+      *perline = 1;
+#ifdef GMM_SECURE_CRT
+      int s = sscanf_s(fmt, " (%c%d.%d)", &p, sizeof(char), width, prec);
+#else
+      int s = sscanf(fmt, " (%c%d.%d)", &p, width, prec);
+#endif
+      GMM_ASSERT1(s>=2 && strchr("PEDF",p), "invalid HB REAL format: " << fmt);
+    }
+    *flag = p;
+    return *width;
+  }
+      
+  /** matrix input/output for Harwell-Boeing format */
+  struct HarwellBoeing_IO {
+    int nrows() const { return Nrow; }
+    int ncols() const { return Ncol; }
+    int nnz() const { return Nnzero; }
+    int is_complex() const { return Type[0] == 'C'; }
+    int is_symmetric() const { return Type[1] == 'S'; }
+    int is_hermitian() const { return Type[1] == 'H'; }
+    HarwellBoeing_IO() { clear(); }
+    HarwellBoeing_IO(const char *filename) { clear(); open(filename); }
+    ~HarwellBoeing_IO() { close(); }
+    /** open filename and reads header */
+    void open(const char *filename);
+    /** read the opened file */
+    template <typename T, int shift> void read(csc_matrix<T, shift>& A);
+    template <typename MAT> void read(MAT &M) IS_DEPRECATED;
+    template <typename T, int shift>
+    static void write(const char *filename, const csc_matrix<T, shift>& A);
+    template <typename T, int shift>
+    static void write(const char *filename, const csc_matrix<T, shift>& A,
+		      const std::vector<T> &rhs);
+    template <typename T, typename INDI, typename INDJ, int shift> 
+    static void write(const char *filename,
+		      const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A);
+    template <typename T, typename INDI, typename INDJ, int shift> 
+    static void write(const char *filename,
+		      const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A,
+		      const std::vector<T> &rhs);
+
+    /** static method for saving the matrix */
+    template <typename MAT> static void write(const char *filename,
+					      const MAT& A) IS_DEPRECATED;
+  private:
+    FILE *f;
+    char Title[73], Key[9], Rhstype[4], Type[4];
+    int Nrow, Ncol, Nnzero, Nrhs;
+    char Ptrfmt[17], Indfmt[17], Valfmt[21], Rhsfmt[21];
+    int Ptrcrd, Indcrd, Valcrd, Rhscrd; 
+    int lcount;
+
+
+    void close() { if (f) fclose(f); clear(); }
+    void clear() { 
+      Nrow = Ncol = Nnzero = Nrhs = 0; f = 0; lcount = 0;
+      memset(Type, 0, sizeof Type); 
+      memset(Key, 0, sizeof Key); 
+      memset(Title, 0, sizeof Title); 
+    }
+    char *getline(char *buf) { 
+      fgets(buf, BUFSIZ, f); ++lcount;
+      int s = SECURE_NONCHAR_SSCANF(buf,"%*s");
+      GMM_ASSERT1(s >= 0, "blank line in HB file at line " << lcount);
+      return buf;
+    }
+
+    int substrtoi(const char *p, size_type len) {
+      char s[100]; len = std::min(len, sizeof s - 1);
+      SECURE_STRNCPY(s, 100, p, len); s[len] = 0; return atoi(s);
+    }
+    double substrtod(const char *p, size_type len, int Valflag) {
+      char s[100]; len = std::min(len, sizeof s - 1);
+      SECURE_STRNCPY(s, 100, p, len); s[len] = 0;
+      if ( Valflag != 'F' && !strchr(s,'E')) {
+	/* insert a char prefix for exp */
+	int last = strlen(s);
+	for (int j=last+1;j>=0;j--) {
+	  s[j] = s[j-1];
+	  if ( s[j] == '+' || s[j] == '-' ) {
+	    s[j-1] = Valflag;                    
+	    break;
+	  }
+	}
+      }
+      return atof(s);
+    }
+    template <typename IND_TYPE>   
+    int readHB_data(IND_TYPE colptr[], IND_TYPE rowind[], 
+		    double val[]) {
+      /***********************************************************************/
+      /*  This function opens and reads the specified file, interpreting its */
+      /*  contents as a sparse matrix stored in the Harwell/Boeing standard  */
+      /*  format and creating compressed column storage scheme vectors to    */
+      /*  hold the index and nonzero value information.                      */
+      /*                                                                     */
+      /*    ----------                                                       */
+      /*    **CAVEAT**                                                       */
+      /*    ----------                                                       */
+      /*  Parsing real formats from Fortran is tricky, and this file reader  */
+      /*  does not claim to be foolproof.   It has been tested for cases     */
+      /*  when the real values are printed consistently and evenly spaced on */
+      /*  each line, with Fixed (F), and Exponential (E or D) formats.       */
+      /*                                                                     */
+      /*  **  If the input file does not adhere to the H/B format, the  **   */
+      /*  **             results will be unpredictable.                 **   */
+      /*                                                                     */
+      /***********************************************************************/
+      int i,ind,col,offset,count;
+      int Ptrperline, Ptrwidth, Indperline, Indwidth;
+      int Valperline, Valwidth, Valprec, Nentries;
+      int Valflag;           /* Indicates 'E','D', or 'F' float format */
+      char line[BUFSIZ];
+
+      /*  Parse the array input formats from Line 3 of HB file  */
+      ParseIfmt(Ptrfmt,&Ptrperline,&Ptrwidth);
+      ParseIfmt(Indfmt,&Indperline,&Indwidth);
+      if ( Type[0] != 'P' ) {          /* Skip if pattern only  */
+	ParseRfmt(Valfmt,&Valperline,&Valwidth,&Valprec,&Valflag);
+      }
+
+      cout << "Valwidth = " << Valwidth << endl; getchar();
+    
+      /*  Read column pointer array:   */
+      offset = 0;         /* if base 0 storage is declared (via macro def),  */
+      /* then storage entries are offset by 1            */
+    
+      for (count = 0, i=0;i<Ptrcrd;i++) {
+	getline(line);
+	for (col = 0, ind = 0;ind<Ptrperline;ind++) {
+	  if (count > Ncol) break;
+	  colptr[count] = substrtoi(line+col,Ptrwidth)-offset;
+	  count++; col += Ptrwidth;
+	}
+      }
+    
+      /*  Read row index array:  */    
+      for (count = 0, i=0;i<Indcrd;i++) {
+	getline(line);
+	for (col = 0, ind = 0;ind<Indperline;ind++) {
+	  if (count == Nnzero) break;
+	  rowind[count] = substrtoi(line+col,Indwidth)-offset;
+	  count++; col += Indwidth;
+	}
+      }
+    
+      /*  Read array of values:  */
+      if ( Type[0] != 'P' ) {          /* Skip if pattern only  */
+	if ( Type[0] == 'C' ) Nentries = 2*Nnzero;
+	else Nentries = Nnzero;
+      
+	count = 0;
+	for (i=0;i<Valcrd;i++) {
+	  getline(line);
+	  if (Valflag == 'D')  {
+            // const_cast Due to aCC excentricity
+	    char *p;
+	    while( (p = const_cast<char *>(strchr(line,'D')) )) *p = 'E';
+	  }
+	  for (col = 0, ind = 0;ind<Valperline;ind++) {
+	    if (count == Nentries) break;
+	    val[count] = substrtod(line+col, Valwidth, Valflag);
+	    count++; col += Valwidth;
+	  }
+	}
+      }
+      return 1;
+    }
+  };
+  
+  inline void HarwellBoeing_IO::open(const char *filename) {
+    int Totcrd,Neltvl,Nrhsix;
+    char line[BUFSIZ];
+    close();
+    SECURE_FOPEN(&f, filename, "r");
+    GMM_ASSERT1(f, "could not open " << filename);
+    /* First line: */
+#ifdef GMM_SECURE_CRT
+    sscanf_s(getline(line), "%c%s", Title, 72, Key, 8);
+#else
+    sscanf(getline(line), "%72c%8s", Title, Key);
+#endif
+    Key[8] = Title[72] = 0;
+    /* Second line: */
+    Totcrd = Ptrcrd = Indcrd = Valcrd = Rhscrd = 0;
+    SECURE_NONCHAR_SSCANF(getline(line), "%d%d%d%d%d", &Totcrd, &Ptrcrd,
+			  &Indcrd, &Valcrd, &Rhscrd);
+    
+    /* Third line: */
+    Nrow = Ncol = Nnzero = Neltvl = 0;
+#ifdef GMM_SECURE_CRT
+    if (sscanf_s(getline(line), "%c%d%d%d%d", Type, 3, &Nrow, &Ncol, &Nnzero,
+		 &Neltvl) < 1)
+#else
+    if (sscanf(getline(line), "%3c%d%d%d%d", Type, &Nrow, &Ncol, &Nnzero,
+	       &Neltvl) < 1)
+#endif
+      IOHBTerminate("Invalid Type info, line 3 of Harwell-Boeing file.\n");
+    for (size_type i = 0; i < 3; ++i) Type[i] = toupper(Type[i]);
+    
+      /*  Fourth line:  */
+#ifdef GMM_SECURE_CRT
+    if ( sscanf_s(getline(line), "%c%c%c%c",Ptrfmt, 16,Indfmt, 16,Valfmt,
+		  20,Rhsfmt, 20) < 3)
+#else
+    if ( sscanf(getline(line), "%16c%16c%20c%20c",Ptrfmt,Indfmt,Valfmt,
+		Rhsfmt) < 3)
+#endif
+      IOHBTerminate("Invalid format info, line 4 of Harwell-Boeing file.\n"); 
+    Ptrfmt[16] = Indfmt[16] = Valfmt[20] = Rhsfmt[20] = 0;
+    
+    /*  (Optional) Fifth line: */
+    if (Rhscrd != 0 ) { 
+      Nrhs = Nrhsix = 0;
+#ifdef GMM_SECURE_CRT
+      if ( sscanf_s(getline(line), "%c%d%d", Rhstype, 3, &Nrhs, &Nrhsix) != 1)
+#else
+      if ( sscanf(getline(line), "%3c%d%d", Rhstype, &Nrhs, &Nrhsix) != 1)
+#endif
+	IOHBTerminate("Invalid RHS type information, line 5 of"
+		      " Harwell-Boeing file.\n");
+    }
+  }
+
+  /* only valid for double and complex<double> csc matrices */
+  template <typename T, int shift> void
+  HarwellBoeing_IO::read(csc_matrix<T, shift>& A) {
+
+    typedef typename csc_matrix<T, shift>::IND_TYPE IND_TYPE;
+
+    GMM_ASSERT1(f, "no file opened!");
+    GMM_ASSERT1(Type[0] != 'P',
+		"Bad HB matrix format (pattern matrices not supported)");
+    GMM_ASSERT1(!is_complex_double__(T()) || Type[0] != 'R',
+		"Bad HB matrix format (file contains a REAL matrix)");
+    GMM_ASSERT1(is_complex_double__(T()) || Type[0] != 'C',
+		"Bad HB matrix format (file contains a COMPLEX matrix)");
+    if (A.pr) { delete[] A.pr; delete[] A.ir; delete[] A.jc; }
+    A.nc = ncols(); A.nr = nrows();
+    A.pr = 0;
+    A.jc = new IND_TYPE[ncols()+1];
+    A.ir = new IND_TYPE[nnz()];
+    A.pr = new T[nnz()];
+    readHB_data(A.jc, A.ir, (double*)A.pr);
+    for (int i = 0; i <= ncols(); ++i) { A.jc[i] += shift; A.jc[i] -= 1; }
+    for (int i = 0; i < nnz(); ++i)    { A.ir[i] += shift; A.ir[i] -= 1; }
+  }
+
+  template <typename MAT> void 
+  HarwellBoeing_IO::read(MAT &M) {
+    csc_matrix<typename gmm::linalg_traits<MAT>::value_type> csc;
+    read(csc); 
+    resize(M, mat_nrows(csc), mat_ncols(csc));
+    copy(csc, M);
+  }
+  
+  template <typename IND_TYPE> 
+  inline int writeHB_mat_double(const char* filename, int M, int N, int nz,
+				const IND_TYPE colptr[],
+				const IND_TYPE rowind[], 
+				const double val[], int Nrhs,
+				const double rhs[], const double guess[],
+				const double exact[], const char* Title,
+				const char* Key, const char* Type, 
+				const char* Ptrfmt, const char* Indfmt,
+				const char* Valfmt, const char* Rhsfmt,
+				const char* Rhstype, int shift) {
+    /************************************************************************/
+    /*  The writeHB function opens the named file and writes the specified  */
+    /*  matrix and optional right-hand-side(s) to that file in              */
+    /*  Harwell-Boeing format.                                              */
+    /*                                                                      */
+    /*  For a description of the Harwell Boeing standard, see:              */
+    /*            Duff, et al.,  ACM TOMS Vol.15, No.1, March 1989          */
+    /*                                                                      */
+    /************************************************************************/
+    FILE *out_file;
+    int i, entry, offset, j, acount, linemod;
+    int totcrd, ptrcrd, indcrd, valcrd, rhscrd;
+    int nvalentries, nrhsentries;
+    int Ptrperline, Ptrwidth, Indperline, Indwidth;
+    int Rhsperline, Rhswidth, Rhsprec, Rhsflag;
+    int Valperline, Valwidth, Valprec;
+    int Valflag;           /* Indicates 'E','D', or 'F' float format */
+    char pformat[16],iformat[16],vformat[19],rformat[19];
+    
+    if ( Type[0] == 'C' )
+      { nvalentries = 2*nz; nrhsentries = 2*M; }
+    else
+      { nvalentries = nz; nrhsentries = M; }
+    
+    if ( filename != NULL ) {
+      SECURE_FOPEN(&out_file, filename, "w");
+      GMM_ASSERT1(out_file != NULL, "Error: Cannot open file: " << filename);
+    } else out_file = stdout;
+    
+    if ( Ptrfmt == NULL ) Ptrfmt = "(8I10)";
+    ParseIfmt(Ptrfmt, &Ptrperline, &Ptrwidth);
+    SECURE_SPRINTF1(pformat,sizeof(pformat),"%%%dd",Ptrwidth);
+    ptrcrd = (N+1)/Ptrperline;
+    if ( (N+1)%Ptrperline != 0) ptrcrd++;
+    
+    if ( Indfmt == NULL ) Indfmt =  Ptrfmt;
+    ParseIfmt(Indfmt, &Indperline, &Indwidth);
+    SECURE_SPRINTF1(iformat,sizeof(iformat), "%%%dd",Indwidth);
+    indcrd = nz/Indperline;
+    if ( nz%Indperline != 0) indcrd++;
+    
+    if ( Type[0] != 'P' ) {          /* Skip if pattern only  */
+      if ( Valfmt == NULL ) Valfmt = "(4E21.13)";
+      ParseRfmt(Valfmt, &Valperline, &Valwidth, &Valprec, &Valflag);
+      if (Valflag == 'D') *strchr(Valfmt,'D') = 'E';
+      if (Valflag == 'F')
+	SECURE_SPRINTF2(vformat, sizeof(vformat), "%% %d.%df", Valwidth,
+			Valprec);
+      else
+	SECURE_SPRINTF2(vformat, sizeof(vformat), "%% %d.%dE", Valwidth,
+			Valprec);
+      valcrd = nvalentries/Valperline;
+      if ( nvalentries%Valperline != 0) valcrd++;
+    } else valcrd = 0;
+    
+    if ( Nrhs > 0 ) {
+      if ( Rhsfmt == NULL ) Rhsfmt = Valfmt;
+      ParseRfmt(Rhsfmt,&Rhsperline,&Rhswidth,&Rhsprec, &Rhsflag);
+      if (Rhsflag == 'F')
+	SECURE_SPRINTF2(rformat,sizeof(rformat), "%% %d.%df",Rhswidth,Rhsprec);
+      else
+	SECURE_SPRINTF2(rformat,sizeof(rformat), "%% %d.%dE",Rhswidth,Rhsprec);
+      if (Rhsflag == 'D') *strchr(Rhsfmt,'D') = 'E';
+      rhscrd = nrhsentries/Rhsperline; 
+      if ( nrhsentries%Rhsperline != 0) rhscrd++;
+      if ( Rhstype[1] == 'G' ) rhscrd+=rhscrd;
+      if ( Rhstype[2] == 'X' ) rhscrd+=rhscrd;
+      rhscrd*=Nrhs;
+    } else rhscrd = 0;
+    
+    totcrd = 4+ptrcrd+indcrd+valcrd+rhscrd;
+    
+    
+    /*  Print header information:  */
+    
+    fprintf(out_file,"%-72s%-8s\n%14d%14d%14d%14d%14d\n",Title, Key, totcrd,
+	    ptrcrd, indcrd, valcrd, rhscrd);
+    fprintf(out_file,"%3s%11s%14d%14d%14d%14d\n",Type,"          ", M, N, nz, 0);
+    fprintf(out_file,"%-16s%-16s%-20s", Ptrfmt, Indfmt, Valfmt);
+    if ( Nrhs != 0 ) {
+      /* Print Rhsfmt on fourth line and                              */
+      /*  optional fifth header line for auxillary vector information:*/
+      fprintf(out_file,"%-20s\n%-14s%d\n",Rhsfmt,Rhstype,Nrhs);
+    }
+    else
+      fprintf(out_file,"\n");
+    
+    offset = 1 - shift;  /* if base 0 storage is declared (via macro def), */
+    /* then storage entries are offset by 1           */
+    
+    /*  Print column pointers:   */
+    for (i = 0; i < N+1; i++) {
+      entry = colptr[i]+offset;
+      fprintf(out_file,pformat,entry);
+      if ( (i+1)%Ptrperline == 0 ) fprintf(out_file,"\n");
+    }
+    
+    if ( (N+1) % Ptrperline != 0 ) fprintf(out_file,"\n");
+    
+    /*  Print row indices:       */
+    for (i=0;i<nz;i++) {
+      entry = rowind[i]+offset;
+      fprintf(out_file,iformat,entry);
+      if ( (i+1)%Indperline == 0 ) fprintf(out_file,"\n");
+    }
+    
+    if ( nz % Indperline != 0 ) fprintf(out_file,"\n");
+    
+    /*  Print values:            */
+    
+    if ( Type[0] != 'P' ) {          /* Skip if pattern only  */
+      for (i=0;i<nvalentries;i++) {
+	fprintf(out_file,vformat,val[i]);
+	if ( (i+1)%Valperline == 0 ) fprintf(out_file,"\n");
+      }
+      
+      if ( nvalentries % Valperline != 0 ) fprintf(out_file,"\n");
+      
+      /*  Print right hand sides:  */
+      acount = 1;
+      linemod=0;
+      if ( Nrhs > 0 ) {
+	for (j=0;j<Nrhs;j++) {
+	  for (i=0;i<nrhsentries;i++) {
+	    fprintf(out_file,rformat,rhs[i] /* *Rhswidth */);
+	    if ( acount++%Rhsperline == linemod ) fprintf(out_file,"\n");
+	  }
+	  if ( acount%Rhsperline != linemod ) {
+	    fprintf(out_file,"\n");
+	    linemod = (acount-1)%Rhsperline;
+	  }
+	  if ( Rhstype[1] == 'G' ) {
+	    for (i=0;i<nrhsentries;i++) {
+	      fprintf(out_file,rformat,guess[i] /* *Rhswidth */);
+	      if ( acount++%Rhsperline == linemod ) fprintf(out_file,"\n");
+	    }
+	    if ( acount%Rhsperline != linemod ) {
+	      fprintf(out_file,"\n");
+	      linemod = (acount-1)%Rhsperline;
+	    }
+	  }
+	  if ( Rhstype[2] == 'X' ) {
+	    for (i=0;i<nrhsentries;i++) {
+	      fprintf(out_file,rformat,exact[i] /* *Rhswidth */);
+	      if ( acount++%Rhsperline == linemod ) fprintf(out_file,"\n");
+	    }
+	    if ( acount%Rhsperline != linemod ) {
+	      fprintf(out_file,"\n");
+	      linemod = (acount-1)%Rhsperline;
+	    }
+	  }
+	}
+      }
+    }
+    int s = fclose(out_file);
+    GMM_ASSERT1(s == 0, "Error closing file in writeHB_mat_double().");
+    return 1;
+  }
+  
+  template <typename T, int shift> void
+  HarwellBoeing_IO::write(const char *filename,
+			  const csc_matrix<T, shift>& A) {
+    write(filename, csc_matrix_ref<T*, unsigned*, unsigned *, shift>
+	  (A.pr, A.ir, A.jc, A.nr, A.nc));
+  }
+
+  template <typename T, int shift> void
+  HarwellBoeing_IO::write(const char *filename,
+			  const csc_matrix<T, shift>& A,
+			  const std::vector<T> &rhs) {
+    write(filename, csc_matrix_ref<T*, unsigned*, unsigned *, shift>
+	  (A.pr, A.ir, A.jc, A.nr, A.nc), rhs);
+  }
+
+  template <typename T, typename INDI, typename INDJ, int shift> void
+  HarwellBoeing_IO::write(const char *filename,
+			  const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A) {
+    const char *t = 0;    
+    if (is_complex_double__(T()))
+      if (mat_nrows(A) == mat_ncols(A)) t = "CUA"; else t = "CRA";
+    else
+      if (mat_nrows(A) == mat_ncols(A)) t = "RUA"; else t = "RRA";
+    writeHB_mat_double(filename, mat_nrows(A), mat_ncols(A),
+		       A.jc[mat_ncols(A)], A.jc, A.ir,
+		       (const double *)A.pr,
+		       0, 0, 0, 0, "GETFEM++ CSC MATRIX", "CSCMAT",
+		       t, 0, 0, 0, 0, "F", shift);
+  }
+
+  template <typename T, typename INDI, typename INDJ, int shift> void
+  HarwellBoeing_IO::write(const char *filename,
+			  const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A,
+			  const std::vector<T> &rhs) {
+    const char *t = 0;
+    if (is_complex_double__(T()))
+      if (mat_nrows(A) == mat_ncols(A)) t = "CUA"; else t = "CRA";
+    else
+      if (mat_nrows(A) == mat_ncols(A)) t = "RUA"; else t = "RRA";
+    int Nrhs = gmm::vect_size(rhs) / mat_nrows(A);
+    writeHB_mat_double(filename, mat_nrows(A), mat_ncols(A),
+		       A.jc[mat_ncols(A)], A.jc, A.ir,
+		       (const double *)A.pr,
+		       Nrhs, (const double *)(&rhs[0]), 0, 0,
+		       "GETFEM++ CSC MATRIX", "CSCMAT",
+		       t, 0, 0, 0, 0, "F  ", shift);
+  }
+
+  
+  template <typename MAT> void
+  HarwellBoeing_IO::write(const char *filename, const MAT& A) {
+    gmm::csc_matrix<typename gmm::linalg_traits<MAT>::value_type> 
+      tmp(gmm::mat_nrows(A), gmm::mat_ncols(A));
+    gmm::copy(A,tmp); 
+    HarwellBoeing_IO::write(filename, tmp);
+  }
+
+  /** save a "double" or "std::complex<double>" csc matrix into a
+      HarwellBoeing file
+  */
+  template <typename T, int shift> inline void
+  Harwell_Boeing_save(const std::string &filename,
+		      const csc_matrix<T, shift>& A)
+  { HarwellBoeing_IO::write(filename.c_str(), A); }
+
+  /** save a reference on "double" or "std::complex<double>" csc matrix
+      into a HarwellBoeing file
+  */
+  template <typename T, typename INDI, typename INDJ, int shift> inline void
+  Harwell_Boeing_save(const std::string &filename,
+		      const csc_matrix_ref<T, INDI, INDJ, shift>& A)
+  { HarwellBoeing_IO::write(filename.c_str(), A); }
+
+  /** save a "double" or "std::complex<double>" generic matrix
+      into a HarwellBoeing file making a copy in a csc matrix
+  */
+  template <typename MAT> inline void
+  Harwell_Boeing_save(const std::string &filename, const MAT& A) {
+    gmm::csc_matrix<typename gmm::linalg_traits<MAT>::value_type> 
+      tmp(gmm::mat_nrows(A), gmm::mat_ncols(A));
+    gmm::copy(A, tmp); 
+    HarwellBoeing_IO::write(filename.c_str(), tmp);
+  }
+
+  template <typename MAT, typename VECT> inline void
+  Harwell_Boeing_save(const std::string &filename, const MAT& A,
+		      const VECT &RHS) {
+    typedef typename gmm::linalg_traits<MAT>::value_type T;
+    gmm::csc_matrix<T> tmp(gmm::mat_nrows(A), gmm::mat_ncols(A));
+    gmm::copy(A, tmp);
+    std::vector<T> tmprhs(gmm::vect_size(RHS));
+    gmm::copy(RHS, tmprhs);
+    HarwellBoeing_IO::write(filename.c_str(), tmp, tmprhs);
+  }
+
+  /** load a "double" or "std::complex<double>" csc matrix from a
+      HarwellBoeing file
+  */
+  template <typename T, int shift> void
+  Harwell_Boeing_load(const std::string &filename, csc_matrix<T, shift>& A) {
+    HarwellBoeing_IO h(filename.c_str()); h.read(A);
+  }
+
+  /** load a "double" or "std::complex<double>" generic matrix from a
+      HarwellBoeing file
+  */
+  template <typename MAT> void
+  Harwell_Boeing_load(const std::string &filename, MAT& A) {
+    csc_matrix<typename gmm::linalg_traits<MAT>::value_type> csc;
+    Harwell_Boeing_load(filename, csc);
+    resize(A, mat_nrows(csc), mat_ncols(csc));
+    copy(csc, A);
+  }
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  Functions to read and write MatrixMarket format.                     */
+  /*                                                                       */
+  /*************************************************************************/
+
+  /* 
+   *   Matrix Market I/O library for ANSI C
+   *
+   *   See http://math.nist.gov/MatrixMarket for details.
+   *
+   *
+   */
+
+#define MM_MAX_LINE_LENGTH 1025
+#define MatrixMarketBanner "%%MatrixMarket"
+#define MM_MAX_TOKEN_LENGTH 64
+
+  typedef char MM_typecode[4];
+
+  /******************* MM_typecode query functions *************************/
+
+#define mm_is_matrix(typecode)	        ((typecode)[0]=='M')
+  
+#define mm_is_sparse(typecode)	        ((typecode)[1]=='C')
+#define mm_is_coordinate(typecode)      ((typecode)[1]=='C')
+#define mm_is_dense(typecode)	        ((typecode)[1]=='A')
+#define mm_is_array(typecode)	        ((typecode)[1]=='A')
+  
+#define mm_is_complex(typecode)	        ((typecode)[2]=='C')
+#define mm_is_real(typecode)	        ((typecode)[2]=='R')
+#define mm_is_pattern(typecode)	        ((typecode)[2]=='P')
+#define mm_is_integer(typecode)         ((typecode)[2]=='I')
+  
+#define mm_is_symmetric(typecode)       ((typecode)[3]=='S')
+#define mm_is_general(typecode)	        ((typecode)[3]=='G')
+#define mm_is_skew(typecode)	        ((typecode)[3]=='K')
+#define mm_is_hermitian(typecode)       ((typecode)[3]=='H')
+  
+  /******************* MM_typecode modify fucntions ************************/
+
+#define mm_set_matrix(typecode)	        ((*typecode)[0]='M')
+#define mm_set_coordinate(typecode)	((*typecode)[1]='C')
+#define mm_set_array(typecode)	        ((*typecode)[1]='A')
+#define mm_set_dense(typecode)	        mm_set_array(typecode)
+#define mm_set_sparse(typecode)	        mm_set_coordinate(typecode)
+
+#define mm_set_complex(typecode)        ((*typecode)[2]='C')
+#define mm_set_real(typecode)	        ((*typecode)[2]='R')
+#define mm_set_pattern(typecode)        ((*typecode)[2]='P')
+#define mm_set_integer(typecode)        ((*typecode)[2]='I')
+
+
+#define mm_set_symmetric(typecode)      ((*typecode)[3]='S')
+#define mm_set_general(typecode)        ((*typecode)[3]='G')
+#define mm_set_skew(typecode)	        ((*typecode)[3]='K')
+#define mm_set_hermitian(typecode)      ((*typecode)[3]='H')
+
+#define mm_clear_typecode(typecode)     ((*typecode)[0]=(*typecode)[1]= \
+			       	        (*typecode)[2]=' ',(*typecode)[3]='G')
+
+#define mm_initialize_typecode(typecode) mm_clear_typecode(typecode)
+
+
+  /******************* Matrix Market error codes ***************************/
+
+
+#define MM_COULD_NOT_READ_FILE	11
+#define MM_PREMATURE_EOF		12
+#define MM_NOT_MTX				13
+#define MM_NO_HEADER			14
+#define MM_UNSUPPORTED_TYPE		15
+#define MM_LINE_TOO_LONG		16
+#define MM_COULD_NOT_WRITE_FILE	17
+
+
+  /******************** Matrix Market internal definitions *****************
+
+   MM_matrix_typecode: 4-character sequence
+
+	                object 	    sparse/   	data        storage 
+	                            dense     	type        scheme
+
+   string position:	 [0]        [1]		[2]         [3]
+
+   Matrix typecode:     M(atrix)    C(oord)	R(eal)      G(eneral)
+		                    A(array)    C(omplex)   H(ermitian)
+	                                        P(attern)   S(ymmetric)
+                                                I(nteger)   K(kew)
+
+  ***********************************************************************/
+
+#define MM_MTX_STR	   "matrix"
+#define MM_ARRAY_STR	   "array"
+#define MM_DENSE_STR	   "array"
+#define MM_COORDINATE_STR  "coordinate" 
+#define MM_SPARSE_STR	   "coordinate"
+#define MM_COMPLEX_STR	   "complex"
+#define MM_REAL_STR	   "real"
+#define MM_INT_STR	   "integer"
+#define MM_GENERAL_STR     "general"
+#define MM_SYMM_STR	   "symmetric"
+#define MM_HERM_STR	   "hermitian"
+#define MM_SKEW_STR	   "skew-symmetric"
+#define MM_PATTERN_STR     "pattern"
+
+  inline char  *mm_typecode_to_str(MM_typecode matcode) {
+    char buffer[MM_MAX_LINE_LENGTH];
+    const char *types[4] = {0,0,0,0};
+    /*    int error =0; */
+    /*   int i; */
+    
+    /* check for MTX type */
+    if (mm_is_matrix(matcode)) 
+      types[0] = MM_MTX_STR;
+    /*
+      else
+      error=1;
+    */
+    /* check for CRD or ARR matrix */
+    if (mm_is_sparse(matcode))
+      types[1] = MM_SPARSE_STR;
+    else
+      if (mm_is_dense(matcode))
+        types[1] = MM_DENSE_STR;
+      else
+        return NULL;
+    
+    /* check for element data type */
+    if (mm_is_real(matcode))
+      types[2] = MM_REAL_STR;
+    else
+      if (mm_is_complex(matcode))
+        types[2] = MM_COMPLEX_STR;
+      else
+	if (mm_is_pattern(matcode))
+	  types[2] = MM_PATTERN_STR;
+	else
+	  if (mm_is_integer(matcode))
+	    types[2] = MM_INT_STR;
+	  else
+	    return NULL;
+    
+    
+    /* check for symmetry type */
+    if (mm_is_general(matcode))
+      types[3] = MM_GENERAL_STR;
+    else if (mm_is_symmetric(matcode))
+      types[3] = MM_SYMM_STR;
+    else if (mm_is_hermitian(matcode))
+      types[3] = MM_HERM_STR;
+    else  if (mm_is_skew(matcode))
+      types[3] = MM_SKEW_STR;
+    else
+      return NULL;
+    
+    SECURE_SPRINTF4(buffer, sizeof(buffer), "%s %s %s %s", types[0], types[1],
+		    types[2], types[3]);
+    return SECURE_STRDUP(buffer);
+    
+  }
+  
+  inline int mm_read_banner(FILE *f, MM_typecode *matcode) {
+    char line[MM_MAX_LINE_LENGTH];
+    char banner[MM_MAX_TOKEN_LENGTH];
+    char mtx[MM_MAX_TOKEN_LENGTH]; 
+    char crd[MM_MAX_TOKEN_LENGTH];
+    char data_type[MM_MAX_TOKEN_LENGTH];
+    char storage_scheme[MM_MAX_TOKEN_LENGTH];
+    char *p;
+    /*    int ret_code; */
+    
+    mm_clear_typecode(matcode);  
+    
+    if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL) 
+      return MM_PREMATURE_EOF;
+
+#ifdef GMM_SECURE_CRT
+    if (sscanf_s(line, "%s %s %s %s %s", banner, sizeof(banner),
+		 mtx, sizeof(mtx), crd, sizeof(crd), data_type,
+		 sizeof(data_type), storage_scheme,
+		 sizeof(storage_scheme)) != 5)
+#else
+	if (sscanf(line, "%s %s %s %s %s", banner, mtx, crd,
+		   data_type, storage_scheme) != 5)
+#endif
+      return MM_PREMATURE_EOF;
+
+    for (p=mtx; *p!='\0'; *p=tolower(*p),p++);  /* convert to lower case */
+    for (p=crd; *p!='\0'; *p=tolower(*p),p++);  
+    for (p=data_type; *p!='\0'; *p=tolower(*p),p++);
+    for (p=storage_scheme; *p!='\0'; *p=tolower(*p),p++);
+
+    /* check for banner */
+    if (strncmp(banner, MatrixMarketBanner, strlen(MatrixMarketBanner)) != 0)
+      return MM_NO_HEADER;
+
+    /* first field should be "mtx" */
+    if (strcmp(mtx, MM_MTX_STR) != 0)
+      return  MM_UNSUPPORTED_TYPE;
+    mm_set_matrix(matcode);
+
+
+    /* second field describes whether this is a sparse matrix (in coordinate
+       storgae) or a dense array */
+
+
+    if (strcmp(crd, MM_SPARSE_STR) == 0)
+      mm_set_sparse(matcode);
+    else
+      if (strcmp(crd, MM_DENSE_STR) == 0)
+	mm_set_dense(matcode);
+      else
+        return MM_UNSUPPORTED_TYPE;
+    
+
+    /* third field */
+
+    if (strcmp(data_type, MM_REAL_STR) == 0)
+      mm_set_real(matcode);
+    else
+      if (strcmp(data_type, MM_COMPLEX_STR) == 0)
+        mm_set_complex(matcode);
+      else
+	if (strcmp(data_type, MM_PATTERN_STR) == 0)
+	  mm_set_pattern(matcode);
+	else
+	  if (strcmp(data_type, MM_INT_STR) == 0)
+	    mm_set_integer(matcode);
+	  else
+	    return MM_UNSUPPORTED_TYPE;
+    
+
+    /* fourth field */
+
+    if (strcmp(storage_scheme, MM_GENERAL_STR) == 0)
+      mm_set_general(matcode);
+    else
+      if (strcmp(storage_scheme, MM_SYMM_STR) == 0)
+        mm_set_symmetric(matcode);
+      else
+	if (strcmp(storage_scheme, MM_HERM_STR) == 0)
+	  mm_set_hermitian(matcode);
+	else
+	  if (strcmp(storage_scheme, MM_SKEW_STR) == 0)
+	    mm_set_skew(matcode);
+	  else
+	    return MM_UNSUPPORTED_TYPE;
+        
+    return 0;
+  }
+
+  inline int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz ) {
+    char line[MM_MAX_LINE_LENGTH];
+    /* int ret_code;*/
+    int num_items_read;
+    
+    /* set return null parameter values, in case we exit with errors */
+    *M = *N = *nz = 0;
+    
+    /* now continue scanning until you reach the end-of-comments */
+    do {
+      if (fgets(line,MM_MAX_LINE_LENGTH,f) == NULL) 
+	return MM_PREMATURE_EOF;
+    } while (line[0] == '%');
+    
+    /* line[] is either blank or has M,N, nz */
+    if (SECURE_NONCHAR_SSCANF(line, "%d %d %d", M, N, nz) == 3) return 0;
+    else
+      do { 
+	num_items_read = SECURE_NONCHAR_FSCANF(f, "%d %d %d", M, N, nz); 
+	if (num_items_read == EOF) return MM_PREMATURE_EOF;
+      }
+      while (num_items_read != 3);
+    
+    return 0;
+  }
+
+
+  inline int mm_read_mtx_crd_data(FILE *f, int, int, int nz, int I[],
+				  int J[], double val[], MM_typecode matcode) {
+    int i;
+    if (mm_is_complex(matcode)) {
+      for (i=0; i<nz; i++)
+	if (SECURE_NONCHAR_FSCANF(f, "%d %d %lg %lg", &I[i], &J[i],
+				  &val[2*i], &val[2*i+1])
+	    != 4) return MM_PREMATURE_EOF;
+    }
+    else if (mm_is_real(matcode)) {
+      for (i=0; i<nz; i++) {
+	if (SECURE_NONCHAR_FSCANF(f, "%d %d %lg\n", &I[i], &J[i], &val[i])
+	    != 3) return MM_PREMATURE_EOF;
+	
+      }
+    }
+    else if (mm_is_pattern(matcode)) {
+      for (i=0; i<nz; i++)
+	if (SECURE_NONCHAR_FSCANF(f, "%d %d", &I[i], &J[i])
+	    != 2) return MM_PREMATURE_EOF;
+    }
+    else return MM_UNSUPPORTED_TYPE;
+
+    return 0;
+  }
+
+  inline int mm_write_mtx_crd(const char *fname, int M, int N, int nz,
+			      int I[], int J[], const double val[],
+			      MM_typecode matcode) {
+    FILE *f;
+    int i;
+    
+    if (strcmp(fname, "stdout") == 0) 
+      f = stdout;
+    else {
+      SECURE_FOPEN(&f, fname, "w");
+      if (f == NULL)
+        return MM_COULD_NOT_WRITE_FILE;
+    }
+    
+    /* print banner followed by typecode */
+    fprintf(f, "%s ", MatrixMarketBanner);
+    char *str = mm_typecode_to_str(matcode);
+    fprintf(f, "%s\n", str);
+    free(str);
+    
+    /* print matrix sizes and nonzeros */
+    fprintf(f, "%d %d %d\n", M, N, nz);
+    
+    /* print values */
+    if (mm_is_pattern(matcode))
+      for (i=0; i<nz; i++)
+	fprintf(f, "%d %d\n", I[i], J[i]);
+    else
+      if (mm_is_real(matcode))
+        for (i=0; i<nz; i++)
+	  fprintf(f, "%d %d %20.16g\n", I[i], J[i], val[i]);
+      else
+	if (mm_is_complex(matcode))
+	  for (i=0; i<nz; i++)
+            fprintf(f, "%d %d %20.16g %20.16g\n", I[i], J[i], val[2*i], 
+		    val[2*i+1]);
+	else {
+	  if (f != stdout) fclose(f);
+	  return MM_UNSUPPORTED_TYPE;
+	}
+    
+    if (f !=stdout) fclose(f); 
+    return 0;
+  }
+  
+
+  /** matrix input/output for MatrixMarket storage */
+  class MatrixMarket_IO {
+    FILE *f;
+    bool isComplex, isSymmetric, isHermitian;
+    int row, col, nz;
+    MM_typecode matcode;
+  public:
+    MatrixMarket_IO() : f(0) {}
+    MatrixMarket_IO(const char *filename) : f(0) { open(filename); }
+    ~MatrixMarket_IO() { if (f) fclose(f); f = 0; }
+
+    int nrows() const { return row; }
+    int ncols() const { return col; }
+    int nnz() const { return nz; }
+    int is_complex() const { return isComplex; }
+    int is_symmetric() const { return isSymmetric; }
+    int is_hermitian() const { return isHermitian; }
+
+    /* open filename and reads header */
+    void open(const char *filename);
+    /* read opened file */
+    template <typename Matrix> void read(Matrix &A);
+    /* write a matrix */
+    template <typename T, int shift> static void 
+    write(const char *filename, const csc_matrix<T, shift>& A);  
+    template <typename T, typename INDI, typename INDJ, int shift> static void 
+    write(const char *filename,
+	  const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A);  
+    template <typename MAT> static void 
+    write(const char *filename, const MAT& A);  
+  };
+
+  /** load a matrix-market file */
+  template <typename Matrix> inline void
+  MatrixMarket_load(const char *filename, Matrix& A) {
+    MatrixMarket_IO mm; mm.open(filename);
+    mm.read(A);
+  }
+  /** write a matrix-market file */
+  template <typename T, int shift> void
+  MatrixMarket_save(const char *filename, const csc_matrix<T, shift>& A) {
+    MatrixMarket_IO mm; mm.write(filename, A);
+  }
+
+  template <typename T, typename INDI, typename INDJ, int shift> inline void
+  MatrixMarket_save(const char *filename,
+		    const csc_matrix_ref<T, INDI, INDJ, shift>& A) {
+    MatrixMarket_IO mm; mm.write(filename, A);
+  }
+
+
+  inline void MatrixMarket_IO::open(const char *filename) {
+    if (f) { fclose(f); }
+    SECURE_FOPEN(&f, filename, "r");
+    GMM_ASSERT1(f, "Sorry, cannot open file " << filename);
+    int s1 = mm_read_banner(f, &matcode);
+    GMM_ASSERT1(s1 == 0, "Sorry, cannnot find the matrix market banner in "
+		<< filename);
+    int s2 = mm_is_coordinate(matcode), s3 = mm_is_matrix(matcode);
+    GMM_ASSERT1(s2 > 0 && s3 > 0,
+		"file is not coordinate storage or is not a matrix");
+    int s4 = mm_is_pattern(matcode);
+    GMM_ASSERT1(s4 == 0,
+	       "the file does only contain the pattern of a sparse matrix");
+    int s5 = mm_is_skew(matcode);
+    GMM_ASSERT1(s5 == 0, "not currently supporting skew symmetric");
+    isSymmetric = mm_is_symmetric(matcode) || mm_is_hermitian(matcode); 
+    isHermitian = mm_is_hermitian(matcode); 
+    isComplex =   mm_is_complex(matcode);
+    mm_read_mtx_crd_size(f, &row, &col, &nz);
+  }
+
+  template <typename Matrix> void MatrixMarket_IO::read(Matrix &A) {
+    typedef typename linalg_traits<Matrix>::value_type T;
+    GMM_ASSERT1(f, "no file opened!");
+    GMM_ASSERT1(!is_complex_double__(T()) || isComplex,
+		"Bad MM matrix format (complex matrix expected)");
+    GMM_ASSERT1(is_complex_double__(T()) || !isComplex,
+		"Bad MM matrix format (real matrix expected)");
+    A = Matrix(row, col);
+    gmm::clear(A);
+    
+    std::vector<int> I(nz), J(nz);
+    std::vector<typename Matrix::value_type> PR(nz);
+    mm_read_mtx_crd_data(f, row, col, nz, &I[0], &J[0],
+			 (double*)&PR[0], matcode);
+    
+    for (size_type i = 0; i < size_type(nz); ++i) A(I[i]-1, J[i]-1) = PR[i];
+  }
+
+  template <typename T, int shift> void 
+  MatrixMarket_IO::write(const char *filename, const csc_matrix<T, shift>& A) {
+    write(filename, csc_matrix_ref<T*,unsigned*,unsigned*,shift>
+	  (A.pr, A.ir, A.jc, A.nr, A.nc));
+  }
+
+  template <typename T, typename INDI, typename INDJ, int shift> void 
+  MatrixMarket_IO::write(const char *filename, 
+			 const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A) {
+    static MM_typecode t1 = {'M', 'C', 'R', 'G'};
+    static MM_typecode t2 = {'M', 'C', 'C', 'G'};
+    MM_typecode t;
+    
+    if (is_complex_double__(T())) std::copy(&(t2[0]), &(t2[0])+4, &(t[0]));
+    else std::copy(&(t1[0]), &(t1[0])+4, &(t[0]));
+    size_type nz = A.jc[mat_ncols(A)];
+    std::vector<int> I(nz), J(nz);
+    for (size_type j=0; j < mat_ncols(A); ++j) {      
+      for (size_type i = A.jc[j]; i < A.jc[j+1]; ++i) {
+	I[i] = A.ir[i] + 1 - shift;
+	J[i] = j + 1;
+      }
+    }
+    mm_write_mtx_crd(filename, mat_nrows(A), mat_ncols(A),
+		     nz, &I[0], &J[0], (const double *)A.pr, t);
+  }
+
+
+  template <typename MAT> void
+  MatrixMarket_IO::write(const char *filename, const MAT& A) {
+    gmm::csc_matrix<typename gmm::linalg_traits<MAT>::value_type> 
+      tmp(gmm::mat_nrows(A), gmm::mat_ncols(A));
+    gmm::copy(A,tmp); 
+    MatrixMarket_IO::write(filename, tmp);
+  }
+
+  template<typename VEC> static void vecsave(std::string fname, const VEC& V) {
+    std::ofstream f(fname.c_str()); f.precision(16);
+    for (size_type i=0; i < gmm::vect_size(V); ++i) f << V[i] << "\n"; 
+  } 
+
+  template<typename VEC> static void vecload(std::string fname,
+					     const VEC& V_) {
+    VEC &V(const_cast<VEC&>(V_));
+    std::ifstream f(fname.c_str());
+    for (size_type i=0; i < gmm::vect_size(V); ++i) f >> V[i]; 
+  }
+}
+
+
+#endif //  GMM_INOUTPUT_H
diff --git a/Contrib/gmm/gmm_interface.h b/Contrib/gmm/gmm_interface.h
new file mode 100755
index 0000000..d7693d6
--- /dev/null
+++ b/Contrib/gmm/gmm_interface.h
@@ -0,0 +1,1065 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+
+/**@file gmm_interface.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 13, 2002.
+   @brief gmm interface for STL vectors.
+*/
+
+#ifndef GMM_INTERFACE_H__
+#define GMM_INTERFACE_H__
+
+#include "gmm_blas.h"
+#include "gmm_sub_index.h"
+
+namespace gmm {
+
+  /* ********************************************************************* */
+  /*                                                                       */
+  /* What is needed for a Vector type :                                    */
+  /*   Vector v(n) defines a vector with n components.                     */
+  /*   v[i] allows to access to the ith component of v.                    */
+  /*   linalg_traits<Vector> should be filled with appropriate definitions */
+  /*                                                                       */
+  /*   for a dense vector : the minimum is two random iterators (begin and */
+  /*                        end) and a pointer to a valid origin.          */
+  /*   for a sparse vector : the minimum is two forward iterators, with    */
+  /*                         a method it.index() which gives the index of  */
+  /*                         a non zero element, an interface object       */
+  /*                         should describe the method to add new non     */
+  /*                         zero element, and  a pointer to a valid       */
+  /*                         origin.                                       */
+  /*                                                                       */
+  /* What is needed for a Matrix type :                                    */
+  /*   Matrix m(n, m) defines a matrix with n rows and m columns.          */
+  /*   m(i, j) allows to access to the element at row i and column j.      */
+  /*   linalg_traits<Matrix> should be filled with appropriate definitions */
+  /*                                                                       */
+  /* What is needed for an iterator on dense vector                        */
+  /*    to be standard random access iterator                              */
+  /*                                                                       */
+  /* What is needed for an iterator on a sparse vector                     */
+  /*    to be a standard bidirectional iterator                            */
+  /*    elt should be sorted with increasing indices.                      */
+  /*    it.index() gives the index of the non-zero element.                */
+  /*                                                                       */
+  /* Remark : If original iterators are not convenient, they could be      */
+  /*   redefined and interfaced in linalg_traits<Vector> without changing  */
+  /*   the original Vector type.                                           */
+  /*                                                                       */
+  /* ********************************************************************* */
+
+  /* ********************************************************************* */
+  /*		Simple references on vectors            		   */
+  /* ********************************************************************* */
+
+  template <typename PT> struct simple_vector_ref {
+    typedef simple_vector_ref<PT> this_type;
+    typedef typename std::iterator_traits<PT>::value_type V;
+    typedef V * CPT;
+    typedef typename std::iterator_traits<PT>::reference ref_V;
+    typedef typename linalg_traits<this_type>::iterator iterator;
+    typedef typename linalg_traits<this_type>::reference reference;
+    typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+    iterator begin_, end_;
+    porigin_type origin;
+    size_type size_;
+
+    simple_vector_ref(ref_V v) : begin_(vect_begin(const_cast<V&>(v))), 
+				 end_(vect_end(const_cast<V&>(v))), 
+				 origin(linalg_origin(const_cast<V&>(v))),
+				 size_(vect_size(v)) {}
+
+    simple_vector_ref(const simple_vector_ref<CPT> &cr)
+      : begin_(cr.begin_),end_(cr.end_),origin(cr.origin),size_(cr.size_) {}
+
+    simple_vector_ref(void) {}
+
+    reference operator[](size_type i) const
+    { return linalg_traits<V>::access(origin, begin_, end_, i); }
+  };
+
+  template <typename IT, typename ORG, typename PT> inline
+  void set_to_begin(IT &it, ORG o, simple_vector_ref<PT> *,linalg_modifiable) {
+    typedef typename linalg_traits<simple_vector_ref<PT> >::V_reference ref_t;
+    set_to_begin(it, o, PT(), ref_t());
+  }
+
+  template <typename IT, typename ORG, typename PT> inline
+  void set_to_begin(IT &it, ORG o, const simple_vector_ref<PT> *,
+		    linalg_modifiable) {
+    typedef typename linalg_traits<simple_vector_ref<PT> >::V_reference ref_t;
+    set_to_begin(it, o, PT(), ref_t());
+  }
+
+  template <typename IT, typename ORG, typename PT> inline
+  void set_to_end(IT &it, ORG o, simple_vector_ref<PT> *, linalg_modifiable) {
+    typedef typename linalg_traits<simple_vector_ref<PT> >::V_reference ref_t;
+    set_to_end(it, o, PT(), ref_t());
+  }
+
+  template <typename IT, typename ORG, typename PT> inline
+  void set_to_end(IT &it, ORG o, const simple_vector_ref<PT> *,
+		  linalg_modifiable) {
+    typedef typename linalg_traits<simple_vector_ref<PT> >::V_reference ref_t;
+    set_to_end(it, o, PT(), ref_t());
+  }
+
+
+  template <typename PT> struct linalg_traits<simple_vector_ref<PT> > {
+    typedef simple_vector_ref<PT> this_type;
+    typedef this_type *pthis_type;
+    typedef typename std::iterator_traits<PT>::value_type V;
+    typedef typename linalg_traits<V>::origin_type origin_type;
+    typedef V *pV;
+    typedef typename linalg_traits<V>::is_reference V_reference;
+    typedef typename which_reference<PT>::is_reference is_reference;
+    typedef abstract_vector linalg_type;
+    typedef typename linalg_traits<V>::value_type value_type;
+    typedef typename select_ref<value_type, typename
+            linalg_traits<V>::reference, PT>::ref_type reference;
+    typedef typename select_ref<const origin_type *, origin_type *,
+			        PT>::ref_type porigin_type;
+    typedef typename select_ref<typename linalg_traits<V>::const_iterator,
+	    typename linalg_traits<V>::iterator, PT>::ref_type iterator;
+    typedef typename linalg_traits<V>::const_iterator const_iterator;
+    typedef typename linalg_traits<V>::storage_type storage_type;
+    typedef linalg_true index_sorted;
+    static size_type size(const this_type &v) { return v.size_; }
+    static inline iterator begin(this_type &v) {
+      iterator it = v.begin_;
+      set_to_begin(it, v.origin, pthis_type(), is_reference()); 
+      return it;
+    }
+    static inline const_iterator begin(const this_type &v) {
+      const_iterator it = v.begin_;
+      set_to_begin(it, v.origin, pthis_type(), is_reference());
+      return it;
+    }
+    static inline iterator end(this_type &v) {
+      iterator it = v.end_;
+      set_to_end(it, v.origin, pthis_type(), is_reference());
+      return it;
+    }
+    static inline const_iterator end(const this_type &v) {
+      const_iterator it = v.end_;
+      set_to_end(it, v.origin, pthis_type(), is_reference());
+      return it;
+    }
+    static origin_type* origin(this_type &v) { return v.origin; }
+    static const origin_type* origin(const this_type &v) { return v.origin; }
+    static void clear(origin_type* o, const iterator &it, const iterator &ite)
+    { linalg_traits<V>::clear(o, it, ite); }
+    static void do_clear(this_type &v) { clear(v.origin, v.begin_, v.end_); }
+    static value_type access(const origin_type *o, const const_iterator &it,
+			     const const_iterator &ite, size_type i)
+    { return linalg_traits<V>::access(o, it, ite, i); }
+    static reference access(origin_type *o, const iterator &it,
+			    const iterator &ite, size_type i)
+    { return linalg_traits<V>::access(o, it, ite, i); }
+  };
+
+  template <typename PT>
+  std::ostream &operator << (std::ostream &o, const simple_vector_ref<PT>& v)
+  { gmm::write(o,v); return o; }
+
+  /* ********************************************************************* */
+  /*		                                         		   */
+  /*		Traits for S.T.L. object                     		   */
+  /*		                                         		   */
+  /* ********************************************************************* */
+
+  template <typename T, typename alloc>
+  struct linalg_traits<std::vector<T, alloc> > {
+    typedef std::vector<T, alloc> this_type;
+    typedef this_type origin_type;
+    typedef linalg_false is_reference;
+    typedef abstract_vector linalg_type;
+    typedef T value_type;
+    typedef T& reference;
+    typedef typename this_type::iterator iterator;
+    typedef typename this_type::const_iterator const_iterator;
+    typedef abstract_dense storage_type;
+    typedef linalg_true index_sorted;
+    static size_type size(const this_type &v) { return v.size(); }
+    static iterator begin(this_type &v) { return v.begin(); }
+    static const_iterator begin(const this_type &v) { return v.begin(); }
+    static iterator end(this_type &v) { return v.end(); }
+    static const_iterator end(const this_type &v) { return v.end(); }
+    static origin_type* origin(this_type &v) { return &v; }
+    static const origin_type* origin(const this_type &v) { return &v; }
+    static void clear(origin_type*, const iterator &it, const iterator &ite)
+    { std::fill(it, ite, value_type(0)); }
+    static void do_clear(this_type &v) { std::fill(v.begin(), v.end(), T(0)); }
+    static value_type access(const origin_type *, const const_iterator &it,
+			     const const_iterator &, size_type i)
+    { return it[i]; }
+    static reference access(origin_type *, const iterator &it,
+			    const iterator &, size_type i)
+    { return it[i]; }
+    static void resize(this_type &v, size_type n) { v.resize(n); }
+  };
+}
+namespace std {
+  template <typename T> ostream &operator <<
+  (std::ostream &o, const vector<T>& m) { gmm::write(o,m); return o; }
+}
+namespace gmm {
+
+  template <typename T>
+  inline size_type nnz(const std::vector<T>& l) { return l.size(); }
+
+  /* ********************************************************************* */
+  /*		                                         		   */
+  /*		Traits for ref objects                     		   */
+  /*		                                         		   */
+  /* ********************************************************************* */
+
+  template <typename IT, typename V>
+  struct tab_ref_with_origin : public gmm::tab_ref<IT> {
+    typedef tab_ref_with_origin<IT, V> this_type;
+    // next line replaced by the 4 following lines in order to please aCC
+    //typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+    typedef typename linalg_traits<V>::origin_type origin_type;
+    typedef typename std::iterator_traits<IT>::pointer PT;
+    typedef typename select_ref<const origin_type *, origin_type *,
+				PT>::ref_type porigin_type;
+   
+
+    porigin_type origin;
+   
+    tab_ref_with_origin(void) {}
+    template <class PT> tab_ref_with_origin(const IT &b, const IT &e, PT p)
+      : gmm::tab_ref<IT>(b,e), origin(porigin_type(p)) {}
+    tab_ref_with_origin(const IT &b, const IT &e, porigin_type p)
+      : gmm::tab_ref<IT>(b,e), origin(p) {}
+   
+    tab_ref_with_origin(const V &v, const sub_interval &si)
+      : gmm::tab_ref<IT>(vect_begin(const_cast<V&>(v))+si.min,
+			 vect_begin(const_cast<V&>(v))+si.max),
+        origin(linalg_origin(const_cast<V&>(v))) {}
+    tab_ref_with_origin(V &v, const sub_interval &si)
+      : gmm::tab_ref<IT>(vect_begin(const_cast<V&>(v))+si.min,
+			 vect_begin(const_cast<V&>(v))+si.max),
+        origin(linalg_origin(const_cast<V&>(v))) {}
+  };
+
+  template <typename IT, typename V>
+  struct linalg_traits<tab_ref_with_origin<IT, V> > {
+    typedef typename std::iterator_traits<IT>::pointer PT;
+    typedef typename linalg_traits<V>::origin_type origin_type;
+    typedef tab_ref_with_origin<IT, V> this_type;
+    typedef typename which_reference<PT>::is_reference is_reference;
+    typedef abstract_vector linalg_type;
+    typedef typename select_ref<const origin_type *, origin_type *,
+				PT>::ref_type porigin_type;
+    typedef typename std::iterator_traits<IT>::value_type value_type;
+    typedef typename std::iterator_traits<IT>::reference reference;
+    typedef typename this_type::iterator iterator;
+    typedef typename this_type::iterator const_iterator;
+    typedef abstract_dense storage_type;
+    typedef linalg_true index_sorted;
+    static size_type size(const this_type &v) { return v.size(); }
+    static iterator begin(this_type &v) { return v.begin(); }
+    static const_iterator begin(const this_type &v) { return v.begin(); }
+    static iterator end(this_type &v) { return v.end(); }
+    static const_iterator end(const this_type &v) { return v.end(); }
+    static origin_type* origin(this_type &v) { return v.origin; }
+    static const origin_type* origin(const this_type &v) { return v.origin; }
+    static void clear(origin_type*, const iterator &it, const iterator &ite)
+    { std::fill(it, ite, value_type(0)); }
+    static inline void do_clear(this_type &v)
+    { std::fill(v.begin(), v.end(), value_type(0)); }
+    static value_type access(const origin_type *, const const_iterator &it,
+			     const const_iterator &, size_type i)
+    { return it[i]; }
+    static reference access(origin_type *, const iterator &it, 
+			    const iterator &, size_type i)
+    { return it[i]; }
+  };
+
+  template <typename IT, typename V> std::ostream &operator <<
+  (std::ostream &o, const tab_ref_with_origin<IT, V>& m)
+  { gmm::write(o,m); return o; }
+
+
+  template <typename IT, typename V>
+  struct tab_ref_reg_spaced_with_origin : public gmm::tab_ref_reg_spaced<IT> {
+    typedef  tab_ref_reg_spaced_with_origin<IT, V> this_type;
+    typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+    porigin_type origin;
+    
+    tab_ref_reg_spaced_with_origin(void) {}
+    tab_ref_reg_spaced_with_origin(const IT &b, size_type n, size_type s,
+				   const porigin_type p)
+      : gmm::tab_ref_reg_spaced<IT>(b,n,s), origin(p) {}
+    tab_ref_reg_spaced_with_origin(const V &v, const sub_slice &si)
+      : gmm::tab_ref_reg_spaced<IT>(vect_begin(const_cast<V&>(v)) + si.min, 
+				    si.N, (si.max - si.min)/si.N),
+      origin(linalg_origin(const_cast<V&>(v))) {}
+    tab_ref_reg_spaced_with_origin(V &v, const sub_slice &si)
+      : gmm::tab_ref_reg_spaced<IT>(vect_begin(const_cast<V&>(v)) + si.min,
+				    si.N, (si.max - si.min)/si.N),
+	origin(linalg_origin(const_cast<V&>(v))) {}
+  };
+
+  template <typename IT, typename V> 
+  struct linalg_traits<tab_ref_reg_spaced_with_origin<IT, V> > {
+    typedef typename std::iterator_traits<IT>::pointer PT;
+    typedef tab_ref_reg_spaced_with_origin<IT, V> this_type;
+    typedef typename linalg_traits<V>::origin_type origin_type;
+    typedef typename select_ref<const origin_type *, origin_type *,
+				PT>::ref_type porigin_type;
+    typedef typename which_reference<PT>::is_reference is_reference;
+    typedef abstract_vector linalg_type;
+    typedef typename std::iterator_traits<IT>::value_type value_type;
+    typedef typename std::iterator_traits<IT>::reference reference;
+    typedef typename this_type::iterator iterator;
+    typedef typename this_type::iterator const_iterator;
+    typedef abstract_dense storage_type;
+    typedef linalg_true index_sorted;
+    static size_type size(const this_type &v) { return v.size(); }
+    static iterator begin(this_type &v) { return v.begin(); }
+    static const_iterator begin(const this_type &v) { return v.begin(); }
+    static iterator end(this_type &v) { return v.end(); }
+    static const_iterator end(const this_type &v) { return v.end(); }
+    static origin_type* origin(this_type &v) { return v.origin; }
+    static const origin_type* origin(const this_type &v) { return v.origin; }
+    static void clear(origin_type*, const iterator &it, const iterator &ite)
+    { std::fill(it, ite, value_type(0)); }
+    static void do_clear(this_type &v)
+    { std::fill(v.begin(), v.end(), value_type(0)); }
+    static value_type access(const origin_type *, const const_iterator &it,
+			     const const_iterator &, size_type i)
+    { return it[i]; }
+    static reference access(origin_type *, const iterator &it, 
+			    const iterator &, size_type i)
+    { return it[i]; }
+  };
+  
+  template <typename IT, typename V> std::ostream &operator <<
+  (std::ostream &o, const tab_ref_reg_spaced_with_origin<IT, V>& m)
+  { gmm::write(o,m); return o; }
+
+
+  template <typename IT, typename ITINDEX, typename V>
+  struct tab_ref_index_ref_with_origin 
+    : public gmm::tab_ref_index_ref<IT, ITINDEX> {
+    typedef tab_ref_index_ref_with_origin<IT, ITINDEX, V> this_type;
+    typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+    porigin_type origin;
+
+    tab_ref_index_ref_with_origin(void) {}
+    tab_ref_index_ref_with_origin(const IT &b, const ITINDEX &bi,
+				  const ITINDEX &ei, porigin_type p)
+      : gmm::tab_ref_index_ref<IT, ITINDEX>(b, bi, ei), origin(p) {}
+
+    tab_ref_index_ref_with_origin(const V &v, const sub_index &si)
+      : gmm::tab_ref_index_ref<IT, ITINDEX>(vect_begin(const_cast<V&>(v)),
+					    si.begin(), si.end()),
+      origin(linalg_origin(const_cast<V&>(v))) {}
+    tab_ref_index_ref_with_origin(V &v, const sub_index &si)
+      : gmm::tab_ref_index_ref<IT, ITINDEX>(vect_begin(const_cast<V&>(v)),
+					    si.begin(), si.end()),
+	origin(linalg_origin(const_cast<V&>(v))) {}
+  };
+
+  template <typename IT, typename ITINDEX, typename V>
+  struct linalg_traits<tab_ref_index_ref_with_origin<IT, ITINDEX, V> > {
+    typedef typename std::iterator_traits<IT>::pointer PT;
+    typedef tab_ref_index_ref_with_origin<IT, ITINDEX, V> this_type;
+    typedef typename linalg_traits<V>::origin_type origin_type;
+    typedef typename select_ref<const origin_type *, origin_type *,
+				PT>::ref_type porigin_type;
+    typedef typename which_reference<PT>::is_reference is_reference;
+    typedef abstract_vector linalg_type;
+    typedef typename std::iterator_traits<IT>::value_type value_type;
+    typedef typename std::iterator_traits<IT>::reference reference;
+    typedef typename this_type::iterator iterator;
+    typedef typename this_type::iterator const_iterator;
+    typedef abstract_dense storage_type;
+    typedef linalg_true index_sorted;
+    static size_type size(const this_type &v) { return v.size(); }
+    static iterator begin(this_type &v) { return v.begin(); }
+    static const_iterator begin(const this_type &v) { return v.begin(); }
+    static iterator end(this_type &v) { return v.end(); }
+    static const_iterator end(const this_type &v) { return v.end(); }
+    static origin_type* origin(this_type &v) { return v.origin; }
+    static const origin_type* origin(const this_type &v) { return v.origin; }
+    static void clear(origin_type*, const iterator &it, const iterator &ite)
+    { std::fill(it, ite, value_type(0)); }
+    static void do_clear(this_type &v)
+    { std::fill(v.begin(), v.end(), value_type(0)); }
+    static value_type access(const origin_type *, const const_iterator &it,
+			     const const_iterator &, size_type i)
+    { return it[i]; }
+    static reference access(origin_type *, const iterator &it,
+			    const iterator &, size_type i)
+    { return it[i]; }
+  };
+
+  template <typename IT, typename ITINDEX, typename V>
+  std::ostream &operator <<
+  (std::ostream &o, const tab_ref_index_ref_with_origin<IT, ITINDEX, V>& m)
+  { gmm::write(o,m); return o; }
+
+
+  template<typename ITER, typename MIT, typename PT> 
+  struct dense_compressed_iterator {
+    typedef ITER value_type;
+    typedef ITER *pointer;
+    typedef ITER &reference;
+    typedef ptrdiff_t difference_type;
+    typedef std::random_access_iterator_tag iterator_category;
+    typedef size_t size_type;
+    typedef dense_compressed_iterator<ITER, MIT, PT> iterator;
+    typedef typename std::iterator_traits<PT>::value_type *MPT;
+
+    ITER it;
+    size_type N, nrows, ncols, i;
+    PT origin;
+    
+    iterator operator ++(int) { iterator tmp = *this; i++; return tmp; }
+    iterator operator --(int) { iterator tmp = *this; i--; return tmp; }
+    iterator &operator ++()   { ++i; return *this; }
+    iterator &operator --()   { --i; return *this; }
+    iterator &operator +=(difference_type ii) { i += ii; return *this; }
+    iterator &operator -=(difference_type ii) { i -= ii; return *this; }
+    iterator operator +(difference_type ii) const 
+    { iterator itt = *this; return (itt += ii); }
+    iterator operator -(difference_type ii) const
+    { iterator itt = *this; return (itt -= ii); }
+    difference_type operator -(const iterator &ii) const
+    { return (N ? (it - ii.it) / N : 0) + i - ii.i; }
+
+    ITER operator *() const { return it+i*N; }
+    ITER operator [](int ii) const { return it + (i+ii) * N; }
+
+    bool operator ==(const iterator &ii) const
+    { return (*this - ii) == difference_type(0); }
+    bool operator !=(const iterator &ii) const { return !(ii == *this); }
+    bool operator < (const iterator &ii) const
+    { return (*this - ii) < difference_type(0); }
+
+    dense_compressed_iterator(void) {}
+    dense_compressed_iterator(const dense_compressed_iterator<MIT,MIT,MPT> &ii)
+      : it(ii.it), N(ii.N), nrows(ii.nrows), ncols(ii.ncols), i(ii.i),
+	origin(ii.origin)  {}
+    dense_compressed_iterator(const ITER &iter, size_type n, size_type r,
+			      size_type c, size_type ii, PT o)
+      : it(iter), N(n), nrows(r), ncols(c), i(ii), origin(o) { }
+    
+  };
+
+  /* ******************************************************************** */
+  /*	    Read only reference on a compressed sparse vector             */
+  /* ******************************************************************** */
+
+  template <typename PT1, typename PT2, int shift = 0>
+  struct cs_vector_ref_iterator {
+    PT1 pr;
+    PT2 ir;
+
+    typedef typename std::iterator_traits<PT1>::value_type value_type;
+    typedef PT1 pointer;
+    typedef typename std::iterator_traits<PT1>::reference  reference;
+    typedef size_t        size_type;
+    typedef ptrdiff_t     difference_type;
+    typedef std::bidirectional_iterator_tag iterator_category;
+    typedef cs_vector_ref_iterator<PT1, PT2, shift> iterator;
+    
+    cs_vector_ref_iterator(void) {}
+    cs_vector_ref_iterator(PT1 p1, PT2 p2) : pr(p1), ir(p2) {}
+
+    inline size_type index(void) const { return (*ir) - shift; }
+    iterator &operator ++() { ++pr; ++ir; return *this; }
+    iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
+    iterator &operator --() { --pr; --ir; return *this; }
+    iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
+    
+    reference operator  *() const { return *pr; }
+    pointer   operator ->() const { return pr; }
+    
+    bool operator ==(const iterator &i) const { return (i.pr==pr);}
+    bool operator !=(const iterator &i) const { return (i.pr!=pr);}
+  };
+    
+  template <typename PT1, typename PT2, int shift = 0> struct cs_vector_ref {
+    PT1 pr;
+    PT2 ir;
+    size_type n, size_;
+
+    typedef cs_vector_ref<PT1, PT2, shift> this_type;
+    typedef typename std::iterator_traits<PT1>::value_type value_type;
+    typedef typename linalg_traits<this_type>::const_iterator const_iterator;
+
+    cs_vector_ref(PT1 pt1, PT2 pt2, size_type nnz, size_type ns)
+      : pr(pt1), ir(pt2), n(nnz), size_(ns) {}
+    cs_vector_ref(void) {}
+
+    size_type size(void) const { return size_; }
+    
+    const_iterator begin(void) const { return const_iterator(pr, ir); }
+    const_iterator end(void) const { return const_iterator(pr+n, ir+n); }
+    
+    value_type operator[](size_type i) const
+    { return linalg_traits<this_type>::access(pr, begin(), end(),i); }
+  };
+
+  template <typename PT1, typename PT2, int shift>
+  struct linalg_traits<cs_vector_ref<PT1, PT2, shift> > {
+    typedef cs_vector_ref<PT1, PT2, shift> this_type;
+    typedef linalg_const is_reference;
+    typedef abstract_vector linalg_type;
+    typedef typename std::iterator_traits<PT1>::value_type value_type;
+    typedef value_type origin_type;
+    typedef typename std::iterator_traits<PT1>::value_type reference;
+    typedef cs_vector_ref_iterator<typename const_pointer<PT1>::pointer,
+	    typename const_pointer<PT2>::pointer, shift>  const_iterator;
+    typedef abstract_null_type iterator;
+    typedef abstract_sparse storage_type;
+    typedef linalg_true index_sorted;
+    static size_type size(const this_type &v) { return v.size(); }
+    static iterator begin(this_type &v) { return v.begin(); }
+    static const_iterator begin(const this_type &v) { return v.begin(); }
+    static iterator end(this_type &v) { return v.end(); }
+    static const_iterator end(const this_type &v) { return v.end(); }
+    static const origin_type* origin(const this_type &v) { return v.pr; }
+    static value_type access(const origin_type *, const const_iterator &b,
+			     const const_iterator &e, size_type i) {
+      if (b.ir == e.ir) return value_type(0);
+      PT2 p = std::lower_bound(b.ir, e.ir, i+shift);
+      return (*p == i+shift && p != e.ir) ? b.pr[p-b.ir] : value_type(0);
+    }
+  };
+
+  template <typename PT1, typename PT2, int shift>
+  std::ostream &operator <<
+  (std::ostream &o, const cs_vector_ref<PT1, PT2, shift>& m)
+  { gmm::write(o,m); return o; }
+
+  template <typename PT1, typename PT2, int shift>
+  inline size_type nnz(const cs_vector_ref<PT1, PT2, shift>& l) { return l.n; }
+
+  /* ******************************************************************** */
+  /*	    Read only reference on a compressed sparse column matrix      */
+  /* ******************************************************************** */
+
+  template <typename PT1, typename PT2, typename PT3, int shift = 0>
+  struct sparse_compressed_iterator {
+    typedef typename std::iterator_traits<PT1>::value_type value_type;
+    typedef const value_type *pointer;
+    typedef const value_type &reference;
+    typedef ptrdiff_t difference_type;
+    typedef size_t size_type;
+    typedef std::random_access_iterator_tag iterator_category;
+    typedef sparse_compressed_iterator<PT1, PT2, PT3, shift> iterator;
+
+    PT1 pr;
+    PT2 ir;
+    PT3 jc;
+    size_type n;
+    const value_type *origin;
+    
+    iterator operator ++(int) { iterator tmp = *this; jc++; return tmp; }
+    iterator operator --(int) { iterator tmp = *this; jc--; return tmp; }
+    iterator &operator ++()   { jc++; return *this; }
+    iterator &operator --()   { jc--; return *this; }
+    iterator &operator +=(difference_type i) { jc += i; return *this; }
+    iterator &operator -=(difference_type i) { jc -= i; return *this; }
+    iterator operator +(difference_type i) const 
+    { iterator itt = *this; return (itt += i); }
+    iterator operator -(difference_type i) const
+    { iterator itt = *this; return (itt -= i); }
+    difference_type operator -(const iterator &i) const { return jc - i.jc; }
+
+    reference operator *() const { return pr + *jc - shift; }
+    reference operator [](int ii) { return pr + *(jc+ii) - shift; }
+
+    bool operator ==(const iterator &i) const { return (jc == i.jc); }
+    bool operator !=(const iterator &i) const { return !(i == *this); }
+    bool operator < (const iterator &i) const { return (jc < i.jc); }
+
+    sparse_compressed_iterator(void) {}
+    sparse_compressed_iterator(PT1 p1, PT2 p2, PT3 p3, size_type nn,
+			       const value_type *o)
+      : pr(p1), ir(p2), jc(p3), n(nn), origin(o) { }
+    
+  };
+
+  template <typename PT1, typename PT2, typename PT3, int shift = 0>
+  struct csc_matrix_ref {
+    PT1 pr; // values.
+    PT2 ir; // row indexes.
+    PT3 jc; // column repartition on pr and ir.
+    size_type nc, nr;
+    
+    typedef typename std::iterator_traits<PT1>::value_type value_type;
+    csc_matrix_ref(PT1 pt1, PT2 pt2, PT3 pt3, size_type nrr, size_type ncc)
+      : pr(pt1), ir(pt2), jc(pt3), nc(ncc), nr(nrr) {}
+    csc_matrix_ref(void) {}
+    
+    size_type nrows(void) const { return nr; }
+    size_type ncols(void) const { return nc; }
+   
+    value_type operator()(size_type i, size_type j) const
+      { return mat_col(*this, j)[i]; }
+  };
+
+  template <typename PT1, typename PT2, typename PT3, int shift>
+  struct linalg_traits<csc_matrix_ref<PT1, PT2, PT3, shift> > {
+    typedef csc_matrix_ref<PT1, PT2, PT3, shift> this_type;
+    typedef linalg_const is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef typename std::iterator_traits<PT1>::value_type value_type;
+    typedef typename std::iterator_traits<PT1>::value_type reference;
+    typedef value_type origin_type;
+    typedef abstract_sparse storage_type;
+    typedef abstract_null_type sub_row_type;
+    typedef abstract_null_type const_sub_row_type;
+    typedef abstract_null_type row_iterator;
+    typedef abstract_null_type const_row_iterator;
+    typedef abstract_null_type sub_col_type;
+    typedef cs_vector_ref<typename const_pointer<PT1>::pointer,
+            typename const_pointer<PT2>::pointer, shift> const_sub_col_type;
+    typedef sparse_compressed_iterator<typename const_pointer<PT1>::pointer,
+				       typename const_pointer<PT2>::pointer,
+				       typename const_pointer<PT3>::pointer,
+				       shift>  const_col_iterator;
+    typedef abstract_null_type col_iterator;
+    typedef col_major sub_orientation;
+    typedef linalg_true index_sorted;
+    static size_type nrows(const this_type &m) { return m.nrows(); }
+    static size_type ncols(const this_type &m) { return m.ncols(); }
+    static const_col_iterator col_begin(const this_type &m)
+    { return const_col_iterator(m.pr, m.ir, m.jc, m.nr, m.pr); }
+    static const_col_iterator col_end(const this_type &m)
+    { return const_col_iterator(m.pr, m.ir, m.jc + m.nc, m.nr, m.pr); }
+    static const_sub_col_type col(const const_col_iterator &it) {
+      return const_sub_col_type(it.pr + *(it.jc) - shift,
+	     it.ir + *(it.jc) - shift, *(it.jc + 1) - *(it.jc), it.n);
+    }
+    static const origin_type* origin(const this_type &m) { return m.pr; }
+    static value_type access(const const_col_iterator &itcol, size_type j)
+    { return col(itcol)[j]; }
+  };
+
+
+  template <typename PT1, typename PT2, typename PT3, int shift>
+  std::ostream &operator <<
+  (std::ostream &o, const csc_matrix_ref<PT1, PT2, PT3, shift>& m)
+  { gmm::write(o,m); return o; }
+
+  /* ******************************************************************** */
+  /*	   Read only reference on a compressed sparse row matrix          */
+  /* ******************************************************************** */
+
+  template <typename PT1, typename PT2, typename PT3, int shift = 0>
+  struct csr_matrix_ref {
+    PT1 pr; // values.
+    PT2 ir; // column indexes.
+    PT3 jc; // row repartition on pr and ir.
+    size_type nc, nr;
+    
+    typedef typename std::iterator_traits<PT1>::value_type value_type;
+    csr_matrix_ref(PT1 pt1, PT2 pt2, PT3 pt3, size_type nrr, size_type ncc)
+      : pr(pt1), ir(pt2), jc(pt3), nc(ncc), nr(nrr) {}
+    csr_matrix_ref(void) {}
+    
+    size_type nrows(void) const { return nr; }
+    size_type ncols(void) const { return nc; }
+   
+    value_type operator()(size_type i, size_type j) const
+      { return mat_col(*this, i)[j]; }
+  };
+  
+  template <typename PT1, typename PT2, typename PT3, int shift>
+  struct linalg_traits<csr_matrix_ref<PT1, PT2, PT3, shift> > {
+    typedef csr_matrix_ref<PT1, PT2, PT3, shift> this_type;
+    typedef linalg_const is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef typename std::iterator_traits<PT1>::value_type value_type;
+    typedef typename std::iterator_traits<PT1>::value_type reference;
+    typedef value_type origin_type;
+    typedef abstract_sparse storage_type;
+    typedef abstract_null_type sub_col_type;
+    typedef abstract_null_type const_sub_col_type;
+    typedef abstract_null_type col_iterator;
+    typedef abstract_null_type const_col_iterator;
+    typedef abstract_null_type sub_row_type;
+    typedef cs_vector_ref<typename const_pointer<PT1>::pointer,
+			  typename const_pointer<PT2>::pointer, shift>
+            const_sub_row_type;
+    typedef sparse_compressed_iterator<typename const_pointer<PT1>::pointer,
+				       typename const_pointer<PT2>::pointer,
+				       typename const_pointer<PT3>::pointer,
+				       shift>  const_row_iterator;
+    typedef abstract_null_type row_iterator;
+    typedef row_major sub_orientation;
+    typedef linalg_true index_sorted;
+    static size_type nrows(const this_type &m) { return m.nrows(); }
+    static size_type ncols(const this_type &m) { return m.ncols(); }
+    static const_row_iterator row_begin(const this_type &m)
+    { return const_row_iterator(m.pr, m.ir, m.jc, m.nc, m.pr); }
+    static const_row_iterator row_end(const this_type &m)
+    { return const_row_iterator(m.pr, m.ir, m.jc + m.nr, m.nc, m.pr); }
+    static const_sub_row_type row(const const_row_iterator &it) {
+      return const_sub_row_type(it.pr + *(it.jc) - shift,
+	     it.ir + *(it.jc) - shift, *(it.jc + 1) - *(it.jc), it.n);
+    }
+    static const origin_type* origin(const this_type &m) { return m.pr; }
+    static value_type access(const const_row_iterator &itrow, size_type j)
+    { return row(itrow)[j]; }
+  };
+
+  template <typename PT1, typename PT2, typename PT3, int shift>
+  std::ostream &operator <<
+  (std::ostream &o, const csr_matrix_ref<PT1, PT2, PT3, shift>& m)
+  { gmm::write(o,m); return o; }
+
+  /* ********************************************************************* */
+  /*		                                         		   */
+  /*		Simple interface for C arrays                     	   */
+  /*		                                         		   */
+  /* ********************************************************************* */
+
+  template <class PT> struct array1D_reference {
+
+    typedef typename std::iterator_traits<PT>::value_type value_type;
+
+    PT begin, end;
+    
+    const value_type &operator[](size_type i) const { return *(begin+i); }
+    value_type &operator[](size_type i) { return *(begin+i); }
+
+    array1D_reference(PT begin_, size_type s) : begin(begin_), end(begin_+s) {}
+  };
+
+  template <typename PT>
+  struct linalg_traits<array1D_reference<PT> > {
+    typedef array1D_reference<PT> this_type;
+    typedef this_type origin_type;
+    typedef typename which_reference<PT>::is_reference is_reference;
+    typedef abstract_vector linalg_type;
+    typedef typename std::iterator_traits<PT>::value_type value_type;
+    typedef typename std::iterator_traits<PT>::reference reference;
+    typedef PT iterator;
+    typedef PT const_iterator;
+    typedef abstract_dense storage_type;
+    typedef linalg_true index_sorted;
+    static size_type size(const this_type &v) { return v.end - v.begin; }
+    static iterator begin(this_type &v) { return v.begin; }
+    static const_iterator begin(const this_type &v) { return v.begin; }
+    static iterator end(this_type &v) { return v.end; }
+    static const_iterator end(const this_type &v) { return v.end; }
+    static origin_type* origin(this_type &v) { return &v; }
+    static const origin_type* origin(const this_type &v) { return &v; }
+    static void clear(origin_type*, const iterator &it, const iterator &ite)
+    { std::fill(it, ite, value_type(0)); }
+    static void do_clear(this_type &v)
+    { std::fill(v.begin, v.end, value_type(0)); }
+    static value_type access(const origin_type *, const const_iterator &it,
+			     const const_iterator &, size_type i)
+    { return it[i]; }
+    static reference access(origin_type *, const iterator &it,
+			    const iterator &, size_type i)
+    { return it[i]; }
+    static void resize(this_type &, size_type )
+    { GMM_ASSERT1(false, "Not resizable vector"); }
+  };
+
+  template<typename PT> std::ostream &operator <<
+  (std::ostream &o, const array1D_reference<PT>& v)
+  { gmm::write(o,v); return o; }
+  
+  template <class PT> struct array2D_col_reference {
+
+    typedef typename std::iterator_traits<PT>::value_type T;
+    typedef typename std::iterator_traits<PT>::reference reference;
+    typedef typename const_reference<reference>::reference const_reference;
+    typedef PT iterator;
+    typedef typename const_pointer<PT>::pointer const_iterator;
+    
+    PT begin_;
+    size_type nbl, nbc;
+
+    inline const_reference operator ()(size_type l, size_type c) const {
+      GMM_ASSERT2(l < nbl && c < nbc, "out of range");
+      return *(begin_ + c*nbl+l);
+    }
+    inline reference operator ()(size_type l, size_type c) {
+      GMM_ASSERT2(l < nbl && c < nbc, "out of range");
+      return *(begin_ + c*nbl+l);
+    }
+    
+    void resize(size_type, size_type);
+    void reshape(size_type m, size_type n) {
+      GMM_ASSERT2(n*m == nbl*nbc, "dimensions mismatch");
+      nbl = m; nbc = n;
+    }
+    
+    void fill(T a, T b = T(0)) { 
+      std::fill(begin_, end+nbc*nbl, b);
+      iterator p = begin_, e = end+nbc*nbl;
+      while (p < e) { *p = a; p += nbl+1; }
+    }
+    inline size_type nrows(void) const { return nbl; }
+    inline size_type ncols(void) const { return nbc; }
+
+    iterator begin(void) { return begin_; }
+    const_iterator begin(void) const { return begin_; }
+    iterator end(void) { return begin_+nbl*nbc; }
+    const_iterator end(void) const { return begin_+nbl*nbc; }
+
+    array2D_col_reference(PT begin__, size_type nrows_, size_type ncols_)
+      : begin_(begin__), nbl(nrows_), nbc(ncols_) {}
+  };
+
+  template <typename PT> struct linalg_traits<array2D_col_reference<PT> > {
+    typedef array2D_col_reference<PT> this_type;
+    typedef this_type origin_type;
+    typedef typename which_reference<PT>::is_reference is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef typename std::iterator_traits<PT>::value_type value_type;
+    typedef typename std::iterator_traits<PT>::reference reference;
+    typedef abstract_dense storage_type;
+    typedef tab_ref_reg_spaced_with_origin<typename this_type::iterator,
+					   this_type> sub_row_type;
+    typedef tab_ref_reg_spaced_with_origin<typename this_type::const_iterator,
+					   this_type> const_sub_row_type;
+    typedef dense_compressed_iterator<typename this_type::iterator,
+				      typename this_type::iterator,
+				      this_type *> row_iterator;
+    typedef dense_compressed_iterator<typename this_type::const_iterator,
+				      typename this_type::iterator,
+				      const this_type *> const_row_iterator;
+    typedef tab_ref_with_origin<typename this_type::iterator, 
+				this_type> sub_col_type;
+    typedef tab_ref_with_origin<typename this_type::const_iterator,
+				this_type> const_sub_col_type;
+    typedef dense_compressed_iterator<typename this_type::iterator,
+				      typename this_type::iterator,
+				      this_type *> col_iterator;
+    typedef dense_compressed_iterator<typename this_type::const_iterator,
+				      typename this_type::iterator,
+				      const this_type *> const_col_iterator;
+    typedef col_and_row sub_orientation;
+    typedef linalg_true index_sorted;
+    static size_type nrows(const this_type &m) { return m.nrows(); }
+    static size_type ncols(const this_type &m) { return m.ncols(); }
+    static const_sub_row_type row(const const_row_iterator &it)
+    { return const_sub_row_type(*it, it.nrows, it.ncols, it.origin); }
+    static const_sub_col_type col(const const_col_iterator &it)
+    { return const_sub_col_type(*it, *it + it.nrows, it.origin); }
+    static sub_row_type row(const row_iterator &it)
+    { return sub_row_type(*it, it.nrows, it.ncols, it.origin); }
+    static sub_col_type col(const col_iterator &it)
+    { return sub_col_type(*it, *it + it.nrows, it.origin); }
+    static row_iterator row_begin(this_type &m)
+    { return row_iterator(m.begin(), 1, m.nrows(), m.ncols(), 0, &m); }
+    static row_iterator row_end(this_type &m)
+    { return row_iterator(m.begin(), 1, m.nrows(), m.ncols(), m.nrows(), &m); }
+    static const_row_iterator row_begin(const this_type &m)
+    { return const_row_iterator(m.begin(), 1, m.nrows(), m.ncols(), 0, &m); }
+    static const_row_iterator row_end(const this_type &m) {
+      return const_row_iterator(m.begin(), 1, m.nrows(),
+				m.ncols(), m.nrows(), &m);
+    }
+    static col_iterator col_begin(this_type &m)
+    { return col_iterator(m.begin(), m.nrows(), m.nrows(), m.ncols(), 0, &m); }
+    static col_iterator col_end(this_type &m) {
+      return col_iterator(m.begin(), m.nrows(), m.nrows(), m.ncols(),
+			  m.ncols(), &m);
+    }
+    static const_col_iterator col_begin(const this_type &m) {
+      return const_col_iterator(m.begin(), m.nrows(), m.nrows(),
+				m.ncols(), 0, &m);
+    }
+    static const_col_iterator col_end(const this_type &m) {
+      return const_col_iterator(m.begin(), m.nrows(),m.nrows(),m.ncols(),
+				m.ncols(), &m);
+    }
+    static origin_type* origin(this_type &m) { return &m; }
+    static const origin_type* origin(const this_type &m) { return &m; }
+    static void do_clear(this_type &m) { m.fill(value_type(0)); }
+    static value_type access(const const_col_iterator &itcol, size_type j)
+    { return (*itcol)[j]; }
+    static reference access(const col_iterator &itcol, size_type j)
+    { return (*itcol)[j]; }
+    static void resize(this_type &v, size_type m, size_type n)
+    { v.resize(m,n); }
+    static void reshape(this_type &v, size_type m, size_type n)
+    { v.reshape(m, n); }
+  };
+
+  template<typename PT> std::ostream &operator <<
+    (std::ostream &o, const array2D_col_reference<PT>& m)
+  { gmm::write(o,m); return o; }
+
+
+
+  template <class PT> struct array2D_row_reference {
+    
+    typedef typename std::iterator_traits<PT>::value_type T;
+    typedef typename std::iterator_traits<PT>::reference reference;
+    typedef typename const_reference<reference>::reference const_reference;
+    typedef PT iterator;
+    typedef typename const_pointer<PT>::pointer const_iterator;
+    
+    PT begin_;
+    size_type nbl, nbc;
+
+    inline const_reference operator ()(size_type l, size_type c) const {
+      GMM_ASSERT2(l < nbl && c < nbc, "out of range");
+      return *(begin_ + l*nbc+c);
+    }
+    inline reference operator ()(size_type l, size_type c) {
+      GMM_ASSERT2(l < nbl && c < nbc, "out of range");
+      return *(begin_ + l*nbc+c);
+    }
+    
+    void resize(size_type, size_type);
+    void reshape(size_type m, size_type n) {
+      GMM_ASSERT2(n*m == nbl*nbc, "dimensions mismatch");
+      nbl = m; nbc = n;
+    }
+    
+    void fill(T a, T b = T(0)) { 
+      std::fill(begin_, end+nbc*nbl, b);
+      iterator p = begin_, e = end+nbc*nbl;
+      while (p < e) { *p = a; p += nbc+1; }
+    }
+    inline size_type nrows(void) const { return nbl; }
+    inline size_type ncols(void) const { return nbc; }
+
+    iterator begin(void) { return begin_; }
+    const_iterator begin(void) const { return begin_; }
+    iterator end(void) { return begin_+nbl*nbc; }
+    const_iterator end(void) const { return begin_+nbl*nbc; }
+
+    array2D_row_reference(PT begin__, size_type nrows_, size_type ncols_)
+      : begin_(begin__), nbl(nrows_), nbc(ncols_) {}
+  };
+
+  template <typename PT> struct linalg_traits<array2D_row_reference<PT> > {
+    typedef array2D_row_reference<PT> this_type;
+    typedef this_type origin_type;
+    typedef typename which_reference<PT>::is_reference is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef typename std::iterator_traits<PT>::value_type value_type;
+    typedef typename std::iterator_traits<PT>::reference reference;
+    typedef abstract_dense storage_type;
+    typedef tab_ref_reg_spaced_with_origin<typename this_type::iterator,
+					   this_type> sub_col_type;
+    typedef tab_ref_reg_spaced_with_origin<typename this_type::const_iterator,
+					   this_type> const_sub_col_type;
+    typedef dense_compressed_iterator<typename this_type::iterator,
+				      typename this_type::iterator,
+				      this_type *> col_iterator;
+    typedef dense_compressed_iterator<typename this_type::const_iterator,
+				      typename this_type::iterator,
+				      const this_type *> const_col_iterator;
+    typedef tab_ref_with_origin<typename this_type::iterator, 
+				this_type> sub_row_type;
+    typedef tab_ref_with_origin<typename this_type::const_iterator,
+				this_type> const_sub_row_type;
+    typedef dense_compressed_iterator<typename this_type::iterator,
+				      typename this_type::iterator,
+				      this_type *> row_iterator;
+    typedef dense_compressed_iterator<typename this_type::const_iterator,
+				      typename this_type::iterator,
+				      const this_type *> const_row_iterator;
+    typedef col_and_row sub_orientation;
+    typedef linalg_true index_sorted;
+    static size_type ncols(const this_type &m) { return m.ncols(); }
+    static size_type nrows(const this_type &m) { return m.nrows(); }
+    static const_sub_col_type col(const const_col_iterator &it)
+    { return const_sub_col_type(*it, it.ncols, it.nrows, it.origin); }
+    static const_sub_row_type row(const const_row_iterator &it)
+    { return const_sub_row_type(*it, *it + it.ncols, it.origin); }
+    static sub_col_type col(const col_iterator &it)
+    { return sub_col_type(*it, *it, it.ncols, it.nrows, it.origin); }
+    static sub_row_type row(const row_iterator &it)
+    { return sub_row_type(*it, *it + it.ncols, it.origin); }
+    static col_iterator col_begin(this_type &m)
+    { return col_iterator(m.begin(), 1, m.ncols(), m.nrows(), 0, &m); }
+    static col_iterator col_end(this_type &m)
+    { return col_iterator(m.begin(), 1, m.ncols(), m.nrows(), m.ncols(), &m); }
+    static const_col_iterator col_begin(const this_type &m)
+    { return const_col_iterator(m.begin(), 1, m.ncols(), m.nrows(), 0, &m); }
+    static const_col_iterator col_end(const this_type &m) {
+      return const_col_iterator(m.begin(), 1, m.ncols(),
+				m.nrows(), m.ncols(), &m);
+    }
+    static row_iterator row_begin(this_type &m)
+    { return row_iterator(m.begin(), m.ncols(), m.ncols(), m.nrows(), 0, &m); }
+    static row_iterator row_end(this_type &m) {
+      return row_iterator(m.begin(), m.ncols(), m.ncols(), m.nrows(),
+			  m.nrows(), &m);
+    }
+    static const_row_iterator row_begin(const this_type &m) {
+      return const_row_iterator(m.begin(), m.ncols(), m.ncols(), m.nrows(),
+				0, &m);
+    }
+    static const_row_iterator row_end(const this_type &m) {
+      return const_row_iterator(m.begin(), m.ncols(), m.ncols(), m.nrows(),
+				m.nrows(), &m);
+    }
+    static origin_type* origin(this_type &m) { return &m; }
+    static const origin_type* origin(const this_type &m) { return &m; }
+    static void do_clear(this_type &m) { m.fill(value_type(0)); }
+    static value_type access(const const_row_iterator &itrow, size_type j)
+    { return (*itrow)[j]; }
+    static reference access(const row_iterator &itrow, size_type j)
+    { return (*itrow)[j]; }
+    static void resize(this_type &v, size_type m, size_type n)
+    { v.resize(m,n); }
+    static void reshape(this_type &v, size_type m, size_type n)
+    { v.reshape(m, n); }
+  };
+
+  template<typename PT> std::ostream &operator <<
+    (std::ostream &o, const array2D_row_reference<PT>& m)
+  { gmm::write(o,m); return o; }
+
+
+
+
+
+
+}
+
+
+#endif //  GMM_INTERFACE_H__
diff --git a/Contrib/gmm/gmm_interface_bgeot.h b/Contrib/gmm/gmm_interface_bgeot.h
new file mode 100755
index 0000000..baa8e77
--- /dev/null
+++ b/Contrib/gmm/gmm_interface_bgeot.h
@@ -0,0 +1,82 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_interface_bgeot.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 13, 2002.
+   @brief interface for bgeot::small_vector
+*/
+#ifndef GMM_INTERFACE_BGEOT_H__
+#define GMM_INTERFACE_BGEOT_H__
+
+
+namespace gmm {
+
+  /* ********************************************************************* */
+  /*		                                         	 	   */
+  /*		Traits for bgeot objects                     		   */
+  /*		                                         		   */
+  /* ********************************************************************* */
+
+  template <typename T> struct linalg_traits<bgeot::small_vector<T> > {
+    typedef bgeot::small_vector<T> this_type;
+    typedef this_type origin_type;
+    typedef linalg_false is_reference;
+    typedef abstract_vector linalg_type;
+    typedef T value_type;
+    typedef T& reference;
+    typedef typename this_type::iterator iterator;
+    typedef typename this_type::const_iterator const_iterator;
+    typedef abstract_dense storage_type;
+    typedef linalg_true index_sorted;
+    static size_type size(const this_type &v) { return v.size(); }
+    static iterator begin(this_type &v) { return v.begin(); }
+    static const_iterator begin(const this_type &v) { return v.begin(); }
+    static iterator end(this_type &v) { return v.end(); }
+    static const_iterator end(const this_type &v) { return v.end(); }
+    static origin_type* origin(this_type &v) { return &v; }
+    static const origin_type* origin(const this_type &v) { return &v; }
+    static void clear(origin_type* o, const iterator &it, const iterator &ite)
+    { std::fill(it, ite, value_type(0)); }
+    static void do_clear(this_type &v)
+    { std::fill(v.begin(), v.end(), value_type(0)); }
+    static value_type access(const origin_type *, const const_iterator &it,
+			     const const_iterator &, size_type i)
+    { return it[i]; }
+    static reference access(origin_type *, const iterator &it,
+			    const iterator &, size_type i)
+    { return it[i]; }
+    static void resize(this_type &v, size_type n) { v.resize(n); }
+  };
+
+}
+
+
+#endif //  GMM_INTERFACE_BGEOT_H__
diff --git a/Contrib/gmm/gmm_iter.h b/Contrib/gmm/gmm_iter.h
new file mode 100755
index 0000000..3a593db
--- /dev/null
+++ b/Contrib/gmm/gmm_iter.h
@@ -0,0 +1,139 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_iter.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date February 10, 2003.
+   @brief Iteration object.
+*/
+
+#ifndef GMM_ITER_H__
+#define GMM_ITER_H__
+
+#include "gmm_kernel.h"
+
+namespace gmm {
+
+  /**  The Iteration object calculates whether the solution has reached the
+       desired accuracy, or whether the maximum number of iterations has
+       been reached. 
+
+       The method finished() checks the convergence.  The first()
+       method is used to determine the first iteration of the loop.
+  */
+  class iteration {
+  protected :
+    double rhsn;       /* Right hand side norm.                            */
+    size_type maxiter; /* Max. number of iterations.                       */
+    int noise;         /* if noise > 0 iterations are printed.             */
+    double resmax;     /* maximum residu.                                  */
+    double resminreach, resadd;
+    size_type nit;     /* iteration number.                                */
+    double res;        /* last computed residu.                            */
+    std::string name;  /* eventually, name of the method.                  */
+    bool written;
+    void (*callback)(const gmm::iteration&);
+  public :
+
+    void init(void) { 
+      nit = 0; res = 0.0; written = false; 
+      resminreach = 1E50; resadd = 0.0; 
+      callback = 0;
+    }
+
+    iteration(double r = 1.0E-8, int noi = 0, size_type mit = size_type(-1))
+      : rhsn(1.0), maxiter(mit), noise(noi), resmax(r) { init(); }
+
+    void  operator ++(int) {  nit++; written = false; resadd += res; }
+    void  operator ++() { (*this)++; }
+
+    bool first(void) { return nit == 0; }
+
+    /* get/set the "noisyness" (verbosity) of the solvers */
+    int get_noisy(void) const { return noise; }
+    void set_noisy(int n) { noise = n; }
+    void reduce_noisy(void) { if (noise > 0) noise--; }
+
+    double get_resmax(void) const { return resmax; }
+    void set_resmax(double r) { resmax = r; }
+
+    double get_res() const { return res; }
+
+    /* change the user-definable callback, called after each iteration */
+    void set_callback(void (*t)(const gmm::iteration&)) {
+      callback = t;
+    }
+
+    size_type get_iteration(void) const { return nit; }
+    void set_iteration(size_type i) { nit = i; }
+    
+    size_type get_maxiter(void) const { return maxiter; }
+    void set_maxiter(size_type i) { maxiter = i; }
+
+    double get_rhsnorm(void) const { return rhsn; }
+    void set_rhsnorm(double r) { rhsn = r; }
+    
+    bool converged(void) { return res <= rhsn * resmax; }
+    bool converged(double nr) { 
+      res = gmm::abs(nr); resminreach = std::min(resminreach, res);
+      return converged();
+    }
+    template <typename VECT> bool converged(const VECT &v)
+    { return converged(gmm::vect_norm2(v)); }
+
+    bool finished(double nr) {
+      if (callback) callback(*this);
+      if (noise > 0 && !written) {
+	double a = (rhsn == 0) ? 1.0 : rhsn;
+	converged(nr);
+	cout << name << " iter " << nit << " residual "
+	     << gmm::abs(nr) / a;
+// 	if (nit % 100 == 0 && nit > 0) {
+// 	  cout << " (residual min " << resminreach / a << " mean val "
+// 	       << resadd / (100.0 * a) << " )";
+// 	  resadd = 0.0;
+// 	}
+	cout <<  endl;
+	written = true;
+      }
+      return (nit >= maxiter || converged(nr));
+    }
+    template <typename VECT> bool finished_vect(const VECT &v)
+    { return finished(double(gmm::vect_norm2(v))); }
+
+
+    void set_name(const std::string &n) { name = n; }
+    const std::string &get_name(void) const { return name; }
+
+  };
+
+}
+
+#endif /* GMM_ITER_H__ */
diff --git a/Contrib/gmm/gmm_iter_solvers.h b/Contrib/gmm/gmm_iter_solvers.h
new file mode 100755
index 0000000..4e782c7
--- /dev/null
+++ b/Contrib/gmm/gmm_iter_solvers.h
@@ -0,0 +1,109 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_iter_solvers.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 13, 2002.
+   @brief Include standard gmm iterative solvers (cg, gmres, ...)
+*/
+#ifndef GMM_ITER_SOLVERS_H__
+#define GMM_ITER_SOLVERS_H__
+
+#include "gmm_iter.h"
+
+
+namespace gmm {
+
+  /** mixed method to find a zero of a real function G, a priori 
+   * between a and b. If the zero is not between a and b, iterations
+   * of secant are applied. When a convenient interval is found,
+   * iterations of dichotomie and regula falsi are applied.
+   */
+  template <typename FUNC, typename T>
+  T find_root(const FUNC &G, T a = T(0), T b = T(1),
+	      T tol = gmm::default_tol(T())) {
+    T c, Ga = G(a), Gb = G(b), Gc, d;
+    d = gmm::abs(b - a);
+#if 0
+    for (int i = 0; i < 4; i++) { /* secant iterations.                   */
+      if (d < tol) return (b + a) / 2.0;
+      c = b - Gb * (b - a) / (Gb - Ga); Gc = G(c);
+      a = b; b = c; Ga = Gb; Gb = Gc;
+      d = gmm::abs(b - a);
+    }
+#endif
+    while (Ga * Gb > 0.0) { /* secant iterations.                         */
+      if (d < tol) return (b + a) / 2.0;
+      c = b - Gb * (b - a) / (Gb - Ga); Gc = G(c);
+      a = b; b = c; Ga = Gb; Gb = Gc;
+      d = gmm::abs(b - a);
+    }
+    
+    c = std::max(a, b); a = std::min(a, b); b = c;
+    while (d > tol) {
+      c = b - (b - a) * (Gb / (Gb - Ga)); /* regula falsi.     */
+      if (c > b) c = b; if (c < a) c = a; 
+      Gc = G(c);
+      if (Gc*Gb > 0) { b = c; Gb = Gc; } else { a = c; Ga = Gc; }
+      c = (b + a) / 2.0 ; Gc = G(c); /* Dichotomie.                       */
+      if (Gc*Gb > 0) { b = c; Gb = Gc; } else { a = c; Ga = Gc; }
+      d = gmm::abs(b - a); c = (b + a) / 2.0; if ((c == a) || (c == b)) d = 0.0;
+    }
+    return (b + a) / 2.0;
+  }
+  
+}
+
+#include "gmm_precond_diagonal.h"
+#include "gmm_precond_ildlt.h"
+#include "gmm_precond_ildltt.h"
+#include "gmm_precond_mr_approx_inverse.h"
+#include "gmm_precond_ilu.h"
+#include "gmm_precond_ilut.h"
+#include "gmm_precond_ilutp.h"
+
+
+
+#include "gmm_solver_cg.h"
+#include "gmm_solver_bicgstab.h"
+#include "gmm_solver_qmr.h"
+#include "gmm_solver_constrained_cg.h"
+#include "gmm_solver_Schwarz_additive.h"
+#include "gmm_modified_gram_schmidt.h"
+#include "gmm_tri_solve.h"
+#include "gmm_solver_gmres.h"
+#include "gmm_solver_bfgs.h"
+#include "gmm_least_squares_cg.h"
+
+// #include "gmm_solver_idgmres.h"
+
+
+
+#endif //  GMM_ITER_SOLVERS_H__
diff --git a/Contrib/gmm/gmm_kernel.h b/Contrib/gmm/gmm_kernel.h
new file mode 100755
index 0000000..e8fd9a4
--- /dev/null
+++ b/Contrib/gmm/gmm_kernel.h
@@ -0,0 +1,53 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_kernel.h 
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date November 15, 2003.
+   @brief Include the base gmm files.
+ */
+
+#ifndef GMM_KERNEL_H__
+#define GMM_KERNEL_H__
+
+#include "gmm_def.h"
+#include "gmm_blas.h"
+#include "gmm_real_part.h"
+#include "gmm_interface.h"
+#include "gmm_sub_vector.h"
+#include "gmm_sub_matrix.h"
+#include "gmm_vector_to_matrix.h"
+#include "gmm_vector.h"
+#include "gmm_matrix.h"
+#include "gmm_tri_solve.h"
+#include "gmm_blas_interface.h"
+
+
+#endif //  GMM_KERNEL_H__
diff --git a/Contrib/gmm/gmm_lapack_interface.h b/Contrib/gmm/gmm_lapack_interface.h
new file mode 100755
index 0000000..ea5edb4
--- /dev/null
+++ b/Contrib/gmm/gmm_lapack_interface.h
@@ -0,0 +1,362 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_lapack_interface.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 7, 2003.
+   @brief gmm interface for LAPACK
+*/
+
+#if defined(GMM_USES_LAPACK) || defined(GMM_USES_ATLAS)
+
+#ifndef GMM_LAPACK_INTERFACE_H
+#define GMM_LAPACK_INTERFACE_H
+
+#include "gmm_blas_interface.h"
+#include "gmm_dense_lu.h"
+#include "gmm_dense_qr.h"
+
+
+namespace gmm {
+
+  /* ********************************************************************* */
+  /* Operations interfaced for T = float, double, std::complex<float>      */
+  /*    or std::complex<double> :                                          */
+  /*                                                                       */
+  /* lu_factor(dense_matrix<T>, std::vector<int>)                          */
+  /* lu_solve(dense_matrix<T>, std::vector<T>, std::vector<T>)             */
+  /* lu_solve(dense_matrix<T>, std::vector<int>, std::vector<T>,           */
+  /*          std::vector<T>)                                              */
+  /* lu_solve_transposed(dense_matrix<T>, std::vector<int>, std::vector<T>,*/
+  /*          std::vector<T>)                                              */
+  /* lu_inverse(dense_matrix<T>)                                           */
+  /* lu_inverse(dense_matrix<T>, std::vector<int>, dense_matrix<T>)        */
+  /*                                                                       */
+  /* qr_factor(dense_matrix<T>, dense_matrix<T>, dense_matrix<T>)          */
+  /*                                                                       */
+  /* implicit_qr_algorithm(dense_matrix<T>, std::vector<T>)                */
+  /* implicit_qr_algorithm(dense_matrix<T>, std::vector<T>,                */
+  /*                       dense_matrix<T>)                                */
+  /* implicit_qr_algorithm(dense_matrix<T>, std::vector<std::complex<T> >) */
+  /* implicit_qr_algorithm(dense_matrix<T>, std::vector<std::complex<T> >, */
+  /*                       dense_matrix<T>)                                */
+  /*                                                                       */
+  /* ********************************************************************* */
+
+  /* ********************************************************************* */
+  /* LAPACK functions used.                                                */
+  /* ********************************************************************* */
+
+  extern "C" {
+    void sgetrf_(...); void dgetrf_(...); void cgetrf_(...); void zgetrf_(...);
+    void sgetrs_(...); void dgetrs_(...); void cgetrs_(...); void zgetrs_(...);
+    void sgetri_(...); void dgetri_(...); void cgetri_(...); void zgetri_(...);
+    void sgeqrf_(...); void dgeqrf_(...); void cgeqrf_(...); void zgeqrf_(...);
+    void sorgqr_(...); void dorgqr_(...); void cungqr_(...); void zungqr_(...);
+    void sormqr_(...); void dormqr_(...); void cunmqr_(...); void zunmqr_(...);
+    void sgees_ (...); void dgees_ (...); void cgees_ (...); void zgees_ (...);
+    void sgeev_ (...); void dgeev_ (...); void cgeev_ (...); void zgeev_ (...);
+  }
+
+  /* ********************************************************************* */
+  /* LU decomposition.                                                     */
+  /* ********************************************************************* */
+
+# define getrf_interface(lapack_name, base_type) inline                    \
+  size_type lu_factor(dense_matrix<base_type > &A, std::vector<int> &ipvt){\
+    GMMLAPACK_TRACE("getrf_interface");                                    \
+    int m(mat_nrows(A)), n(mat_ncols(A)), lda(m), info(0);                 \
+    if (m && n) lapack_name(&m, &n, &A(0,0), &lda, &ipvt[0], &info);       \
+    return size_type(info);                                                \
+  }
+
+  getrf_interface(sgetrf_, BLAS_S)
+  getrf_interface(dgetrf_, BLAS_D)
+  getrf_interface(cgetrf_, BLAS_C)
+  getrf_interface(zgetrf_, BLAS_Z)
+
+  /* ********************************************************************* */
+  /* LU solve.                                                             */
+  /* ********************************************************************* */
+
+# define getrs_interface(f_name, trans1, lapack_name, base_type) inline    \
+  void f_name(const dense_matrix<base_type > &A,                           \
+	      const std::vector<int> &ipvt, std::vector<base_type > &x,    \
+	      const std::vector<base_type > &b) {                          \
+    GMMLAPACK_TRACE("getrs_interface");                                    \
+    int n(mat_nrows(A)), info, nrhs(1);                                    \
+    gmm::copy(b, x); trans1;                                               \
+    if (n)                                                                 \
+      lapack_name(&t, &n, &nrhs, &(A(0,0)),&n,&ipvt[0], &x[0], &n, &info); \
+  }
+  
+# define getrs_trans_n const char t = 'N'
+# define getrs_trans_t const char t = 'T'
+
+  getrs_interface(lu_solve, getrs_trans_n, sgetrs_, BLAS_S)
+  getrs_interface(lu_solve, getrs_trans_n, dgetrs_, BLAS_D)
+  getrs_interface(lu_solve, getrs_trans_n, cgetrs_, BLAS_C)
+  getrs_interface(lu_solve, getrs_trans_n, zgetrs_, BLAS_Z)
+  getrs_interface(lu_solve_transposed, getrs_trans_t, sgetrs_, BLAS_S)
+  getrs_interface(lu_solve_transposed, getrs_trans_t, dgetrs_, BLAS_D)
+  getrs_interface(lu_solve_transposed, getrs_trans_t, cgetrs_, BLAS_C)
+  getrs_interface(lu_solve_transposed, getrs_trans_t, zgetrs_, BLAS_Z)
+
+  /* ********************************************************************* */
+  /* LU inverse.                                                           */
+  /* ********************************************************************* */
+
+# define getri_interface(lapack_name, base_type) inline                    \
+  void lu_inverse(const dense_matrix<base_type > &LU,                      \
+       std::vector<int> &ipvt, const dense_matrix<base_type > &A_) {       \
+    GMMLAPACK_TRACE("getri_interface");                                    \
+    dense_matrix<base_type >&                                              \
+    A = const_cast<dense_matrix<base_type > &>(A_);                        \
+    int n(mat_nrows(A)), info, lwork(-1); base_type work1;                 \
+    if (n) {                                                               \
+      gmm::copy(LU, A);                                                    \
+      lapack_name(&n, &A(0,0), &n, &ipvt[0], &work1, &lwork, &info);       \
+      lwork = int(gmm::real(work1));                                       \
+      std::vector<base_type > work(lwork);                                 \
+      lapack_name(&n, &A(0,0), &n, &ipvt[0], &work[0], &lwork, &info);     \
+    }                                                                      \
+  }
+
+  getri_interface(sgetri_, BLAS_S)
+  getri_interface(dgetri_, BLAS_D)
+  getri_interface(cgetri_, BLAS_C)
+  getri_interface(zgetri_, BLAS_Z)
+
+
+  /* ********************************************************************* */
+  /* QR factorization.                                                     */
+  /* ********************************************************************* */
+
+# define geqrf_interface(lapack_name1, base_type) inline		   \
+  void qr_factor(dense_matrix<base_type > &A){			           \
+    GMMLAPACK_TRACE("geqrf_interface");				           \
+    int m(mat_nrows(A)), n(mat_ncols(A)), info, lwork(-1); base_type work1;\
+    if (m && n) {							   \
+      std::vector<base_type > tau(n);					   \
+      lapack_name1(&m, &n, &A(0,0), &m, &tau[0], &work1  , &lwork, &info); \
+      lwork = int(gmm::real(work1));					   \
+      std::vector<base_type > work(lwork);				   \
+      lapack_name1(&m, &n, &A(0,0), &m, &tau[0], &work[0], &lwork, &info); \
+      GMM_ASSERT1(!info, "QR factorization failed");			   \
+    }									   \
+  }
+    
+  geqrf_interface(sgeqrf_, BLAS_S)
+  geqrf_interface(dgeqrf_, BLAS_D)
+    // For complex values, housholder vectors are not the same as in
+    // gmm::lu_factor. Impossible to interface for the moment.
+    //  geqrf_interface(cgeqrf_, BLAS_C)
+    //  geqrf_interface(zgeqrf_, BLAS_Z)
+
+# define geqrf_interface2(lapack_name1, lapack_name2, base_type) inline    \
+  void qr_factor(const dense_matrix<base_type > &A,                        \
+       dense_matrix<base_type > &Q, dense_matrix<base_type > &R) {         \
+    GMMLAPACK_TRACE("geqrf_interface2");                                   \
+    int m(mat_nrows(A)), n(mat_ncols(A)), info, lwork(-1); base_type work1;\
+    if (m && n) {                                                          \
+      gmm::copy(A, Q);                                                     \
+      std::vector<base_type > tau(n);                                      \
+      lapack_name1(&m, &n, &Q(0,0), &m, &tau[0], &work1  , &lwork, &info); \
+      lwork = int(gmm::real(work1));                                       \
+      std::vector<base_type > work(lwork);                                 \
+      lapack_name1(&m, &n, &Q(0,0), &m, &tau[0], &work[0], &lwork, &info); \
+      GMM_ASSERT1(!info, "QR factorization failed");                       \
+      base_type *p = &R(0,0), *q = &Q(0,0);                                \
+      for (int j = 0; j < n; ++j, q += m-n)                                \
+        for (int i = 0; i < n; ++i, ++p, ++q)                              \
+          *p = (j < i) ? base_type(0) : *q;                                \
+      lapack_name2(&m, &n, &n, &Q(0,0), &m,&tau[0],&work[0],&lwork,&info); \
+    }                                                                      \
+    else gmm::clear(Q);                                                    \
+  }
+
+  geqrf_interface2(sgeqrf_, sorgqr_, BLAS_S)
+  geqrf_interface2(dgeqrf_, dorgqr_, BLAS_D)
+  geqrf_interface2(cgeqrf_, cungqr_, BLAS_C)
+  geqrf_interface2(zgeqrf_, zungqr_, BLAS_Z)
+  
+  /* ********************************************************************* */
+  /* QR algorithm for eigenvalues search.                                  */
+  /* ********************************************************************* */
+
+# define gees_interface(lapack_name, base_type)                            \
+  template <typename VECT> inline void implicit_qr_algorithm(              \
+         const dense_matrix<base_type > &A,  const VECT &eigval_,          \
+         dense_matrix<base_type > &Q,                                      \
+         double tol=gmm::default_tol(base_type()), bool compvect = true) { \
+    GMMLAPACK_TRACE("gees_interface");                                     \
+    typedef bool (*L_fp)(...);  L_fp p = 0;                                \
+    int n(mat_nrows(A)), info, lwork(-1), sdim; base_type work1;           \
+    if (!n) return;                                                        \
+    dense_matrix<base_type > H(n,n); gmm::copy(A, H);                      \
+    char jobvs = (compvect ? 'V' : 'N'), sort = 'N';                       \
+    std::vector<double> rwork(n), eigv1(n), eigv2(n);                      \
+    lapack_name(&jobvs, &sort, p, &n, &H(0,0), &n, &sdim, &eigv1[0],       \
+                &eigv2[0], &Q(0,0), &n, &work1, &lwork, &rwork[0], &info); \
+    lwork = int(gmm::real(work1));                                         \
+    std::vector<base_type > work(lwork);                                   \
+    lapack_name(&jobvs, &sort, p, &n, &H(0,0), &n, &sdim, &eigv1[0],       \
+		&eigv2[0], &Q(0,0), &n, &work[0], &lwork, &rwork[0],&info);\
+    GMM_ASSERT1(!info, "QR algorithm failed");                             \
+    extract_eig(H, const_cast<VECT &>(eigval_), tol);                      \
+  }
+
+# define gees_interface2(lapack_name, base_type)                           \
+  template <typename VECT> inline void implicit_qr_algorithm(              \
+         const dense_matrix<base_type > &A,  const VECT &eigval_,          \
+         dense_matrix<base_type > &Q,                                      \
+         double tol=gmm::default_tol(base_type()), bool compvect = true) { \
+    GMMLAPACK_TRACE("gees_interface2");                                    \
+    typedef bool (*L_fp)(...);  L_fp p = 0;                                \
+    int n(mat_nrows(A)), info, lwork(-1), sdim; base_type work1;           \
+    if (!n) return;                                                        \
+    dense_matrix<base_type > H(n,n); gmm::copy(A, H);                      \
+    char jobvs = (compvect ? 'V' : 'N'), sort = 'N';                       \
+    std::vector<double> rwork(n), eigvv(n*2);                              \
+    lapack_name(&jobvs, &sort, p, &n, &H(0,0), &n, &sdim, &eigvv[0],       \
+                &Q(0,0), &n, &work1, &lwork, &rwork[0], &rwork[0], &info); \
+    lwork = int(gmm::real(work1));                                         \
+    std::vector<base_type > work(lwork);                                   \
+    lapack_name(&jobvs, &sort, p, &n, &H(0,0), &n, &sdim, &eigvv[0],       \
+                &Q(0,0), &n, &work[0], &lwork, &rwork[0], &rwork[0],&info);\
+    GMM_ASSERT1(!info, "QR algorithm failed");                             \
+    extract_eig(H, const_cast<VECT &>(eigval_), tol);                      \
+  }
+
+  gees_interface(sgees_, BLAS_S)
+  gees_interface(dgees_, BLAS_D)
+  gees_interface2(cgees_, BLAS_C)
+  gees_interface2(zgees_, BLAS_Z)
+
+# define geev_int_right(lapack_name, base_type)			           \
+  template <typename VECT> inline void geev_interface_right(               \
+         const dense_matrix<base_type > &A,  const VECT &eigval_,          \
+         dense_matrix<base_type > &Q) {		                           \
+    GMMLAPACK_TRACE("geev_interface");                                     \
+    int n(mat_nrows(A)), info, lwork(-1); base_type work1;                 \
+    if (!n) return;                                                        \
+    dense_matrix<base_type > H(n,n); gmm::copy(A, H);                      \
+    char jobvl = 'N', jobvr = 'V';                                         \
+    std::vector<base_type > eigvr(n), eigvi(n);                            \
+    lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigvr[0], &eigvi[0],     \
+		&Q(0,0), &n, &Q(0,0), &n, &work1, &lwork, &info);   	   \
+    lwork = int(gmm::real(work1));                                         \
+    std::vector<base_type > work(lwork);                                   \
+    lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigvr[0], &eigvi[0],     \
+		&Q(0,0), &n, &Q(0,0), &n, &work[0], &lwork, &info);    	   \
+    GMM_ASSERT1(!info, "QR algorithm failed");                             \
+    gmm::copy(eigvr, gmm::real_part(const_cast<VECT &>(eigval_)));	   \
+    gmm::copy(eigvi, gmm::imag_part(const_cast<VECT &>(eigval_)));	   \
+  }
+
+# define geev_int_rightc(lapack_name, base_type)			   \
+  template <typename VECT> inline void geev_interface_right(               \
+         const dense_matrix<base_type > &A,  const VECT &eigval_,          \
+         dense_matrix<base_type > &Q) {		                           \
+    GMMLAPACK_TRACE("geev_interface");                                     \
+    int n(mat_nrows(A)), info, lwork(-1); base_type work1;                 \
+    if (!n) return;                                                        \
+    dense_matrix<base_type > H(n,n); gmm::copy(A, H);                      \
+    char jobvl = 'N', jobvr = 'V';                                         \
+    std::vector<double> rwork(2*n);                                        \
+    std::vector<base_type> eigv(n);                                        \
+    lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigv[0], &Q(0,0), &n,    \
+		&Q(0,0), &n, &work1, &lwork, &rwork[0], &info);	   	   \
+    lwork = int(gmm::real(work1));                                         \
+    std::vector<base_type > work(lwork);                                   \
+    lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigv[0], &Q(0,0), &n,    \
+		&Q(0,0), &n, &work[0], &lwork,  &rwork[0],  &info);	   \
+    GMM_ASSERT1(!info, "QR algorithm failed");                             \
+    gmm::copy(eigv, const_cast<VECT &>(eigval_));			   \
+  }
+
+  geev_int_right(sgeev_, BLAS_S)
+  geev_int_right(dgeev_, BLAS_D)
+  geev_int_rightc(cgeev_, BLAS_C)
+  geev_int_rightc(zgeev_, BLAS_Z)
+
+# define geev_int_left(lapack_name, base_type)                             \
+  template <typename VECT> inline void geev_interface_left(                \
+         const dense_matrix<base_type > &A,  const VECT &eigval_,          \
+         dense_matrix<base_type > &Q) {	 	                           \
+    GMMLAPACK_TRACE("geev_interface");                                     \
+    int n(mat_nrows(A)), info, lwork(-1); base_type work1;                 \
+    if (!n) return;                                                        \
+    dense_matrix<base_type > H(n,n); gmm::copy(A, H);                      \
+    char jobvl = 'V', jobvr = 'N';                                         \
+    std::vector<base_type > eigvr(n), eigvi(n);                            \
+    lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigvr[0], &eigvi[0],     \
+		&Q(0,0), &n, &Q(0,0), &n, &work1, &lwork, &info);   	   \
+    lwork = int(gmm::real(work1));                                         \
+    std::vector<base_type > work(lwork);                                   \
+    lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigvr[0], &eigvi[0],     \
+		&Q(0,0), &n, &Q(0,0), &n, &work[0], &lwork, &info);    	   \
+    GMM_ASSERT1(!info, "QR algorithm failed");                             \
+    gmm::copy(eigvr, gmm::real_part(const_cast<VECT &>(eigval_)));	   \
+    gmm::copy(eigvi, gmm::imag_part(const_cast<VECT &>(eigval_)));	   \
+  }
+
+# define geev_int_leftc(lapack_name, base_type)	  		           \
+  template <typename VECT> inline void geev_interface_left(                \
+         const dense_matrix<base_type > &A,  const VECT &eigval_,          \
+         dense_matrix<base_type > &Q) {		                           \
+    GMMLAPACK_TRACE("geev_interface");                                     \
+    int n(mat_nrows(A)), info, lwork(-1); base_type work1;                 \
+    if (!n) return;                                                        \
+    dense_matrix<base_type > H(n,n); gmm::copy(A, H);                      \
+    char jobvl = 'V', jobvr = 'N';                                         \
+    std::vector<double> rwork(2*n);                                        \
+    std::vector<base_type> eigv(n);                                        \
+    lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigv[0], &Q(0,0), &n,    \
+		&Q(0,0), &n, &work1, &lwork, &rwork[0], &info);	   	   \
+    lwork = int(gmm::real(work1));                                         \
+    std::vector<base_type > work(lwork);                                   \
+    lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigv[0], &Q(0,0), &n,    \
+		&Q(0,0), &n, &work[0], &lwork,  &rwork[0],  &info);	   \
+    GMM_ASSERT1(!info, "QR algorithm failed");                             \
+    gmm::copy(eigv, const_cast<VECT &>(eigval_));			   \
+  }
+
+  geev_int_left(sgeev_, BLAS_S)
+  geev_int_left(dgeev_, BLAS_D)
+  geev_int_leftc(cgeev_, BLAS_C)
+  geev_int_leftc(zgeev_, BLAS_Z) 
+    
+
+}
+
+#endif // GMM_LAPACK_INTERFACE_H
+
+#endif // GMM_USES_LAPACK || GMM_USES_ATLAS
diff --git a/Contrib/gmm/gmm_least_squares_cg.h b/Contrib/gmm/gmm_least_squares_cg.h
new file mode 100755
index 0000000..711d334
--- /dev/null
+++ b/Contrib/gmm/gmm_least_squares_cg.h
@@ -0,0 +1,95 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_leastsquares_cg.h
+   @author Benjamin Schleimer <bensch128  (at) yahoo (dot) com>
+   @date January 23, 2007.
+   @brief Conjugate gradient least squares algorithm. 
+   Algorithm taken from http://www.stat.washington.edu/wxs/Stat538-w05/Notes/conjugate-gradients.pdf page 6
+*/
+#ifndef GMM_LEAST_SQUARES_CG_H__
+#define GMM_LEAST_SQUARES_CG_H__
+
+#include "gmm_kernel.h"
+#include "gmm_iter.h"
+#include "gmm_conjugated.h"
+
+namespace gmm {
+
+  template <typename Matrix, typename Vector1, typename Vector2>
+  void least_squares_cg(const Matrix& C, Vector1& x, const Vector2& y,
+			iteration &iter) {
+
+    typedef typename temporary_dense_vector<Vector1>::vector_type temp_vector;
+    typedef typename linalg_traits<Vector1>::value_type T;
+
+    T rho, rho_1(0), a;
+    temp_vector p(vect_size(x)), q(vect_size(y)), g(vect_size(x));
+    temp_vector r(vect_size(y));
+    iter.set_rhsnorm(gmm::sqrt(gmm::abs(vect_hp(y, y))));
+
+    if (iter.get_rhsnorm() == 0.0)
+      clear(x);
+    else {
+      mult(C, scaled(x, T(-1)), y, r);
+      mult(conjugated(C), r, g);
+      rho = vect_hp(g, g);
+      copy(g, p);
+
+      while (!iter.finished_vect(g)) {
+
+	if (!iter.first()) { 
+	  rho = vect_hp(g, g);
+	  add(g, scaled(p, rho / rho_1), p);
+	}
+
+	mult(C, p, q);
+
+	a = rho / vect_hp(q, q);	
+	add(scaled(p, a), x);
+	add(scaled(q, -a), r);
+	// NOTE: how do we minimize the impact to the transpose?
+	mult(conjugated(C), r, g);
+	rho_1 = rho;
+
+	++iter;
+      }
+    }
+  }
+
+  template <typename Matrix, typename Precond, 
+            typename Vector1, typename Vector2> inline 
+  void least_squares_cg(const Matrix& C, const Vector1& x, const Vector2& y,
+			iteration &iter)
+  { least_squares_cg(C, linalg_const_cast(x), y, iter); }
+}
+
+
+#endif //  GMM_SOLVER_CG_H__
diff --git a/Contrib/gmm/gmm_matrix.h b/Contrib/gmm/gmm_matrix.h
new file mode 100755
index 0000000..e6cb2a7
--- /dev/null
+++ b/Contrib/gmm/gmm_matrix.h
@@ -0,0 +1,1188 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/** @file gmm_matrix.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 13, 2002.
+    @brief Declaration of some matrix types (gmm::dense_matrix,
+    gmm::row_matrix, gmm::col_matrix, gmm::csc_matrix, etc.)
+*/
+
+#ifndef GMM_MATRIX_H__
+#define GMM_MATRIX_H__
+
+#include "gmm_vector.h"
+#include "gmm_sub_vector.h"
+#include "gmm_sub_matrix.h"
+#include "gmm_transposed.h"
+
+namespace gmm
+{
+
+  /* ******************************************************************** */
+  /*		                                            		  */
+  /*		Identity matrix                         		  */
+  /*		                                            		  */
+  /* ******************************************************************** */
+
+  struct identity_matrix {
+    template <class MAT> void build_with(const MAT &) {}
+  };
+
+  template <typename M> inline
+  void add(const identity_matrix&, M &v1) {
+    size_type n = std::min(gmm::mat_nrows(v1), gmm::mat_ncols(v1));
+    for (size_type i = 0; i < n; ++i)
+      v1(i,i) += typename linalg_traits<M>::value_type(1);
+  }
+  template <typename M> inline
+  void add(const identity_matrix &I, const M &v1)
+  { add(I, linalg_const_cast(v1)); }
+
+  template <typename V1, typename V2> inline
+  void mult(const identity_matrix&, const V1 &v1, V2 &v2)
+  { copy(v1, v2); }
+  template <typename V1, typename V2> inline
+  void mult(const identity_matrix&, const V1 &v1, const V2 &v2) 
+  { copy(v1, v2); }
+  template <typename V1, typename V2, typename V3> inline
+  void mult(const identity_matrix&, const V1 &v1, const V2 &v2, V3 &v3)
+  { add(v1, v2, v3); }
+  template <typename V1, typename V2, typename V3> inline
+  void mult(const identity_matrix&, const V1 &v1, const V2 &v2, const V3 &v3)
+  { add(v1, v2, v3); }
+  template <typename V1, typename V2> inline
+  void left_mult(const identity_matrix&, const V1 &v1, V2 &v2)
+  { copy(v1, v2); }
+  template <typename V1, typename V2> inline
+  void left_mult(const identity_matrix&, const V1 &v1, const V2 &v2) 
+  { copy(v1, v2); }
+  template <typename V1, typename V2> inline
+  void right_mult(const identity_matrix&, const V1 &v1, V2 &v2)
+  { copy(v1, v2); }
+  template <typename V1, typename V2> inline
+  void right_mult(const identity_matrix&, const V1 &v1, const V2 &v2) 
+  { copy(v1, v2); }
+  template <typename V1, typename V2> inline
+  void transposed_left_mult(const identity_matrix&, const V1 &v1, V2 &v2)
+  { copy(v1, v2); }
+  template <typename V1, typename V2> inline
+  void transposed_left_mult(const identity_matrix&, const V1 &v1,const V2 &v2) 
+  { copy(v1, v2); }
+  template <typename V1, typename V2> inline
+  void transposed_right_mult(const identity_matrix&, const V1 &v1, V2 &v2)
+  { copy(v1, v2); }
+  template <typename V1, typename V2> inline
+  void transposed_right_mult(const identity_matrix&,const V1 &v1,const V2 &v2) 
+  { copy(v1, v2); }
+  template <typename M> void copy_ident(const identity_matrix&, M &m) {
+    size_type i = 0, n = std::min(mat_nrows(m), mat_ncols(m));
+    clear(m);
+    for (; i < n; ++i) m(i,i) = typename linalg_traits<M>::value_type(1);
+  }
+  template <typename M> inline void copy(const identity_matrix&, M &m)
+  { copy_ident(identity_matrix(), m); } 
+  template <typename M> inline void copy(const identity_matrix &, const M &m)
+  { copy_ident(identity_matrix(), linalg_const_cast(m)); }
+  template <typename V1, typename V2> inline
+  typename linalg_traits<V1>::value_type
+  vect_sp(const identity_matrix &, const V1 &v1, const V2 &v2)
+  { return vect_sp(v1, v2); }
+  template <typename V1, typename V2> inline
+  typename linalg_traits<V1>::value_type
+  vect_hp(const identity_matrix &, const V1 &v1, const V2 &v2)
+  { return vect_hp(v1, v2); }
+  template<typename M> inline bool is_identity(const M&) { return false; }
+  inline bool is_identity(const identity_matrix&) { return true; }
+
+  /* ******************************************************************** */
+  /*		                                            		  */
+  /*		Row matrix                                   		  */
+  /*		                                            		  */
+  /* ******************************************************************** */
+
+  template<typename V> class row_matrix {
+  protected :
+    std::vector<V> li; /* array of rows.                                  */
+    size_type nc;
+    
+  public :
+    
+    typedef typename linalg_traits<V>::reference reference;
+    typedef typename linalg_traits<V>::value_type value_type;
+    
+    row_matrix(size_type r, size_type c) : li(r, V(c)), nc(c) {}
+    row_matrix(void) : nc(0) {}
+    reference operator ()(size_type l, size_type c) 
+    { return li[l][c]; }
+    value_type operator ()(size_type l, size_type c) const
+    { return li[l][c]; }
+
+    void clear_mat();
+    void resize(size_type m, size_type n);
+
+    typename std::vector<V>::iterator begin(void)
+    { return li.begin(); }
+    typename std::vector<V>::iterator end(void)  
+    { return li.end(); }
+    typename std::vector<V>::const_iterator begin(void) const
+    { return li.begin(); }
+    typename std::vector<V>::const_iterator end(void) const
+    { return li.end(); }
+    
+    
+    V& row(size_type i) { return li[i]; }
+    const V& row(size_type i) const { return li[i]; }
+    V& operator[](size_type i) { return li[i]; }
+    const V& operator[](size_type i) const { return li[i]; }
+    
+    inline size_type nrows(void) const { return li.size(); }
+    inline size_type ncols(void) const { return nc;        }
+
+    void swap(row_matrix<V> &m) { std::swap(li, m.li); std::swap(nc, m.nc); }
+    void swap_row(size_type i, size_type j) { std::swap(li[i], li[j]); }
+  };
+
+  template<typename V> void row_matrix<V>::resize(size_type m, size_type n) {
+    li.resize(m);
+    for (size_type i=0; i < m; ++i) gmm::resize(li[i], n);
+    nc = n;
+  }
+
+
+  template<typename V> void row_matrix<V>::clear_mat()
+  { for (size_type i=0; i < nrows(); ++i) clear(li[i]); }
+
+  template <typename V> struct linalg_traits<row_matrix<V> > {
+    typedef row_matrix<V> this_type;
+    typedef this_type origin_type;
+    typedef linalg_false is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef typename linalg_traits<V>::value_type value_type;
+    typedef typename linalg_traits<V>::reference reference;
+    typedef typename linalg_traits<V>::storage_type storage_type;
+    typedef simple_vector_ref<V *> sub_row_type;
+    typedef simple_vector_ref<const V *> const_sub_row_type;
+    typedef typename std::vector<V>::iterator row_iterator;
+    typedef typename std::vector<V>::const_iterator const_row_iterator;
+    typedef abstract_null_type sub_col_type;
+    typedef abstract_null_type const_sub_col_type;
+    typedef abstract_null_type col_iterator;
+    typedef abstract_null_type const_col_iterator;
+    typedef row_major sub_orientation;
+    typedef linalg_true index_sorted;
+    static size_type nrows(const this_type &m) { return m.nrows(); }
+    static size_type ncols(const this_type &m) { return m.ncols(); }
+    static row_iterator row_begin(this_type &m) { return m.begin(); }
+    static row_iterator row_end(this_type &m) { return m.end(); }
+    static const_row_iterator row_begin(const this_type &m)
+    { return m.begin(); }
+    static const_row_iterator row_end(const this_type &m)
+    { return m.end(); }
+    static const_sub_row_type row(const const_row_iterator &it)
+    { return const_sub_row_type(*it); }
+    static sub_row_type row(const row_iterator &it) 
+    { return sub_row_type(*it); }
+    static origin_type* origin(this_type &m) { return &m; }
+    static const origin_type* origin(const this_type &m) { return &m; }
+    static void do_clear(this_type &m) { m.clear_mat(); }
+    static value_type access(const const_row_iterator &itrow, size_type j)
+    { return (*itrow)[j]; }
+    static reference access(const row_iterator &itrow, size_type j)
+    { return (*itrow)[j]; }
+    static void resize(this_type &v, size_type m, size_type n)
+    { v.resize(m, n); }
+    static void reshape(this_type &, size_type, size_type)
+    { GMM_ASSERT1(false, "Sorry, to be done"); }
+  };
+
+  template<typename V> std::ostream &operator <<
+    (std::ostream &o, const row_matrix<V>& m) { gmm::write(o,m); return o; }
+
+  /* ******************************************************************** */
+  /*		                                            		  */
+  /*		Column matrix                                		  */
+  /*		                                            		  */
+  /* ******************************************************************** */
+
+  template<typename V> class col_matrix {
+  protected :
+    std::vector<V> li; /* array of columns.                               */
+    size_type nr;
+    
+  public :
+    
+    typedef typename linalg_traits<V>::reference reference;
+    typedef typename linalg_traits<V>::value_type value_type;
+    
+    col_matrix(size_type r, size_type c) : li(c, V(r)), nr(r) { }
+    col_matrix(void) : nr(0) {}
+    reference operator ()(size_type l, size_type c)
+    { return li[c][l]; }
+    value_type operator ()(size_type l, size_type c) const
+    { return li[c][l]; }
+
+    void clear_mat();
+    void resize(size_type, size_type);
+
+    V& col(size_type i) { return li[i]; }
+    const V& col(size_type i) const { return li[i]; }
+    V& operator[](size_type i) { return li[i]; }
+    const V& operator[](size_type i) const { return li[i]; }
+
+    typename std::vector<V>::iterator begin(void)
+    { return li.begin(); }
+    typename std::vector<V>::iterator end(void)  
+    { return li.end(); }
+    typename std::vector<V>::const_iterator begin(void) const
+    { return li.begin(); }
+    typename std::vector<V>::const_iterator end(void) const
+    { return li.end(); }
+    
+    inline size_type ncols(void) const { return li.size(); }
+    inline size_type nrows(void) const { return nr; }
+
+    void swap(col_matrix<V> &m) { std::swap(li, m.li); std::swap(nr, m.nr); }
+    void swap_col(size_type i, size_type j) { std::swap(li[i], li[j]); }
+  };
+
+  template<typename V> void col_matrix<V>::resize(size_type m, size_type n) {
+    li.resize(n);
+    for (size_type i=0; i < n; ++i) gmm::resize(li[i], m);
+    nr = m;
+  }
+
+  template<typename V> void col_matrix<V>::clear_mat()
+  { for (size_type i=0; i < ncols(); ++i)  clear(li[i]); }
+
+  template <typename V> struct linalg_traits<col_matrix<V> > {
+    typedef col_matrix<V> this_type;
+    typedef this_type origin_type;
+    typedef linalg_false is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef typename linalg_traits<V>::value_type value_type;
+    typedef typename linalg_traits<V>::reference reference;
+    typedef typename linalg_traits<V>::storage_type storage_type;
+    typedef simple_vector_ref<V *> sub_col_type;
+    typedef simple_vector_ref<const V *> const_sub_col_type;
+    typedef typename std::vector<V>::iterator col_iterator;
+    typedef typename std::vector<V>::const_iterator const_col_iterator;
+    typedef abstract_null_type sub_row_type;
+    typedef abstract_null_type const_sub_row_type;
+    typedef abstract_null_type row_iterator;
+    typedef abstract_null_type const_row_iterator;
+    typedef col_major sub_orientation;
+    typedef linalg_true index_sorted;
+    static size_type nrows(const this_type &m) { return m.nrows(); }
+    static size_type ncols(const this_type &m) { return m.ncols(); }
+    static col_iterator col_begin(this_type &m) { return m.begin(); }
+    static col_iterator col_end(this_type &m) { return m.end(); }
+    static const_col_iterator col_begin(const this_type &m)
+    { return m.begin(); }
+    static const_col_iterator col_end(const this_type &m)
+    { return m.end(); }
+    static const_sub_col_type col(const const_col_iterator &it)
+    { return const_sub_col_type(*it); }
+    static sub_col_type col(const col_iterator &it) 
+    { return sub_col_type(*it); }
+    static origin_type* origin(this_type &m) { return &m; }
+    static const origin_type* origin(const this_type &m) { return &m; }
+    static void do_clear(this_type &m) { m.clear_mat(); }
+    static value_type access(const const_col_iterator &itcol, size_type j)
+    { return (*itcol)[j]; }
+    static reference access(const col_iterator &itcol, size_type j)
+    { return (*itcol)[j]; }
+    static void resize(this_type &v, size_type m, size_type n)
+    { v.resize(m,n); }
+    static void reshape(this_type &, size_type, size_type)
+    { GMM_ASSERT1(false, "Sorry, to be done"); }
+  };
+
+  template<typename V> std::ostream &operator <<
+    (std::ostream &o, const col_matrix<V>& m) { gmm::write(o,m); return o; }
+
+  /* ******************************************************************** */
+  /*		                                            		  */
+  /*		Dense matrix                                		  */
+  /*		                                            		  */
+  /* ******************************************************************** */
+
+  template<typename T> class dense_matrix : public std::vector<T> {
+  public:
+    typedef typename std::vector<T>::size_type size_type;
+    typedef typename std::vector<T>::iterator iterator;
+    typedef typename std::vector<T>::const_iterator const_iterator;
+    
+  protected:
+    size_type nbc, nbl;
+    
+  public:
+    
+    inline const T& operator ()(size_type l, size_type c) const {
+      GMM_ASSERT2(l < nbl && c < nbc, "out of range");
+      return *(this->begin() + c*nbl+l);
+    }
+    inline T& operator ()(size_type l, size_type c) {
+      GMM_ASSERT2(l < nbl && c < nbc, "out of range");
+      return *(this->begin() + c*nbl+l);
+    }
+
+    void resize(size_type, size_type);
+    void reshape(size_type, size_type);
+    
+    void fill(T a, T b = T(0));
+    inline size_type nrows(void) const { return nbl; }
+    inline size_type ncols(void) const { return nbc; }
+    void swap(dense_matrix<T> &m)
+    { std::vector<T>::swap(m); std::swap(nbc, m.nbc); std::swap(nbl, m.nbl); }
+    
+    dense_matrix(size_type l, size_type c)
+      : std::vector<T>(c*l), nbc(c), nbl(l)  {}
+    dense_matrix(void) { nbl = nbc = 0; }
+  };
+
+  template<typename T> void dense_matrix<T>::reshape(size_type m,size_type n) {
+    GMM_ASSERT2(n*m == nbl*nbc, "dimensions mismatch");
+    nbl = m; nbc = n;
+  }
+
+  template<typename T> void dense_matrix<T>::resize(size_type m, size_type n) {
+    if (n*m > nbc*nbl) std::vector<T>::resize(n*m);
+    if (m < nbl) {
+      for (size_type i = 1; i < std::min(nbc, n); ++i)
+	std::copy(this->begin()+i*nbl, this->begin()+(i*nbl+m),
+		  this->begin()+i*m);
+      for (size_type i = std::min(nbc, n); i < n; ++i)
+	std::fill(this->begin()+(i*m), this->begin()+(i+1)*m, T(0));
+      }
+    else if (m > nbl) { /* do nothing when the nb of rows does not change */
+      for (size_type i = std::min(nbc, n); i > 1; --i)
+	std::copy(this->begin()+(i-1)*nbl, this->begin()+i*nbl,
+		  this->begin()+(i-1)*m);
+      for (size_type i = 0; i < std::min(nbc, n); ++i)
+	std::fill(this->begin()+(i*m+nbl), this->begin()+(i+1)*m, T(0));
+    }
+    if (n*m < nbc*nbl) std::vector<T>::resize(n*m);
+    nbl = m; nbc = n;
+  }
+  
+  template<typename T> void dense_matrix<T>::fill(T a, T b) {
+    std::fill(this->begin(), this->end(), b);
+    size_type n = std::min(nbl, nbc);
+    if (a != b) for (size_type i = 0; i < n; ++i) (*this)(i,i) = a; 
+  }
+
+  template <typename T> struct linalg_traits<dense_matrix<T> > {
+    typedef dense_matrix<T> this_type;
+    typedef this_type origin_type;
+    typedef linalg_false is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef T value_type;
+    typedef T& reference;
+    typedef abstract_dense storage_type;
+    typedef tab_ref_reg_spaced_with_origin<typename this_type::iterator,
+					   this_type> sub_row_type;
+    typedef tab_ref_reg_spaced_with_origin<typename this_type::const_iterator,
+					   this_type> const_sub_row_type;
+    typedef dense_compressed_iterator<typename this_type::iterator,
+				      typename this_type::iterator,
+				      this_type *> row_iterator;
+    typedef dense_compressed_iterator<typename this_type::const_iterator,
+				      typename this_type::iterator,
+				      const this_type *> const_row_iterator;
+    typedef tab_ref_with_origin<typename this_type::iterator, 
+				this_type> sub_col_type;
+    typedef tab_ref_with_origin<typename this_type::const_iterator,
+				this_type> const_sub_col_type;
+    typedef dense_compressed_iterator<typename this_type::iterator,
+				      typename this_type::iterator,
+				      this_type *> col_iterator;
+    typedef dense_compressed_iterator<typename this_type::const_iterator,
+				      typename this_type::iterator,
+				      const this_type *> const_col_iterator;
+    typedef col_and_row sub_orientation;
+    typedef linalg_true index_sorted;
+    static size_type nrows(const this_type &m) { return m.nrows(); }
+    static size_type ncols(const this_type &m) { return m.ncols(); }
+    static const_sub_row_type row(const const_row_iterator &it)
+    { return const_sub_row_type(*it, it.nrows, it.ncols, it.origin); }
+    static const_sub_col_type col(const const_col_iterator &it)
+    { return const_sub_col_type(*it, *it + it.nrows, it.origin); }
+    static sub_row_type row(const row_iterator &it)
+    { return sub_row_type(*it, it.nrows, it.ncols, it.origin); }
+    static sub_col_type col(const col_iterator &it)
+    { return sub_col_type(*it, *it + it.nrows, it.origin); }
+    static row_iterator row_begin(this_type &m)
+    { return row_iterator(m.begin(), m.size() ? 1 : 0, m.nrows(), m.ncols(), 0, &m); }
+    static row_iterator row_end(this_type &m)
+    { return row_iterator(m.begin(), m.size() ? 1 : 0, m.nrows(), m.ncols(), m.nrows(), &m); }
+    static const_row_iterator row_begin(const this_type &m)
+    { return const_row_iterator(m.begin(), m.size() ? 1 : 0, m.nrows(), m.ncols(), 0, &m); }
+    static const_row_iterator row_end(const this_type &m)
+    { return const_row_iterator(m.begin(),  m.size() ? 1 : 0, m.nrows(), m.ncols(), m.nrows(), &m); }
+    static col_iterator col_begin(this_type &m)
+    { return col_iterator(m.begin(), m.nrows(), m.nrows(), m.ncols(), 0, &m); }
+    static col_iterator col_end(this_type &m)
+    { return col_iterator(m.begin(), m.nrows(), m.nrows(), m.ncols(), m.ncols(), &m); }
+    static const_col_iterator col_begin(const this_type &m)
+    { return const_col_iterator(m.begin(), m.nrows(), m.nrows(), m.ncols(), 0, &m); }
+    static const_col_iterator col_end(const this_type &m)
+    { return const_col_iterator(m.begin(),m.nrows(),m.nrows(),m.ncols(),m.ncols(), &m); }
+    static origin_type* origin(this_type &m) { return &m; }
+    static const origin_type* origin(const this_type &m) { return &m; }
+    static void do_clear(this_type &m) { m.fill(value_type(0)); }
+    static value_type access(const const_col_iterator &itcol, size_type j)
+    { return (*itcol)[j]; }
+    static reference access(const col_iterator &itcol, size_type j)
+    { return (*itcol)[j]; }
+    static void resize(this_type &v, size_type m, size_type n)
+    { v.resize(m,n); }
+    static void reshape(this_type &v, size_type m, size_type n)
+    { v.reshape(m, n); }
+  };
+
+  template<typename T> std::ostream &operator <<
+    (std::ostream &o, const dense_matrix<T>& m) { gmm::write(o,m); return o; }
+
+  /* ******************************************************************** */
+  /*                                                                      */
+  /*	        Read only compressed sparse column matrix                 */
+  /*                                                                      */
+  /* ******************************************************************** */
+
+  template <typename T, int shift = 0>
+  struct csc_matrix {
+    typedef unsigned int IND_TYPE;
+
+    T *pr;        // values.
+    IND_TYPE *ir; // row indices.
+    IND_TYPE *jc; // column repartition on pr and ir.
+    size_type nc, nr;
+
+    typedef T value_type;
+    typedef T& access_type;
+
+    template <typename Matrix> void init_with_good_format(const Matrix &B);
+    template <typename Matrix> void init_with(const Matrix &A);
+    void init_with(const col_matrix<gmm::rsvector<T> > &B)
+    { init_with_good_format(B); }
+    void init_with(const col_matrix<wsvector<T> > &B)
+    { init_with_good_format(B); }
+    template <typename PT1, typename PT2, typename PT3, int cshift>
+    void init_with(const csc_matrix_ref<PT1,PT2,PT3,cshift>& B)
+    { init_with_good_format(B); }
+    template <typename U, int cshift>    
+    void init_with(const csc_matrix<U, cshift>& B)
+    { init_with_good_format(B); }
+
+    void init_with_identity(size_type n);
+
+    csc_matrix(void) : pr(0), ir(0), jc(0), nc(0), nr(0) {}
+    csc_matrix(size_type nnr, size_type nnc);
+    ~csc_matrix() { if (pr) { delete[] pr; delete[] ir; delete[] jc; } }
+
+    size_type nrows(void) const { return nr; }
+    size_type ncols(void) const { return nc; }
+    void swap(csc_matrix<T, shift> &m) { 
+      std::swap(pr, m.pr); 
+      std::swap(ir,m.ir); std::swap(jc, m.jc); 
+      std::swap(nc, m.nc); std::swap(nr,m.nr);
+    }
+    value_type operator()(size_type i, size_type j) const
+    { return mat_col(*this, j)[i]; }
+  };
+
+  template <typename T, int shift> template<typename Matrix>
+  void csc_matrix<T, shift>::init_with_good_format(const Matrix &B) {
+    typedef typename linalg_traits<Matrix>::const_sub_col_type col_type;
+    if (pr) { delete[] pr; delete[] ir; delete[] jc; }
+    nc = mat_ncols(B); nr = mat_nrows(B);
+    jc = new IND_TYPE[nc+1];
+    jc[0] = shift;
+    for (size_type j = 0; j < nc; ++j) {
+      jc[j+1] = jc[j] + nnz(mat_const_col(B, j));
+    }
+    pr = new T[jc[nc]];
+    ir = new IND_TYPE[jc[nc]];
+    for (size_type j = 0; j < nc; ++j) {
+      col_type col = mat_const_col(B, j);
+      typename linalg_traits<col_type>::const_iterator
+	it = vect_const_begin(col), ite = vect_const_end(col);
+      for (size_type k = 0; it != ite; ++it, ++k)
+	{ pr[jc[j]-shift+k] = *it; ir[jc[j]-shift+k] = it.index() + shift; }
+    }
+  }
+  
+  template <typename T, int shift> template <typename Matrix>
+  void csc_matrix<T, shift>::init_with(const Matrix &A) {
+    col_matrix<wsvector<T> > B(mat_nrows(A), mat_ncols(A));
+    copy(A, B);
+    init_with_good_format(B);
+  }
+  
+  template <typename T, int shift>
+  void csc_matrix<T, shift>::init_with_identity(size_type n) {
+    if (pr) { delete[] pr; delete[] ir; delete[] jc; }
+    nc = nr = n; 
+    pr = new T[nc];
+    ir = new IND_TYPE[nc];
+    jc = new IND_TYPE[nc+1];
+    for (size_type j = 0; j < nc; ++j)
+      { ir[j] = jc[j] = shift + j; pr[j] = T(1); }
+    jc[nc] = shift + nc;
+  }
+  
+  template <typename T, int shift>
+  csc_matrix<T, shift>::csc_matrix(size_type nnr, size_type nnc)
+    : nc(nnc), nr(nnr) {
+    pr = new T[1];  ir = new IND_TYPE[1];
+    jc = new IND_TYPE[nc+1];
+    for (size_type j = 0; j <= nc; ++j) jc[j] = shift;
+  }
+
+  template <typename T, int shift>
+  struct linalg_traits<csc_matrix<T, shift> > {
+    typedef csc_matrix<T, shift> this_type;
+    typedef typename this_type::IND_TYPE IND_TYPE;
+    typedef linalg_const is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef T value_type;
+    typedef T origin_type;
+    typedef T reference;
+    typedef abstract_sparse storage_type;
+    typedef abstract_null_type sub_row_type;
+    typedef abstract_null_type const_sub_row_type;
+    typedef abstract_null_type row_iterator;
+    typedef abstract_null_type const_row_iterator;
+    typedef abstract_null_type sub_col_type;
+    typedef cs_vector_ref<const T *, const IND_TYPE *, shift>
+    const_sub_col_type;
+    typedef sparse_compressed_iterator<const T *, const IND_TYPE *,
+				       const IND_TYPE *, shift>
+    const_col_iterator;
+    typedef abstract_null_type col_iterator;
+    typedef col_major sub_orientation;
+    typedef linalg_true index_sorted;
+    static size_type nrows(const this_type &m) { return m.nrows(); }
+    static size_type ncols(const this_type &m) { return m.ncols(); }
+    static const_col_iterator col_begin(const this_type &m)
+    { return const_col_iterator(m.pr, m.ir, m.jc, m.nr, m.pr); }
+    static const_col_iterator col_end(const this_type &m)
+    { return const_col_iterator(m.pr, m.ir, m.jc + m.nc, m.nr, m.pr); }
+    static const_sub_col_type col(const const_col_iterator &it) {
+      return const_sub_col_type(it.pr + *(it.jc) - shift,
+				it.ir + *(it.jc) - shift,
+				*(it.jc + 1) - *(it.jc), it.n);
+    }
+    static const origin_type* origin(const this_type &m) { return m.pr; }
+    static void do_clear(this_type &m) { m.do_clear(); }
+    static value_type access(const const_col_iterator &itcol, size_type j)
+    { return col(itcol)[j]; }
+  };
+
+  template <typename T, int shift>
+  std::ostream &operator <<
+    (std::ostream &o, const csc_matrix<T, shift>& m)
+  { gmm::write(o,m); return o; }
+  
+  template <typename T, int shift>
+  inline void copy(const identity_matrix &, csc_matrix<T, shift>& M)
+  { M.init_with_identity(mat_nrows(M)); }
+
+  template <typename Matrix, typename T, int shift>
+  inline void copy(const Matrix &A, csc_matrix<T, shift>& M)
+  { M.init_with(A); }
+
+  /* ******************************************************************** */
+  /*                                                                      */
+  /*	        Read only compressed sparse row matrix                    */
+  /*                                                                      */
+  /* ******************************************************************** */
+
+  template <typename T, int shift = 0>
+  struct csr_matrix {
+
+    typedef unsigned int IND_TYPE;
+
+    T *pr;        // values.
+    IND_TYPE *ir; // col indices.
+    IND_TYPE *jc; // row repartition on pr and ir.
+    size_type nc, nr;
+
+    typedef T value_type;
+    typedef T& access_type;
+
+
+    template <typename Matrix> void init_with_good_format(const Matrix &B);
+    void init_with(const row_matrix<wsvector<T> > &B)
+    { init_with_good_format(B); }
+    void init_with(const row_matrix<rsvector<T> > &B)
+    { init_with_good_format(B); }
+    template <typename PT1, typename PT2, typename PT3, int cshift>
+    void init_with(const csr_matrix_ref<PT1,PT2,PT3,cshift>& B)
+    { init_with_good_format(B); }
+    template <typename U, int cshift>
+    void init_with(const csr_matrix<U, cshift>& B)
+    { init_with_good_format(B); }
+
+    template <typename Matrix> void init_with(const Matrix &A);
+    void init_with_identity(size_type n);
+
+    csr_matrix(void) : pr(0), ir(0), jc(0), nc(0), nr(0) {}
+    csr_matrix(size_type nnr, size_type nnc);
+    ~csr_matrix() { if (pr) { delete[] pr; delete[] ir; delete[] jc; } }
+
+    size_type nrows(void) const { return nr; }
+    size_type ncols(void) const { return nc; }
+    void swap(csr_matrix<T, shift> &m) { 
+      std::swap(pr, m.pr); 
+      std::swap(ir,m.ir); std::swap(jc, m.jc); 
+      std::swap(nc, m.nc); std::swap(nr,m.nr);
+    }
+   
+    value_type operator()(size_type i, size_type j) const
+    { return mat_row(*this, i)[j]; }
+  };
+  
+  template <typename T, int shift> template <typename Matrix>
+  void csr_matrix<T, shift>::init_with_good_format(const Matrix &B) {
+    typedef typename linalg_traits<Matrix>::const_sub_row_type row_type;
+    if (pr) { delete[] pr; delete[] ir; delete[] jc; }
+    nc = mat_ncols(B); nr = mat_nrows(B);
+    jc = new IND_TYPE[nr+1];
+    jc[0] = shift;
+    for (size_type j = 0; j < nr; ++j) {
+      jc[j+1] = jc[j] + nnz(mat_const_row(B, j));
+    }
+    pr = new T[jc[nr]];
+    ir = new IND_TYPE[jc[nr]];
+    for (size_type j = 0; j < nr; ++j) {
+      row_type row = mat_const_row(B, j);
+      typename linalg_traits<row_type>::const_iterator
+	it = vect_const_begin(row), ite = vect_const_end(row);
+      for (size_type k = 0; it != ite; ++it, ++k)
+	{ pr[jc[j]-shift+k] = *it; ir[jc[j]-shift+k] = it.index()+shift; }
+    }
+  }
+
+  template <typename T, int shift> template <typename Matrix> 
+  void csr_matrix<T, shift>::init_with(const Matrix &A) { 
+    row_matrix<wsvector<T> > B(mat_nrows(A), mat_ncols(A)); 
+    copy(A, B); 
+    init_with_good_format(B);
+  }
+
+  template <typename T, int shift> 
+  void csr_matrix<T, shift>::init_with_identity(size_type n) {
+    if (pr) { delete[] pr; delete[] ir; delete[] jc; }
+    nc = nr = n; 
+    pr = new T[nr];
+    ir = new IND_TYPE[nr];
+    jc = new IND_TYPE[nr+1];
+    for (size_type j = 0; j < nr; ++j)
+      { ir[j] = jc[j] = shift + j; pr[j] = T(1); }
+    jc[nr] = shift + nr;
+  }
+
+  template <typename T, int shift>
+  csr_matrix<T, shift>::csr_matrix(size_type nnr, size_type nnc)
+    : nc(nnc), nr(nnr) {
+    pr = new T[1];  ir = new IND_TYPE[1];
+    jc = new IND_TYPE[nr+1];
+    for (size_type j = 0; j < nr; ++j) jc[j] = shift;
+    jc[nr] = shift;
+  }
+
+
+  template <typename T, int shift>
+  struct linalg_traits<csr_matrix<T, shift> > {
+    typedef csr_matrix<T, shift> this_type;
+    typedef typename this_type::IND_TYPE IND_TYPE;
+    typedef linalg_const is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef T value_type;
+    typedef T origin_type;
+    typedef T reference;
+    typedef abstract_sparse storage_type;
+    typedef abstract_null_type sub_col_type;
+    typedef abstract_null_type const_sub_col_type;
+    typedef abstract_null_type col_iterator;
+    typedef abstract_null_type const_col_iterator;
+    typedef abstract_null_type sub_row_type;
+    typedef cs_vector_ref<const T *, const IND_TYPE *, shift>
+    const_sub_row_type;
+    typedef sparse_compressed_iterator<const T *, const IND_TYPE *,
+				       const IND_TYPE *, shift>
+    const_row_iterator;
+    typedef abstract_null_type row_iterator;
+    typedef row_major sub_orientation;
+    typedef linalg_true index_sorted;
+    static size_type nrows(const this_type &m) { return m.nrows(); }
+    static size_type ncols(const this_type &m) { return m.ncols(); }
+    static const_row_iterator row_begin(const this_type &m)
+    { return const_row_iterator(m.pr, m.ir, m.jc, m.nc, m.pr); }
+    static const_row_iterator row_end(const this_type &m)
+    { return const_row_iterator(m.pr, m.ir, m.jc + m.nr, m.nc, m.pr); }
+    static const_sub_row_type row(const const_row_iterator &it) {
+      return const_sub_row_type(it.pr + *(it.jc) - shift,
+				it.ir + *(it.jc) - shift,
+				*(it.jc + 1) - *(it.jc), it.n);
+    }
+    static const origin_type* origin(const this_type &m) { return m.pr; }
+    static void do_clear(this_type &m) { m.do_clear(); }
+    static value_type access(const const_row_iterator &itrow, size_type j)
+    { return row(itrow)[j]; }
+  };
+
+  template <typename T, int shift>
+  std::ostream &operator <<
+    (std::ostream &o, const csr_matrix<T, shift>& m)
+  { gmm::write(o,m); return o; }
+  
+  template <typename T, int shift>
+  inline void copy(const identity_matrix &, csr_matrix<T, shift>& M)
+  { M.init_with_identity(mat_nrows(M)); }
+
+  template <typename Matrix, typename T, int shift>
+  inline void copy(const Matrix &A, csr_matrix<T, shift>& M)
+  { M.init_with(A); }
+
+  /* ******************************************************************** */
+  /*		                                            		  */
+  /*		Block matrix                                		  */
+  /*		                                            		  */
+  /* ******************************************************************** */
+
+  template <typename MAT> class block_matrix {
+  protected :
+    std::vector<MAT> blocks;
+    size_type nrowblocks_;
+    size_type ncolblocks_;
+    std::vector<sub_interval> introw, intcol;
+
+  public :
+    typedef typename linalg_traits<MAT>::value_type value_type;
+    typedef typename linalg_traits<MAT>::reference reference;
+
+    size_type nrows(void) const { return introw[nrowblocks_-1].max; }
+    size_type ncols(void) const { return intcol[ncolblocks_-1].max; }
+    size_type nrowblocks(void) const { return nrowblocks_; }
+    size_type ncolblocks(void) const { return ncolblocks_; }
+    const sub_interval &subrowinterval(size_type i) const { return introw[i]; }
+    const sub_interval &subcolinterval(size_type i) const { return intcol[i]; }
+    const MAT &block(size_type i, size_type j) const 
+    { return blocks[j*ncolblocks_+i]; }
+    MAT &block(size_type i, size_type j)
+    { return blocks[j*ncolblocks_+i]; }
+    void do_clear(void);
+    // to be done : read and write access to a component
+    value_type operator() (size_type i, size_type j) const {
+      size_type k, l;
+      for (k = 0; k < nrowblocks_; ++k)
+	if (i >= introw[k].min && i <  introw[k].max) break;
+      for (l = 0; l < nrowblocks_; ++l)
+	if (j >= introw[l].min && j <  introw[l].max) break;
+      return (block(k, l))(i - introw[k].min, j - introw[l].min);
+    }
+    reference operator() (size_type i, size_type j) {
+      size_type k, l;
+      for (k = 0; k < nrowblocks_; ++k)
+	if (i >= introw[k].min && i <  introw[k].max) break;
+      for (l = 0; l < nrowblocks_; ++l)
+	if (j >= introw[l].min && j <  introw[l].max) break;
+      return (block(k, l))(i - introw[k].min, j - introw[l].min);
+    }
+    
+    template <typename CONT> void resize(const CONT &c1, const CONT &c2);
+    template <typename CONT> block_matrix(const CONT &c1, const CONT &c2)
+    { resize(c1, c2); }
+    block_matrix(void) {}
+
+  };
+
+  template <typename MAT> struct linalg_traits<block_matrix<MAT> > {
+    typedef block_matrix<MAT> this_type;
+    typedef linalg_false is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef this_type origin_type;
+    typedef typename linalg_traits<MAT>::value_type value_type;
+    typedef typename linalg_traits<MAT>::reference reference;
+    typedef typename linalg_traits<MAT>::storage_type storage_type;
+    typedef abstract_null_type sub_row_type;       // to be done ...
+    typedef abstract_null_type const_sub_row_type; // to be done ...
+    typedef abstract_null_type row_iterator;       // to be done ...
+    typedef abstract_null_type const_row_iterator; // to be done ...
+    typedef abstract_null_type sub_col_type;       // to be done ...
+    typedef abstract_null_type const_sub_col_type; // to be done ...
+    typedef abstract_null_type col_iterator;       // to be done ...
+    typedef abstract_null_type const_col_iterator; // to be done ...
+    typedef abstract_null_type sub_orientation;    // to be done ...
+    typedef linalg_true index_sorted;
+    static size_type nrows(const this_type &m) { return m.nrows(); }
+    static size_type ncols(const this_type &m) { return m.ncols(); }
+    static origin_type* origin(this_type &m) { return &m; }
+    static const origin_type* origin(const this_type &m) { return &m; }
+    static void do_clear(this_type &m) { m.do_clear(); }
+    // access to be done ...    
+    static void resize(this_type &, size_type , size_type)
+    { GMM_ASSERT1(false, "Sorry, to be done"); }
+    static void reshape(this_type &, size_type , size_type)
+    { GMM_ASSERT1(false, "Sorry, to be done"); }
+  };
+
+  template <typename MAT> void block_matrix<MAT>::do_clear(void) { 
+    for (size_type j = 0, l = 0; j < ncolblocks_; ++j)
+      for (size_type i = 0, k = 0; i < nrowblocks_; ++i)
+	clear(block(i,j));
+  }
+
+  template <typename MAT> template <typename CONT>
+  void block_matrix<MAT>::resize(const CONT &c1, const CONT &c2) {
+    nrowblocks_ = c1.size(); ncolblocks_ = c2.size();
+    blocks.resize(nrowblocks_ * ncolblocks_);
+    intcol.resize(ncolblocks_);
+    introw.resize(nrowblocks_);
+    for (size_type j = 0, l = 0; j < ncolblocks_; ++j) {
+      intcol[j] = sub_interval(l, c2[j]); l += c2[j];
+      for (size_type i = 0, k = 0; i < nrowblocks_; ++i) {
+	if (j == 0) { introw[i] = sub_interval(k, c1[i]); k += c1[i]; }
+	block(i, j) = MAT(c1[i], c2[j]);
+      }
+    }
+  }
+
+  template <typename M1, typename M2>
+  void copy(const block_matrix<M1> &m1, M2 &m2) {
+    for (size_type j = 0; j < m1.ncolblocks(); ++j)
+      for (size_type i = 0; i < m1.nrowblocks(); ++i)
+	copy(m1.block(i,j), sub_matrix(m2, m1.subrowinterval(i), 
+				       m1.subcolinterval(j)));
+  }
+
+  template <typename M1, typename M2>
+  void copy(const block_matrix<M1> &m1, const M2 &m2)
+  { copy(m1, linalg_const_cast(m2)); }
+  
+
+  template <typename MAT, typename V1, typename V2>
+  void mult(const block_matrix<MAT> &m, const V1 &v1, V2 &v2) {
+    clear(v2);
+    typename sub_vector_type<V2 *, sub_interval>::vector_type sv;
+    for (size_type i = 0; i < m.nrowblocks() ; ++i)
+      for (size_type j = 0; j < m.ncolblocks() ; ++j) {
+	sv = sub_vector(v2, m.subrowinterval(i));
+	mult(m.block(i,j),
+	     sub_vector(v1, m.subcolinterval(j)), sv, sv);
+      }
+  }
+
+  template <typename MAT, typename V1, typename V2, typename V3>
+  void mult(const block_matrix<MAT> &m, const V1 &v1, const V2 &v2, V3 &v3) {
+    typename sub_vector_type<V3 *, sub_interval>::vector_type sv;
+    for (size_type i = 0; i < m.nrowblocks() ; ++i)
+      for (size_type j = 0; j < m.ncolblocks() ; ++j) {
+	sv = sub_vector(v3, m.subrowinterval(i));
+	if (j == 0)
+	  mult(m.block(i,j),
+	       sub_vector(v1, m.subcolinterval(j)),
+	       sub_vector(v2, m.subrowinterval(i)), sv);
+	else
+	  mult(m.block(i,j),
+	       sub_vector(v1, m.subcolinterval(j)), sv, sv);
+      }
+    
+  }
+
+  template <typename MAT, typename V1, typename V2>
+  void mult(const block_matrix<MAT> &m, const V1 &v1, const V2 &v2)
+  { mult(m, v1, linalg_const_cast(v2)); }
+
+  template <typename MAT, typename V1, typename V2, typename V3>
+  void mult(const block_matrix<MAT> &m, const V1 &v1, const V2 &v2, 
+	    const V3 &v3)
+  { mult_const(m, v1, v2, linalg_const_cast(v3)); }
+
+}
+  /* ******************************************************************** */
+  /*		                                            		  */
+  /*		Distributed matrices                                	  */
+  /*		                                            		  */
+  /* ******************************************************************** */
+
+#ifdef GMM_USES_MPI
+#include <mpi.h>
+ 
+namespace gmm { 
+  
+  template <typename T> inline MPI_Datatype mpi_type(T)
+  { GMM_ASSERT1(false, "Sorry unsupported type"); return MPI_FLOAT; }
+  inline MPI_Datatype mpi_type(double) { return MPI_DOUBLE; }
+  inline MPI_Datatype mpi_type(float) { return MPI_FLOAT; }
+  inline MPI_Datatype mpi_type(long double) { return MPI_LONG_DOUBLE; }
+#ifndef LAM_MPI
+  inline MPI_Datatype mpi_type(std::complex<float>) { return MPI_COMPLEX; }
+  inline MPI_Datatype mpi_type(std::complex<double>) { return MPI_DOUBLE_COMPLEX; }
+#endif
+  inline MPI_Datatype mpi_type(int) { return MPI_INT; }
+  inline MPI_Datatype mpi_type(unsigned int) { return MPI_UNSIGNED; }
+  inline MPI_Datatype mpi_type(size_t) {
+    if (sizeof(int) == sizeof(size_t)) return MPI_UNSIGNED;
+    if (sizeof(long) == sizeof(size_t)) return MPI_UNSIGNED_LONG;
+    return MPI_LONG_LONG;
+  }
+
+
+
+  template <typename MAT> struct mpi_distributed_matrix {
+    MAT M;
+
+    mpi_distributed_matrix(size_type n, size_type m) : M(n, m) {}
+    mpi_distributed_matrix() {}
+
+    const MAT &local_matrix(void) const { return M; }
+    MAT &local_matrix(void) { return M; }
+  };
+  
+  template <typename MAT> inline MAT &eff_matrix(MAT &m) { return m; }
+  template <typename MAT> inline
+  const MAT &eff_matrix(const MAT &m) { return m; }
+  template <typename MAT> inline
+  MAT &eff_matrix(mpi_distributed_matrix<MAT> &m) { return m.M; }
+  template <typename MAT> inline
+  const MAT &eff_matrix(const mpi_distributed_matrix<MAT> &m) { return m.M; }
+  
+
+  template <typename MAT1, typename MAT2>
+  inline void copy(const mpi_distributed_matrix<MAT1> &m1,
+		   mpi_distributed_matrix<MAT2> &m2)
+  { copy(eff_matrix(m1), eff_matrix(m2)); }
+  template <typename MAT1, typename MAT2>
+  inline void copy(const mpi_distributed_matrix<MAT1> &m1,
+		   const mpi_distributed_matrix<MAT2> &m2)
+  { copy(m1.M, m2.M); }
+  
+  template <typename MAT1, typename MAT2>
+  inline void copy(const mpi_distributed_matrix<MAT1> &m1, MAT2 &m2)
+  { copy(m1.M, m2); }
+  template <typename MAT1, typename MAT2>
+  inline void copy(const mpi_distributed_matrix<MAT1> &m1, const MAT2 &m2)
+  { copy(m1.M, m2); }
+  
+
+  template <typename MATSP, typename V1, typename V2> inline
+  typename strongest_value_type3<V1,V2,MATSP>::value_type
+  vect_sp(const mpi_distributed_matrix<MATSP> &ps, const V1 &v1,
+	  const V2 &v2) {
+    typedef typename strongest_value_type3<V1,V2,MATSP>::value_type T;
+    T res = vect_sp(ps.M, v1, v2), rest;
+    MPI_Allreduce(&res, &rest, 1, mpi_type(T()), MPI_SUM,MPI_COMM_WORLD);
+    return rest;
+  }
+
+  template <typename MAT, typename V1, typename V2>
+  inline void mult_add(const mpi_distributed_matrix<MAT> &m, const V1 &v1,
+		       V2 &v2) {
+    typedef typename linalg_traits<V2>::value_type T;
+    std::vector<T> v3(vect_size(v2)), v4(vect_size(v2));
+    static double tmult_tot = 0.0;
+    static double tmult_tot2 = 0.0;
+    double t_ref = MPI_Wtime();
+    gmm::mult(m.M, v1, v3);
+    if (is_sparse(v2)) GMM_WARNING2("Using a plain temporary, here.");
+    double t_ref2 = MPI_Wtime();
+    MPI_Allreduce(&(v3[0]), &(v4[0]),gmm::vect_size(v2), mpi_type(T()),
+		  MPI_SUM,MPI_COMM_WORLD);
+    tmult_tot2 = MPI_Wtime()-t_ref2;
+    cout << "reduce mult mpi = " << tmult_tot2 << endl;
+    gmm::add(v4, v2);
+    tmult_tot = MPI_Wtime()-t_ref;
+    cout << "tmult mpi = " << tmult_tot << endl;
+  }
+
+  template <typename MAT, typename V1, typename V2>
+  void mult_add(const mpi_distributed_matrix<MAT> &m, const V1 &v1,
+		const V2 &v2_)
+  { mult_add(m, v1, const_cast<V2 &>(v2_)); }
+
+  template <typename MAT, typename V1, typename V2>
+  inline void mult(const mpi_distributed_matrix<MAT> &m, const V1 &v1,
+		   const V2 &v2_)
+  { V2 &v2 = const_cast<V2 &>(v2_); clear(v2); mult_add(m, v1, v2); }
+
+  template <typename MAT, typename V1, typename V2>
+  inline void mult(const mpi_distributed_matrix<MAT> &m, const V1 &v1,
+		   V2 &v2)
+  { clear(v2); mult_add(m, v1, v2); }
+
+  template <typename MAT, typename V1, typename V2, typename V3>
+  inline void mult(const mpi_distributed_matrix<MAT> &m, const V1 &v1,
+		   const V2 &v2, const V3 &v3_)
+  { V3 &v3 = const_cast<V3 &>(v3_); gmm::copy(v2, v3); mult_add(m, v1, v3); }
+
+  template <typename MAT, typename V1, typename V2, typename V3>
+  inline void mult(const mpi_distributed_matrix<MAT> &m, const V1 &v1,
+		   const V2 &v2, V3 &v3)
+  { gmm::copy(v2, v3); mult_add(m, v1, v3); }
+  
+
+  template <typename MAT> inline
+  size_type mat_nrows(const mpi_distributed_matrix<MAT> &M) 
+  { return mat_nrows(M.M); }
+  template <typename MAT> inline
+  size_type mat_ncols(const mpi_distributed_matrix<MAT> &M) 
+  { return mat_nrows(M.M); }
+  template <typename MAT> inline
+  void resize(mpi_distributed_matrix<MAT> &M, size_type m, size_type n)
+  { resize(M.M, m, n); }
+  template <typename MAT> inline void clear(mpi_distributed_matrix<MAT> &M)
+  { clear(M.M); }
+  
+
+  // For compute reduced system
+  template <typename MAT1, typename MAT2> inline
+  void mult(const MAT1 &M1, const mpi_distributed_matrix<MAT2> &M2,
+	    mpi_distributed_matrix<MAT2> &M3)
+  { mult(M1, M2.M, M3.M); }
+  template <typename MAT1, typename MAT2> inline
+  void mult(const mpi_distributed_matrix<MAT2> &M2,
+	    const MAT1 &M1, mpi_distributed_matrix<MAT2> &M3)
+  { mult(M2.M, M1, M3.M); }
+  template <typename MAT1, typename MAT2, typename MAT3> inline
+  void mult(const MAT1 &M1, const mpi_distributed_matrix<MAT2> &M2,
+		   MAT3 &M3)
+  { mult(M1, M2.M, M3); }
+  template <typename MAT1, typename MAT2, typename MAT3> inline
+  void mult(const MAT1 &M1, const mpi_distributed_matrix<MAT2> &M2,
+		   const MAT3 &M3)
+  { mult(M1, M2.M, M3); }
+
+  template <typename M, typename SUBI1, typename SUBI2>
+  struct sub_matrix_type<const mpi_distributed_matrix<M> *, SUBI1, SUBI2>
+  { typedef abstract_null_type matrix_type; };
+
+  template <typename M, typename SUBI1, typename SUBI2>
+  struct sub_matrix_type<mpi_distributed_matrix<M> *, SUBI1, SUBI2>
+  { typedef abstract_null_type matrix_type; };
+
+  template <typename M, typename SUBI1, typename SUBI2>  inline
+  typename select_return<typename sub_matrix_type<const M *, SUBI1, SUBI2>
+  ::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI2>::matrix_type,
+   M *>::return_type
+   sub_matrix(mpi_distributed_matrix<M> &m, const SUBI1 &si1, const SUBI2 &si2)
+  { return sub_matrix(m.M, si1, si2); }
+
+  template <typename MAT, typename SUBI1, typename SUBI2>  inline
+  typename select_return<typename sub_matrix_type<const MAT *, SUBI1, SUBI2>
+  ::matrix_type, typename sub_matrix_type<MAT *, SUBI1, SUBI2>::matrix_type,
+			 const MAT *>::return_type
+  sub_matrix(const mpi_distributed_matrix<MAT> &m, const SUBI1 &si1,
+	     const SUBI2 &si2)
+  { return sub_matrix(m.M, si1, si2);  }
+
+  template <typename M, typename SUBI1>  inline
+    typename select_return<typename sub_matrix_type<const M *, SUBI1, SUBI1>
+    ::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI1>::matrix_type,
+    M *>::return_type
+  sub_matrix(mpi_distributed_matrix<M> &m, const SUBI1 &si1) 
+  { return sub_matrix(m.M, si1, si1); }
+
+  template <typename M, typename SUBI1>  inline
+    typename select_return<typename sub_matrix_type<const M *, SUBI1, SUBI1>
+    ::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI1>::matrix_type,
+    const M *>::return_type
+  sub_matrix(const mpi_distributed_matrix<M> &m, const SUBI1 &si1)
+  { return sub_matrix(m.M, si1, si1); }
+
+
+  template <typename L> struct transposed_return<const mpi_distributed_matrix<L> *> 
+  { typedef abstract_null_type return_type; };
+  template <typename L> struct transposed_return<mpi_distributed_matrix<L> *> 
+  { typedef abstract_null_type return_type; };
+  
+  template <typename L> inline typename transposed_return<const L *>::return_type
+  transposed(const mpi_distributed_matrix<L> &l)
+  { return transposed(l.M); }
+
+  template <typename L> inline typename transposed_return<L *>::return_type
+  transposed(mpi_distributed_matrix<L> &l)
+  { return transposed(l.M); }
+
+
+  template <typename MAT>
+  struct linalg_traits<mpi_distributed_matrix<MAT> > {
+    typedef mpi_distributed_matrix<MAT> this_type;
+    typedef MAT origin_type;
+    typedef linalg_false is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef typename linalg_traits<MAT>::value_type value_type;
+    typedef typename linalg_traits<MAT>::reference reference;
+    typedef typename linalg_traits<MAT>::storage_type storage_type;
+    typedef abstract_null_type sub_row_type;
+    typedef abstract_null_type const_sub_row_type;
+    typedef abstract_null_type row_iterator;
+    typedef abstract_null_type const_row_iterator;
+    typedef abstract_null_type sub_col_type;
+    typedef abstract_null_type const_sub_col_type;
+    typedef abstract_null_type col_iterator;
+    typedef abstract_null_type const_col_iterator;
+    typedef abstract_null_type sub_orientation;
+    typedef abstract_null_type index_sorted;
+    static size_type nrows(const this_type &m) { return nrows(m.M); }
+    static size_type ncols(const this_type &m) { return ncols(m.M); }
+    static void do_clear(this_type &m) { clear(m.M); }
+  };
+
+}
+
+
+#endif // GMM_USES_MPI
+
+namespace std {
+  template <typename V>
+  void swap(gmm::row_matrix<V> &m1, gmm::row_matrix<V> &m2)
+  { m1.swap(m2); }
+  template <typename V>
+  void swap(gmm::col_matrix<V> &m1, gmm::col_matrix<V> &m2)
+  { m1.swap(m2); }
+  template <typename T>
+  void swap(gmm::dense_matrix<T> &m1, gmm::dense_matrix<T> &m2)
+  { m1.swap(m2); }
+  template <typename T, int shift> void 
+  swap(gmm::csc_matrix<T,shift> &m1, gmm::csc_matrix<T,shift> &m2)
+  { m1.swap(m2); }
+  template <typename T, int shift> void 
+  swap(gmm::csr_matrix<T,shift> &m1, gmm::csr_matrix<T,shift> &m2)
+  { m1.swap(m2); }
+}
+
+
+
+
+#endif /* GMM_MATRIX_H__ */
diff --git a/Contrib/gmm/gmm_modified_gram_schmidt.h b/Contrib/gmm/gmm_modified_gram_schmidt.h
new file mode 100755
index 0000000..213cf7a
--- /dev/null
+++ b/Contrib/gmm/gmm_modified_gram_schmidt.h
@@ -0,0 +1,97 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 1997-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_modified_gram_schmidt.h
+   @author  Andrew Lumsdaine <lums at osl.iu.edu>, Lie-Quan Lee     <llee at osl.iu.edu>
+   @date October 13, 2002.
+   @brief Modified Gram-Schmidt orthogonalization
+*/
+
+#ifndef GMM_MODIFIED_GRAM_SCHMIDT_H
+#define GMM_MODIFIED_GRAM_SCHMIDT_H
+
+#include "gmm_kernel.h"
+
+namespace gmm {
+
+  template <typename T>
+  class modified_gram_schmidt {
+  protected:
+    typedef dense_matrix<T> MAT;
+    MAT M;
+
+  public:
+
+    modified_gram_schmidt(int restart, size_t s) : M(s, restart+1) {}
+
+    typename linalg_traits<MAT>::const_sub_col_type
+      operator[](size_t i) const { return mat_const_col(M, i); }
+
+    typename linalg_traits<MAT>::sub_col_type
+      operator[](size_t i) { return mat_col(M, i); }
+
+    inline size_type nrows(void) const { return M.nrows(); }
+    inline size_type ncols(void) const { return M.ncols(); }
+    MAT &mat(void) { return M; }
+    const MAT &mat(void) const { return M; }
+    
+  };
+
+  template <typename T, typename VecHi> inline
+  void orthogonalize(modified_gram_schmidt<T>& V, const VecHi& Hi_, size_t i) {
+    VecHi& Hi = const_cast<VecHi&>(Hi_);
+    
+    for (size_t k = 0; k <= i; k++) {
+      Hi[k] = gmm::vect_hp(V[i+1], V[k]);
+      gmm::add(gmm::scaled(V[k], -Hi[k]), V[i+1]);
+    }
+  }
+
+  template <typename T, typename VecHi>
+  void orthogonalize_with_refinment(modified_gram_schmidt<T>& V,
+				    const VecHi& Hi_, size_t i) {
+    VecHi& Hi = const_cast<VecHi&>(Hi_);
+    orthogonalize(V, Hi_, i);
+    
+    sub_interval SUBI(0, V.nrows()), SUBJ(0, i+1);
+    std::vector<T> corr(i+1);
+    gmm::mult(conjugated(sub_matrix(V.mat(), SUBI, SUBJ)),
+	      V[i+1], corr);
+    gmm::mult(sub_matrix(V.mat(), SUBI, SUBJ),
+	      scaled(corr, T(-1)), V[i+1],V[i+1]);
+    gmm::add(corr, sub_vector(Hi, SUBJ));
+  }
+  
+  template <typename T, typename VecS, typename VecX>
+  void combine(modified_gram_schmidt<T>& V, const VecS& s, VecX& x, size_t i)
+  { for (size_t j = 0; j < i; ++j) gmm::add(gmm::scaled(V[j], s[j]), x); }
+}
+
+#endif
diff --git a/Contrib/gmm/gmm_opt.h b/Contrib/gmm/gmm_opt.h
new file mode 100755
index 0000000..2dfd9f8
--- /dev/null
+++ b/Contrib/gmm/gmm_opt.h
@@ -0,0 +1,122 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_opt.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date July 9, 2003.
+   @brief Optimization for some small cases (inversion of 2x2 matrices etc.)
+*/
+#ifndef GMM_OPT_H__
+#define GMM_OPT_H__
+
+namespace gmm {
+
+  /* ********************************************************************* */
+  /*    Optimized determinant and inverse for small matrices (2x2 and 3x3) */
+  /*    with dense_matrix<T>.                                              */
+  /* ********************************************************************* */
+
+  template <typename T>  T lu_det(const dense_matrix<T> &A) {
+    size_type n(mat_nrows(A));
+    if (n) {
+      const T *p = &(A(0,0));
+      switch (n) {
+      case 1 : return (*p);
+      case 2 : return (*p) * (*(p+3)) - (*(p+1)) * (*(p+2));
+      case 3 : return (*p) * ((*(p+4)) * (*(p+8)) - (*(p+5)) * (*(p+7)))
+		 - (*(p+1)) * ((*(p+3)) * (*(p+8)) - (*(p+5)) * (*(p+6)))
+		 + (*(p+2)) * ((*(p+3)) * (*(p+7)) - (*(p+4)) * (*(p+6)));
+      default :
+	{
+	  dense_matrix<T> B(mat_nrows(A), mat_ncols(A));
+	  std::vector<size_type> ipvt(mat_nrows(A));
+	  gmm::copy(A, B);
+	  lu_factor(B, ipvt);
+	  return lu_det(B, ipvt);	
+	}
+      }
+    }
+    return T(1);
+  }
+
+  template <typename T> T lu_inverse(const dense_matrix<T> &A_) {
+    dense_matrix<T>& A = const_cast<dense_matrix<T> &>(A_);
+    size_type N = mat_nrows(A);
+    T det(1);
+    if (N) {
+      T *p = &(A(0,0));
+      if (N <= 3) {
+	switch (N) {
+	  case 1 : {
+	    det = *p;
+	    GMM_ASSERT1(det!=T(0), "non invertible matrix");
+	    *p = T(1) / det; 
+	  } break;
+	  case 2 : {
+	    det = (*p) * (*(p+3)) - (*(p+1)) * (*(p+2));
+	    GMM_ASSERT1(det!=T(0), "non invertible matrix");
+	    std::swap(*p, *(p+3));
+	    *p++ /= det; *p++ /= -det; *p++ /= -det; *p++ /= det; 
+	  } break;
+	  case 3 : {
+	    T a, b, c, d, e, f, g, h, i;
+	    a =   (*(p+4)) * (*(p+8)) - (*(p+5)) * (*(p+7));
+	    b = - (*(p+1)) * (*(p+8)) + (*(p+2)) * (*(p+7));
+	    c =   (*(p+1)) * (*(p+5)) - (*(p+2)) * (*(p+4));
+	    d = - (*(p+3)) * (*(p+8)) + (*(p+5)) * (*(p+6));
+	    e =   (*(p+0)) * (*(p+8)) - (*(p+2)) * (*(p+6));
+	    f = - (*(p+0)) * (*(p+5)) + (*(p+2)) * (*(p+3));
+	    g =   (*(p+3)) * (*(p+7)) - (*(p+4)) * (*(p+6));
+	    h = - (*(p+0)) * (*(p+7)) + (*(p+1)) * (*(p+6));
+	    i =   (*(p+0)) * (*(p+4)) - (*(p+1)) * (*(p+3));
+	    det = (*p) * a + (*(p+1)) * d + (*(p+2)) * g;
+	    GMM_ASSERT1(det!=T(0), "non invertible matrix");
+	    *p++ = a / det; *p++ = b / det; *p++ = c / det; 
+	    *p++ = d / det; *p++ = e / det; *p++ = f / det; 
+	    *p++ = g / det; *p++ = h / det; *p++ = i / det; 
+	  } break;
+	}
+      }
+      else {
+	dense_matrix<T> B(mat_nrows(A), mat_ncols(A));
+	std::vector<int> ipvt(mat_nrows(A));
+	gmm::copy(A, B);
+	size_type info = lu_factor(B, ipvt);
+	GMM_ASSERT1(!info, "non invertible matrix");
+	lu_inverse(B, ipvt, A);
+	return lu_det(B, ipvt);
+      }
+    }
+    return det;
+  }
+  
+}
+
+#endif //  GMM_OPT_H__
diff --git a/Contrib/gmm/gmm_precond.h b/Contrib/gmm/gmm_precond.h
new file mode 100755
index 0000000..7e95dc8
--- /dev/null
+++ b/Contrib/gmm/gmm_precond.h
@@ -0,0 +1,64 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2004-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+#ifndef GMM_PRECOND_H
+#define GMM_PRECOND_H
+
+#include "gmm_kernel.h"
+
+/** @file gmm_precond.h
+    @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+    @date March 29, 2004.
+    @brief gmm preconditioners.
+ */
+
+/* Preconditioner concept :                                                */
+/*                                                                         */
+/* A the matrix, P the preconditioner PA well conditioned.                 */
+/* PRECOND precontioner type.                                              */
+/* mult(P, v, w) :  w <- P v                                               */
+/* transposed_mult(P, v, w)       : w <- transposed(P) v                   */
+/* left_mult(P, v, w)             : see qmr solver                         */
+/* right_mult(P, v, w)            : see qmr solver                         */
+/* transposed_left_mult(P, v, w)  : see qmr solver                         */
+/* transposed_right_mult(P, v, w) : see qmr solver                         */
+/*                                                                         */
+/* PRECOND P() : empty preconditioner.                                     */
+/* PRECOND P(A, ...) : preconditioner for the matrix A, with optional      */
+/*                     parameters                                          */
+/* PRECOND(...)  : empty precondtioner with parameters set.                */
+/* P.build_with(A) : build a precondtioner for A.                          */
+/*                                                                         */
+/* *********************************************************************** */
+
+
+
+
+#endif 
+
diff --git a/Contrib/gmm/gmm_precond_diagonal.h b/Contrib/gmm/gmm_precond_diagonal.h
new file mode 100755
index 0000000..e3f74c6
--- /dev/null
+++ b/Contrib/gmm/gmm_precond_diagonal.h
@@ -0,0 +1,131 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_precond_diagonal.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date June 5, 2003.
+   @brief Diagonal matrix preconditoner.
+*/
+
+#ifndef GMM_PRECOND_DIAGONAL_H
+#define GMM_PRECOND_DIAGONAL_H
+
+#include "gmm_precond.h"
+
+namespace gmm {
+
+  /** Diagonal preconditioner. */
+  template<typename Matrix> struct diagonal_precond {
+    typedef typename linalg_traits<Matrix>::value_type value_type;
+    typedef typename number_traits<value_type>::magnitude_type magnitude_type;
+
+    std::vector<magnitude_type> diag;
+
+    void build_with(const Matrix &M) {
+      diag.resize(mat_nrows(M));
+      for (size_type i = 0; i < mat_nrows(M); ++i) {
+	magnitude_type x = gmm::abs(M(i, i));
+	if (x == magnitude_type(0)) {
+	  x = magnitude_type(1);
+	  GMM_WARNING2("The matrix has a zero on its diagonal");
+	}
+	diag[i] = magnitude_type(1) / x;
+      }
+    }
+    size_type memsize() const { return sizeof(*this) + diag.size() * sizeof(value_type); }
+    diagonal_precond(const Matrix &M) { build_with(M); }
+    diagonal_precond(void) {}
+  };
+
+  template <typename Matrix, typename V2> inline
+  void mult_diag_p(const diagonal_precond<Matrix>& P, V2 &v2, abstract_sparse){
+    typename linalg_traits<V2>::iterator it = vect_begin(v2),
+      ite = vect_end(v2);
+    for (; it != ite; ++it) *it *= P.diag[it.index()];
+  }
+
+  template <typename Matrix, typename V2> inline
+  void mult_diag_p(const diagonal_precond<Matrix>& P,V2 &v2, abstract_skyline)
+    { mult_diag_p(P, v2, abstract_sparse()); }
+
+  template <typename Matrix, typename V2> inline
+  void mult_diag_p(const diagonal_precond<Matrix>& P, V2 &v2, abstract_dense){
+    for (size_type i = 0; i < P.diag.size(); ++i) v2[i] *= P.diag[i];
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void mult(const diagonal_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    GMM_ASSERT2(P.diag.size() == vect_size(v2),"dimensions mismatch");
+    copy(v1, v2);
+    mult_diag_p(P, v2, typename linalg_traits<V2>::storage_type());
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_mult(const diagonal_precond<Matrix>& P,const V1 &v1,V2 &v2) {
+    mult(P, v1, v2);
+  }
+  
+  // # define DIAG_LEFT_MULT_SQRT
+  
+  template <typename Matrix, typename V1, typename V2> inline
+  void left_mult(const diagonal_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    GMM_ASSERT2(P.diag.size() == vect_size(v2), "dimensions mismatch");
+    copy(v1, v2);
+#   ifdef DIAG_LEFT_MULT_SQRT
+    for (size_type i= 0; i < P.diag.size(); ++i) v2[i] *= gmm::sqrt(P.diag[i]);
+#   else
+    for (size_type i= 0; i < P.diag.size(); ++i) v2[i] *= P.diag[i];
+#   endif
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_left_mult(const diagonal_precond<Matrix>& P,
+			    const V1 &v1, V2 &v2)
+    { left_mult(P, v1, v2); }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void right_mult(const diagonal_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    typedef typename linalg_traits<Matrix>::value_type T;
+    GMM_ASSERT2(P.diag.size() == vect_size(v2), "dimensions mismatch");
+    copy(v1, v2);
+#   ifdef DIAG_LEFT_MULT_SQRT    
+    for (size_type i= 0; i < P.diag.size(); ++i) v2[i] *= gmm::sqrt(P.diag[i]);
+#   endif
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_right_mult(const diagonal_precond<Matrix>& P,
+			    const V1 &v1, V2 &v2)
+    { right_mult(P, v1, v2); }
+
+}
+
+#endif 
+
diff --git a/Contrib/gmm/gmm_precond_ildlt.h b/Contrib/gmm/gmm_precond_ildlt.h
new file mode 100755
index 0000000..5c4eece
--- /dev/null
+++ b/Contrib/gmm/gmm_precond_ildlt.h
@@ -0,0 +1,286 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+// This file is a modified version of cholesky.h from ITL.
+// See http://osl.iu.edu/research/itl/
+// Following the corresponding Copyright notice.
+//===========================================================================
+//
+// Copyright (c) 1997-2001, The Trustees of Indiana University.
+// All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//    * Redistributions of source code must retain the above copyright
+//      notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above copyright
+//      notice, this list of conditions and the following disclaimer in the
+//      documentation and/or other materials provided with the distribution.
+//    * Neither the name of the University of California, Berkeley nor the
+//      names of its contributors may be used to endorse or promote products
+//      derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE  IS  PROVIDED  BY  THE TRUSTEES  OF  INDIANA UNIVERSITY  AND
+// CONTRIBUTORS  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,  INCLUDING,
+// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS
+// FOR  A PARTICULAR PURPOSE ARE DISCLAIMED. IN  NO  EVENT SHALL THE TRUSTEES
+// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY,  OR CONSEQUENTIAL DAMAGES (INCLUDING,  BUT
+// NOT  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA,  OR PROFITS;  OR BUSINESS  INTERRUPTION)  HOWEVER  CAUSED AND ON ANY
+// THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT  LIABILITY, OR TORT
+// (INCLUDING  NEGLIGENCE  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+// THIS  SOFTWARE,  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//===========================================================================
+
+#ifndef GMM_PRECOND_ILDLT_H
+#define GMM_PRECOND_ILDLT_H
+
+/**@file gmm_precond_ildlt.h
+   @author Andrew Lumsdaine <lums at osl.iu.edu>
+   @author Lie-Quan Lee <llee at osl.iu.edu>
+   @author Yves Renard <yves.renard at insa-lyon.fr>
+   @date June 5, 2003.
+   @brief Incomplete Level 0 ILDLT Preconditioner.
+*/
+
+#include "gmm_precond.h"
+
+namespace gmm {
+
+  /** Incomplete Level 0 LDLT Preconditioner.
+      
+  For use with symmetric real or hermitian complex sparse matrices.
+
+  Notes: The idea under a concrete Preconditioner such as Incomplete
+  Cholesky is to create a Preconditioner object to use in iterative
+  methods.
+
+
+  Y. Renard : Transformed in LDLT for stability reason.
+  
+  U=LT is stored in csr format. D is stored on the diagonal of U.
+  */
+  template <typename Matrix>
+  class ildlt_precond {
+
+  public :
+    typedef typename linalg_traits<Matrix>::value_type value_type;
+    typedef typename number_traits<value_type>::magnitude_type magnitude_type;
+    typedef csr_matrix_ref<value_type *, size_type *, size_type *, 0> tm_type;
+
+    tm_type U;
+
+  protected :
+    std::vector<value_type> Tri_val;
+    std::vector<size_type> Tri_ind, Tri_ptr;
+ 
+    template<typename M> void do_ildlt(const M& A, row_major);
+    void do_ildlt(const Matrix& A, col_major);
+
+  public:
+
+    size_type nrows(void) const { return mat_nrows(U); }
+    size_type ncols(void) const { return mat_ncols(U); }
+    value_type &D(size_type i) { return Tri_val[Tri_ptr[i]]; }
+    const value_type &D(size_type i) const { return Tri_val[Tri_ptr[i]]; }
+    ildlt_precond(void) {}
+    void build_with(const Matrix& A) {
+      Tri_ptr.resize(mat_nrows(A)+1);
+      do_ildlt(A, typename principal_orientation_type<typename
+		  linalg_traits<Matrix>::sub_orientation>::potype());
+    }
+    ildlt_precond(const Matrix& A)  { build_with(A); }
+    size_type memsize() const { 
+      return sizeof(*this) + 
+	Tri_val.size() * sizeof(value_type) + 
+	(Tri_ind.size()+Tri_ptr.size()) * sizeof(size_type); 
+    }
+  };
+
+  template <typename Matrix> template<typename M>
+  void ildlt_precond<Matrix>::do_ildlt(const M& A, row_major) {
+    typedef typename linalg_traits<Matrix>::storage_type store_type;
+    typedef value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+    
+    size_type Tri_loc = 0, n = mat_nrows(A), d, g, h, i, j, k;
+    if (n == 0) return;
+    T z, zz;
+    Tri_ptr[0] = 0;
+    R prec = default_tol(R());
+    R max_pivot = gmm::abs(A(0,0)) * prec;
+    
+    for (int count = 0; count < 2; ++count) {
+      if (count) { Tri_val.resize(Tri_loc); Tri_ind.resize(Tri_loc); }
+      for (Tri_loc = 0, i = 0; i < n; ++i) {
+	typedef typename linalg_traits<M>::const_sub_row_type row_type;
+	row_type row = mat_const_row(A, i);
+        typename linalg_traits<row_type>::const_iterator
+	  it = vect_const_begin(row), ite = vect_const_end(row);
+
+	if (count) { Tri_val[Tri_loc] = T(0); Tri_ind[Tri_loc] = i; }
+	++Tri_loc; // diagonal element
+
+	for (k = 0; it != ite; ++it, ++k) {
+	  j = index_of_it(it, k, store_type());
+	  if (i == j) {
+	    if (count) Tri_val[Tri_loc-1] = *it; 
+	  }
+	  else if (j > i) {
+	    if (count) { Tri_val[Tri_loc] = *it; Tri_ind[Tri_loc]=j; }
+	    ++Tri_loc;
+	  }
+	}
+	Tri_ptr[i+1] = Tri_loc;
+      }
+    }
+    
+    if (A(0,0) == T(0)) {
+      Tri_val[Tri_ptr[0]] = T(1);
+      GMM_WARNING2("pivot 0 is too small");
+    }
+    
+    for (k = 0; k < n; k++) {
+      d = Tri_ptr[k];
+      z = T(gmm::real(Tri_val[d])); Tri_val[d] = z;
+      if (gmm::abs(z) <= max_pivot) {
+	Tri_val[d] = z = T(1);
+	GMM_WARNING2("pivot " << k << " is too small [" << gmm::abs(z) << "]");
+      }
+      max_pivot = std::max(max_pivot, std::min(gmm::abs(z) * prec, R(1)));
+      
+      for (i = d + 1; i < Tri_ptr[k+1]; ++i) Tri_val[i] /= z;
+      for (i = d + 1; i < Tri_ptr[k+1]; ++i) {
+	zz = gmm::conj(Tri_val[i] * z);
+	h = Tri_ind[i];
+	g = i;
+	
+	for (j = Tri_ptr[h] ; j < Tri_ptr[h+1]; ++j)
+	  for ( ; g < Tri_ptr[k+1] && Tri_ind[g] <= Tri_ind[j]; ++g)
+	    if (Tri_ind[g] == Tri_ind[j])
+	      Tri_val[j] -= zz * Tri_val[g];
+      }
+    }
+    U = tm_type(&(Tri_val[0]), &(Tri_ind[0]), &(Tri_ptr[0]),
+			n, mat_ncols(A));
+  }
+  
+  template <typename Matrix>
+  void ildlt_precond<Matrix>::do_ildlt(const Matrix& A, col_major)
+  { do_ildlt(gmm::conjugated(A), row_major()); }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void mult(const ildlt_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    gmm::copy(v1, v2);
+    gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
+    for (size_type i = 0; i < mat_nrows(P.U); ++i) v2[i] /= P.D(i);
+    gmm::upper_tri_solve(P.U, v2, true);
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_mult(const ildlt_precond<Matrix>& P,const V1 &v1,V2 &v2)
+  { mult(P, v1, v2); }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void left_mult(const ildlt_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    copy(v1, v2);
+    gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
+    for (size_type i = 0; i < mat_nrows(P.U); ++i) v2[i] /= P.D(i);
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void right_mult(const ildlt_precond<Matrix>& P, const V1 &v1, V2 &v2)
+  { copy(v1, v2); gmm::upper_tri_solve(P.U, v2, true);  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_left_mult(const ildlt_precond<Matrix>& P, const V1 &v1,
+			    V2 &v2) {
+    copy(v1, v2);
+    gmm::upper_tri_solve(P.U, v2, true);
+    for (size_type i = 0; i < mat_nrows(P.U); ++i) v2[i] /= P.D(i);
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_right_mult(const ildlt_precond<Matrix>& P, const V1 &v1,
+			     V2 &v2)
+  { copy(v1, v2); gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true); }
+
+
+
+  // for compatibility with old versions
+
+  template <typename Matrix>
+  struct cholesky_precond : public ildlt_precond<Matrix> {
+    cholesky_precond(const Matrix& A) : ildlt_precond<Matrix>(A) {}
+    cholesky_precond(void) {}
+  } IS_DEPRECATED;
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void mult(const cholesky_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    gmm::copy(v1, v2);
+    gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
+    for (size_type i = 0; i < mat_nrows(P.U); ++i) v2[i] /= P.D(i);
+    gmm::upper_tri_solve(P.U, v2, true);
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_mult(const cholesky_precond<Matrix>& P,const V1 &v1,V2 &v2)
+  { mult(P, v1, v2); }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void left_mult(const cholesky_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    copy(v1, v2);
+    gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
+    for (size_type i = 0; i < mat_nrows(P.U); ++i) v2[i] /= P.D(i);
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void right_mult(const cholesky_precond<Matrix>& P, const V1 &v1, V2 &v2)
+  { copy(v1, v2); gmm::upper_tri_solve(P.U, v2, true);  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_left_mult(const cholesky_precond<Matrix>& P, const V1 &v1,
+			    V2 &v2) {
+    copy(v1, v2);
+    gmm::upper_tri_solve(P.U, v2, true);
+    for (size_type i = 0; i < mat_nrows(P.U); ++i) v2[i] /= P.D(i);
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_right_mult(const cholesky_precond<Matrix>& P, const V1 &v1,
+			     V2 &v2)
+  { copy(v1, v2); gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true); }
+  
+}
+
+#endif 
+
diff --git a/Contrib/gmm/gmm_precond_ildltt.h b/Contrib/gmm/gmm_precond_ildltt.h
new file mode 100755
index 0000000..8afa9e7
--- /dev/null
+++ b/Contrib/gmm/gmm_precond_ildltt.h
@@ -0,0 +1,217 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_precond_ildltt.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date June 30, 2003.
+   @brief incomplete LDL^t (cholesky) preconditioner with fill-in and threshold.
+*/
+
+#ifndef GMM_PRECOND_ILDLTT_H
+#define GMM_PRECOND_ILDLTT_H
+
+// Store U = LT and D in indiag. On each line, the fill-in is the number
+// of non-zero elements on the line of the original matrix plus K, except if
+// the matrix is dense. In this case the fill-in is K on each line.
+
+#include "gmm_precond_ilut.h"
+
+namespace gmm {
+  /** incomplete LDL^t (cholesky) preconditioner with fill-in and
+      threshold. */
+  template <typename Matrix>
+  class ildltt_precond  {
+  public :
+    typedef typename linalg_traits<Matrix>::value_type value_type;
+    typedef typename number_traits<value_type>::magnitude_type magnitude_type;
+    
+    typedef rsvector<value_type> svector;
+
+    row_matrix<svector> U;
+    std::vector<magnitude_type> indiag;
+
+  protected:
+    size_type K;
+    double eps;    
+
+    template<typename M> void do_ildltt(const M&, row_major);
+    void do_ildltt(const Matrix&, col_major);
+
+  public:
+    void build_with(const Matrix& A) {
+      gmm::resize(U, mat_nrows(A), mat_ncols(A));
+      indiag.resize(std::min(mat_nrows(A), mat_ncols(A)));
+      do_ildltt(A, typename principal_orientation_type<typename
+		linalg_traits<Matrix>::sub_orientation>::potype());
+    }
+    ildltt_precond(const Matrix& A, int k_, double eps_) 
+      : U(mat_nrows(A),mat_ncols(A)), K(k_), eps(eps_) { build_with(A); }
+    ildltt_precond(void) { K=10; eps = 1E-7; }
+    ildltt_precond(size_type k_, double eps_) :  K(k_), eps(eps_) {}
+    size_type memsize() const { 
+      return sizeof(*this) + nnz(U)*sizeof(value_type) + indiag.size() * sizeof(magnitude_type);
+    }    
+  };
+
+  template<typename Matrix> template<typename M> 
+  void ildltt_precond<Matrix>::do_ildltt(const M& A,row_major) {
+    typedef value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+
+    size_type n = mat_nrows(A);
+    if (n == 0) return;
+    svector w(n);
+    T tmp;
+    R prec = default_tol(R()), max_pivot = gmm::abs(A(0,0)) * prec;
+
+    gmm::clear(U);
+    for (size_type i = 0; i < n; ++i) {
+      gmm::copy(mat_const_row(A, i), w);
+      double norm_row = gmm::vect_norm2(w);
+
+      for (size_type krow = 0, k; krow < w.nb_stored(); ++krow) {
+	typename svector::iterator wk = w.begin() + krow;
+	if ((k = wk->c) >= i) break;
+ 	if (gmm::is_complex(wk->e)) {
+ 	  tmp = gmm::conj(U(k, i))/indiag[k]; // not completely satisfactory ..
+ 	  gmm::add(scaled(mat_row(U, k), -tmp), w);
+ 	}
+ 	else {
+	  tmp = wk->e;
+	  if (gmm::abs(tmp) < eps * norm_row) { w.sup(k); --krow; } 
+	  else { wk->e += tmp; gmm::add(scaled(mat_row(U, k), -tmp), w); }
+	}
+      }
+      tmp = w[i];
+
+      if (gmm::abs(gmm::real(tmp)) <= max_pivot)
+	{ GMM_WARNING2("pivot " << i << " is too small"); tmp = T(1); }
+
+      max_pivot = std::max(max_pivot, std::min(gmm::abs(tmp) * prec, R(1)));
+      indiag[i] = R(1) / gmm::real(tmp);
+      gmm::clean(w, eps * norm_row);
+      gmm::scale(w, T(indiag[i]));
+      std::sort(w.begin(), w.end(), elt_rsvector_value_less_<T>());
+      typename svector::const_iterator wit = w.begin(), wite = w.end();
+      for (size_type nnu = 0; wit != wite; ++wit)  // copy to be optimized ...
+	if (wit->c > i) { if (nnu < K) { U(i, wit->c) = wit->e; ++nnu; } }
+    }
+  }
+
+  template<typename Matrix> 
+  void ildltt_precond<Matrix>::do_ildltt(const Matrix& A, col_major)
+  { do_ildltt(gmm::conjugated(A), row_major()); }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void mult(const ildltt_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    gmm::copy(v1, v2);
+    gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
+    for (size_type i = 0; i < P.indiag.size(); ++i) v2[i] *= P.indiag[i];
+    gmm::upper_tri_solve(P.U, v2, true);
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_mult(const ildltt_precond<Matrix>& P,const V1 &v1, V2 &v2)
+  { mult(P, v1, v2); }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void left_mult(const ildltt_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    copy(v1, v2);
+    gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
+    for (size_type i = 0; i < P.indiag.size(); ++i) v2[i] *= P.indiag[i];
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void right_mult(const ildltt_precond<Matrix>& P, const V1 &v1, V2 &v2)
+  { copy(v1, v2); gmm::upper_tri_solve(P.U, v2, true); }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_left_mult(const ildltt_precond<Matrix>& P, const V1 &v1,
+			    V2 &v2) {
+    copy(v1, v2);
+    gmm::upper_tri_solve(P.U, v2, true);
+    for (size_type i = 0; i < P.indiag.size(); ++i) v2[i] *= P.indiag[i];
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_right_mult(const ildltt_precond<Matrix>& P, const V1 &v1,
+			     V2 &v2)
+  { copy(v1, v2); gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true); }
+
+
+  // for compatibility with old versions
+
+  template <typename Matrix>
+  struct choleskyt_precond : public ildltt_precond<Matrix>{
+    choleskyt_precond(const Matrix& A, int k_, double eps_)
+      : ildltt_precond<Matrix>(A, k_, eps_) {}
+    choleskyt_precond(void) {}
+  } IS_DEPRECATED;
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void mult(const choleskyt_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    gmm::copy(v1, v2);
+    gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
+    for (size_type i = 0; i < P.indiag.size(); ++i) v2[i] *= P.indiag[i];
+    gmm::upper_tri_solve(P.U, v2, true);
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_mult(const choleskyt_precond<Matrix>& P,const V1 &v1, V2 &v2)
+  { mult(P, v1, v2); }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void left_mult(const choleskyt_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    copy(v1, v2);
+    gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
+    for (size_type i = 0; i < P.indiag.size(); ++i) v2[i] *= P.indiag[i];
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void right_mult(const choleskyt_precond<Matrix>& P, const V1 &v1, V2 &v2)
+  { copy(v1, v2); gmm::upper_tri_solve(P.U, v2, true); }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_left_mult(const choleskyt_precond<Matrix>& P, const V1 &v1,
+			    V2 &v2) {
+    copy(v1, v2);
+    gmm::upper_tri_solve(P.U, v2, true);
+    for (size_type i = 0; i < P.indiag.size(); ++i) v2[i] *= P.indiag[i];
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_right_mult(const choleskyt_precond<Matrix>& P, const V1 &v1,
+			     V2 &v2)
+  { copy(v1, v2); gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true); }
+
+}
+
+#endif 
+
diff --git a/Contrib/gmm/gmm_precond_ilu.h b/Contrib/gmm/gmm_precond_ilu.h
new file mode 100755
index 0000000..4d5f5fa
--- /dev/null
+++ b/Contrib/gmm/gmm_precond_ilu.h
@@ -0,0 +1,280 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 1997-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+// This file is a modified version of ilu.h from ITL.
+// See http://osl.iu.edu/research/itl/
+// Following the corresponding Copyright notice.
+//===========================================================================
+//
+// Copyright (c) 1997-2001, The Trustees of Indiana University.
+// All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//    * Redistributions of source code must retain the above copyright
+//      notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above copyright
+//      notice, this list of conditions and the following disclaimer in the
+//      documentation and/or other materials provided with the distribution.
+//    * Neither the name of the University of California, Berkeley nor the
+//      names of its contributors may be used to endorse or promote products
+//      derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE  IS  PROVIDED  BY  THE TRUSTEES  OF  INDIANA UNIVERSITY  AND
+// CONTRIBUTORS  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,  INCLUDING,
+// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS
+// FOR  A PARTICULAR PURPOSE ARE DISCLAIMED. IN  NO  EVENT SHALL THE TRUSTEES
+// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY,  OR CONSEQUENTIAL DAMAGES (INCLUDING,  BUT
+// NOT  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA,  OR PROFITS;  OR BUSINESS  INTERRUPTION)  HOWEVER  CAUSED AND ON ANY
+// THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT  LIABILITY, OR TORT
+// (INCLUDING  NEGLIGENCE  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+// THIS  SOFTWARE,  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//===========================================================================
+
+/**@file gmm_precond_ilu.h
+   @author Andrew Lumsdaine <lums at osl.iu.edu>
+   @author Lie-Quan Lee <llee at osl.iu.edu>
+   @author Yves Renard <yves.renard at insa-lyon.fr>
+   @date June 5, 2003.
+   @brief Incomplete LU without fill-in Preconditioner.
+*/
+
+#ifndef GMM_PRECOND_ILU_H
+#define GMM_PRECOND_ILU_H
+
+//
+// Notes: The idea under a concrete Preconditioner such 
+//        as Incomplete LU is to create a Preconditioner
+//        object to use in iterative methods. 
+//
+
+#include "gmm_precond.h"
+
+namespace gmm {
+  /** Incomplete LU without fill-in Preconditioner. */
+  template <typename Matrix>
+  class ilu_precond {
+
+  public :
+    typedef typename linalg_traits<Matrix>::value_type value_type;
+    typedef csr_matrix_ref<value_type *, size_type *, size_type *, 0> tm_type;
+
+    tm_type U, L;
+    bool invert;
+  protected :
+    std::vector<value_type> L_val, U_val;
+    std::vector<size_type> L_ind, U_ind, L_ptr, U_ptr;
+ 
+    template<typename M> void do_ilu(const M& A, row_major);
+    void do_ilu(const Matrix& A, col_major);
+
+  public:
+    
+    size_type nrows(void) const { return mat_nrows(L); }
+    size_type ncols(void) const { return mat_ncols(U); }
+    
+    void build_with(const Matrix& A) {
+      invert = false;
+       L_ptr.resize(mat_nrows(A)+1);
+       U_ptr.resize(mat_nrows(A)+1);
+       do_ilu(A, typename principal_orientation_type<typename
+	      linalg_traits<Matrix>::sub_orientation>::potype());
+    }
+    ilu_precond(const Matrix& A) { build_with(A); }
+    ilu_precond(void) {}
+    size_type memsize() const { 
+      return sizeof(*this) + 
+	(L_val.size()+U_val.size()) * sizeof(value_type) + 
+	(L_ind.size()+L_ptr.size()) * sizeof(size_type) +
+	(U_ind.size()+U_ptr.size()) * sizeof(size_type); 
+    }
+  };
+
+  template <typename Matrix> template <typename M>
+  void ilu_precond<Matrix>::do_ilu(const M& A, row_major) {
+    typedef typename linalg_traits<Matrix>::storage_type store_type;
+    typedef value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+
+    size_type L_loc = 0, U_loc = 0, n = mat_nrows(A), i, j, k;
+    if (n == 0) return;
+    L_ptr[0] = 0; U_ptr[0] = 0;
+    R prec = default_tol(R());
+    R max_pivot = gmm::abs(A(0,0)) * prec;
+
+
+    for (int count = 0; count < 2; ++count) {
+      if (count) { 
+	L_val.resize(L_loc); L_ind.resize(L_loc);
+	U_val.resize(U_loc); U_ind.resize(U_loc);
+      }
+      L_loc = U_loc = 0;
+      for (i = 0; i < n; ++i) {
+	typedef typename linalg_traits<M>::const_sub_row_type row_type;
+	row_type row = mat_const_row(A, i);
+	typename linalg_traits<row_type>::const_iterator
+	  it = vect_const_begin(row), ite = vect_const_end(row);
+	
+	if (count) { U_val[U_loc] = T(0); U_ind[U_loc] = i; }
+	++U_loc; // diagonal element
+	
+	for (k = 0; it != ite && k < 1000; ++it, ++k) {
+	  // if a plain row is present, retains only the 1000 firsts
+	  // nonzero elements. ---> a sort should be done.
+	  j = index_of_it(it, k, store_type());
+	  if (j < i) {
+	    if (count) { L_val[L_loc] = *it; L_ind[L_loc] = j; }
+	    L_loc++;
+	  }
+	  else if (i == j) {
+	    if (count) U_val[U_loc-1] = *it;
+	  }
+	  else {
+	    if (count) { U_val[U_loc] = *it; U_ind[U_loc] = j; }
+	    U_loc++;
+	  }
+	}
+        L_ptr[i+1] = L_loc; U_ptr[i+1] = U_loc;
+      }
+    }
+    
+    if (A(0,0) == T(0)) {
+      U_val[U_ptr[0]] = T(1);
+      GMM_WARNING2("pivot 0 is too small");
+    }
+
+    size_type qn, pn, rn;
+    for (i = 1; i < n; i++) {
+
+      pn = U_ptr[i];
+      if (gmm::abs(U_val[pn]) <= max_pivot) {
+	U_val[pn] = T(1);
+	GMM_WARNING2("pivot " << i << " is too small");
+      }
+      max_pivot = std::max(max_pivot,
+			   std::min(gmm::abs(U_val[pn]) * prec, R(1)));
+
+      for (j = L_ptr[i]; j < L_ptr[i+1]; j++) {
+	pn = U_ptr[L_ind[j]];
+	
+	T multiplier = (L_val[j] /= U_val[pn]);
+	
+	qn = j + 1;
+	rn = U_ptr[i];
+	
+	for (pn++; U_ind[pn] < i && pn < U_ptr[L_ind[j]+1]; pn++) {
+	  while (L_ind[qn] < U_ind[pn] && qn < L_ptr[i+1])
+	    qn++;
+	  if (U_ind[pn] == L_ind[qn] && qn < L_ptr[i+1])
+	    L_val[qn] -= multiplier * U_val[pn];
+	}
+	for (; pn < U_ptr[L_ind[j]+1]; pn++) {
+	  while (U_ind[rn] < U_ind[pn] && rn < U_ptr[i+1])
+	    rn++;
+	  if (U_ind[pn] == U_ind[rn] && rn < U_ptr[i+1])
+	    U_val[rn] -= multiplier * U_val[pn];
+	}
+      }
+    }
+
+    L = tm_type(&(L_val[0]), &(L_ind[0]), &(L_ptr[0]), n, mat_ncols(A));
+    U = tm_type(&(U_val[0]), &(U_ind[0]), &(U_ptr[0]), n, mat_ncols(A));
+  }
+  
+  template <typename Matrix>
+  void ilu_precond<Matrix>::do_ilu(const Matrix& A, col_major) {
+    do_ilu(gmm::transposed(A), row_major());
+    invert = true;
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void mult(const ilu_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    gmm::copy(v1, v2);
+    if (P.invert) {
+      gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+      gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+    }
+    else {
+      gmm::lower_tri_solve(P.L, v2, true);
+      gmm::upper_tri_solve(P.U, v2, false);
+    }
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_mult(const ilu_precond<Matrix>& P,const V1 &v1,V2 &v2) {
+    gmm::copy(v1, v2);
+    if (P.invert) {
+      gmm::lower_tri_solve(P.L, v2, true);
+      gmm::upper_tri_solve(P.U, v2, false);
+    }
+    else {
+      gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+      gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+    }
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void left_mult(const ilu_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    copy(v1, v2);
+    if (P.invert) gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+    else gmm::lower_tri_solve(P.L, v2, true);
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void right_mult(const ilu_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    copy(v1, v2);
+    if (P.invert) gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+    else gmm::upper_tri_solve(P.U, v2, false);
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_left_mult(const ilu_precond<Matrix>& P, const V1 &v1,
+			    V2 &v2) {
+    copy(v1, v2);
+    if (P.invert) gmm::upper_tri_solve(P.U, v2, false);
+    else gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_right_mult(const ilu_precond<Matrix>& P, const V1 &v1,
+			     V2 &v2) {
+    copy(v1, v2);
+    if (P.invert) gmm::lower_tri_solve(P.L, v2, true);
+    else gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+  }
+
+
+}
+
+#endif 
+
diff --git a/Contrib/gmm/gmm_precond_ilut.h b/Contrib/gmm/gmm_precond_ilut.h
new file mode 100755
index 0000000..b0c3045
--- /dev/null
+++ b/Contrib/gmm/gmm_precond_ilut.h
@@ -0,0 +1,227 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 1997-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+#ifndef GMM_PRECOND_ILUT_H
+#define GMM_PRECOND_ILUT_H
+
+/**@file gmm_precond_ilut.h
+   @author  Andrew Lumsdaine <lums at osl.iu.edu>, Lie-Quan Lee <llee at osl.iu.edu>
+   @date June 5, 2003.
+   @brief ILUT:  Incomplete LU with threshold and K fill-in Preconditioner.
+*/
+
+/*
+  Performane comparing for SSOR, ILU and ILUT based on sherman 5 matrix 
+  in Harwell-Boeing collection on Sun Ultra 30 UPA/PCI (UltraSPARC-II 296MHz)
+  Preconditioner & Factorization time  &  Number of Iteration \\ \hline
+  SSOR        &   0.010577  & 41 \\
+  ILU         &   0.019336  & 32 \\
+  ILUT with 0 fill-in and threshold of 1.0e-6 & 0.343612 &  23 \\
+  ILUT with 5 fill-in and threshold of 1.0e-6 & 0.343612 &  18 \\ \hline
+*/
+
+#include "gmm_precond.h"
+
+namespace gmm {
+
+  template<typename T> struct elt_rsvector_value_less_ {
+    inline bool operator()(const elt_rsvector_<T>& a, 
+			   const elt_rsvector_<T>& b) const
+    { return (gmm::abs(a.e) > gmm::abs(b.e)); }
+  };
+
+  /** Incomplete LU with threshold and K fill-in Preconditioner.
+
+  The algorithm of ILUT(A, 0, 1.0e-6) is slower than ILU(A). If No
+  fill-in is arrowed, you can use ILU instead of ILUT.
+
+  Notes: The idea under a concrete Preconditioner such as ilut is to
+  create a Preconditioner object to use in iterative methods.
+  */
+  template <typename Matrix>
+  class ilut_precond  {
+  public :
+    typedef typename linalg_traits<Matrix>::value_type value_type;
+    typedef wsvector<value_type> _wsvector;
+    typedef rsvector<value_type> _rsvector;
+    typedef row_matrix<_rsvector> LU_Matrix;
+
+    bool invert;
+    LU_Matrix L, U;
+
+  protected:
+    size_type K;
+    double eps;    
+
+    template<typename M> void do_ilut(const M&, row_major);
+    void do_ilut(const Matrix&, col_major);
+
+  public:
+    void build_with(const Matrix& A) {
+      invert = false;
+      gmm::resize(L, mat_nrows(A), mat_ncols(A));
+      gmm::resize(U, mat_nrows(A), mat_ncols(A));
+      do_ilut(A, typename principal_orientation_type<typename
+	      linalg_traits<Matrix>::sub_orientation>::potype());
+    }
+    ilut_precond(const Matrix& A, int k_, double eps_) 
+      : L(mat_nrows(A), mat_ncols(A)), U(mat_nrows(A), mat_ncols(A)),
+	K(k_), eps(eps_) { build_with(A); }
+    ilut_precond(size_type k_, double eps_) :  K(k_), eps(eps_) {}
+    ilut_precond(void) { K = 10; eps = 1E-7; }
+    size_type memsize() const { 
+      return sizeof(*this) + (nnz(U)+nnz(L))*sizeof(value_type);
+    }
+  };
+
+  template<typename Matrix> template<typename M> 
+  void ilut_precond<Matrix>::do_ilut(const M& A, row_major) {
+    typedef value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+    
+    size_type n = mat_nrows(A);
+    if (n == 0) return;
+    std::vector<T> indiag(n);
+    _wsvector w(mat_ncols(A));
+    _rsvector ww(mat_ncols(A)), wL(mat_ncols(A)), wU(mat_ncols(A));
+    T tmp;
+    gmm::clear(U); gmm::clear(L);
+    R prec = default_tol(R()); 
+    R max_pivot = gmm::abs(A(0,0)) * prec;
+
+    for (size_type i = 0; i < n; ++i) {
+      gmm::copy(mat_const_row(A, i), w);
+      double norm_row = gmm::vect_norm2(w);
+
+      typename _wsvector::iterator wkold = w.begin();
+      bool itfirst = true;
+      for (typename _wsvector::iterator wk = w.begin();
+	   wk != w.end() && wk->first < i; ) {
+	size_type k = wk->first;
+	tmp = (wk->second) * indiag[k];
+	if (gmm::abs(tmp) < eps * norm_row) w.erase(k); 
+	else { wk->second += tmp; gmm::add(scaled(mat_row(U, k), -tmp), w); }
+	if (itfirst) wk = w.begin(); else wk = ++wkold;
+	if (wk != w.end() && wk->first == k) { ++wk; itfirst = false; }
+      }
+      tmp = w[i];
+
+      if (gmm::abs(tmp) <= max_pivot) {
+	GMM_WARNING2("pivot " << i << " too small. try with ilutp ?");
+	w[i] = tmp = T(1);
+      }
+
+      max_pivot = std::max(max_pivot, std::min(gmm::abs(tmp) * prec, R(1)));
+      indiag[i] = T(1) / tmp;
+      gmm::clean(w, eps * norm_row);
+      gmm::copy(w, ww);
+      std::sort(ww.begin(), ww.end(), elt_rsvector_value_less_<T>());
+      typename _rsvector::const_iterator wit = ww.begin(), wite = ww.end();
+
+      size_type nnl = 0, nnu = 0;    
+      wL.base_resize(K); wU.base_resize(K+1);
+      typename _rsvector::iterator witL = wL.begin(), witU = wU.begin();
+      for (; wit != wite; ++wit) 
+	if (wit->c < i) { if (nnl < K) { *witL++ = *wit; ++nnl; } }
+	else { if (nnu < K  || wit->c == i) { *witU++ = *wit; ++nnu; } }
+      wL.base_resize(nnl); wU.base_resize(nnu);
+      std::sort(wL.begin(), wL.end());
+      std::sort(wU.begin(), wU.end());
+      gmm::copy(wL, L.row(i));
+      gmm::copy(wU, U.row(i));
+    }
+
+  }
+
+  template<typename Matrix> 
+  void ilut_precond<Matrix>::do_ilut(const Matrix& A, col_major) {
+    do_ilut(gmm::transposed(A), row_major());
+    invert = true;
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void mult(const ilut_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    gmm::copy(v1, v2);
+    if (P.invert) {
+      gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+      gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+    }
+    else {
+      gmm::lower_tri_solve(P.L, v2, true);
+      gmm::upper_tri_solve(P.U, v2, false);
+    }
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_mult(const ilut_precond<Matrix>& P,const V1 &v1,V2 &v2) {
+    gmm::copy(v1, v2);
+    if (P.invert) {
+      gmm::lower_tri_solve(P.L, v2, true);
+      gmm::upper_tri_solve(P.U, v2, false);
+    }
+    else {
+      gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+      gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+    }
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void left_mult(const ilut_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    copy(v1, v2);
+    if (P.invert) gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+    else gmm::lower_tri_solve(P.L, v2, true);
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void right_mult(const ilut_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    copy(v1, v2);
+    if (P.invert) gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+    else gmm::upper_tri_solve(P.U, v2, false);
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_left_mult(const ilut_precond<Matrix>& P, const V1 &v1,
+			    V2 &v2) {
+    copy(v1, v2);
+    if (P.invert) gmm::upper_tri_solve(P.U, v2, false);
+    else gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_right_mult(const ilut_precond<Matrix>& P, const V1 &v1,
+			     V2 &v2) {
+    copy(v1, v2);
+    if (P.invert) gmm::lower_tri_solve(P.L, v2, true);
+    else gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+  }
+
+}
+
+#endif 
+
diff --git a/Contrib/gmm/gmm_precond_ilutp.h b/Contrib/gmm/gmm_precond_ilutp.h
new file mode 100755
index 0000000..68bce2e
--- /dev/null
+++ b/Contrib/gmm/gmm_precond_ilutp.h
@@ -0,0 +1,281 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2004-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_precond_ilutp.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 14, 2004.
+   @brief ILUTP: Incomplete LU with threshold and K fill-in Preconditioner and
+   column pivoting.
+
+   
+*/
+#ifndef GMM_PRECOND_ILUTP_H
+#define GMM_PRECOND_ILUTP_H
+
+#include "gmm_precond_ilut.h"
+
+namespace gmm {
+
+  /**
+     ILUTP: Incomplete LU with threshold and K fill-in Preconditioner and
+     column pivoting.
+   
+     See Yousef Saad, Iterative Methods for
+     sparse linear systems, PWS Publishing Company, section 10.4.4
+
+      TODO : store the permutation by cycles to avoid the temporary vector
+  */
+  template <typename Matrix>
+  class ilutp_precond  {
+  public :
+    typedef typename linalg_traits<Matrix>::value_type value_type;
+    typedef wsvector<value_type> _wsvector;
+    typedef rsvector<value_type> _rsvector;
+    typedef row_matrix<_rsvector> LU_Matrix;
+    typedef col_matrix<_wsvector> CLU_Matrix;
+
+    bool invert;
+    LU_Matrix L, U;
+    gmm::unsorted_sub_index indperm;
+    gmm::unsorted_sub_index indperminv;
+    mutable std::vector<value_type> temporary;
+
+  protected:
+    size_type K;
+    double eps;
+
+    template<typename M> void do_ilutp(const M&, row_major);
+    void do_ilutp(const Matrix&, col_major);
+
+  public:
+    void build_with(const Matrix& A) {
+      invert = false;
+      gmm::resize(L, mat_nrows(A), mat_ncols(A));
+      gmm::resize(U, mat_nrows(A), mat_ncols(A));
+      do_ilutp(A, typename principal_orientation_type<typename
+	      linalg_traits<Matrix>::sub_orientation>::potype());
+    }
+    ilutp_precond(const Matrix& A, size_type k_, double eps_) 
+      : L(mat_nrows(A), mat_ncols(A)), U(mat_nrows(A), mat_ncols(A)),
+	K(k_), eps(eps_) { build_with(A); }
+    ilutp_precond(int k_, double eps_) :  K(k_), eps(eps_) {}
+    ilutp_precond(void) { K = 10; eps = 1E-7; }
+    size_type memsize() const { 
+      return sizeof(*this) + (nnz(U)+nnz(L))*sizeof(value_type);
+    }
+  };
+
+
+  template<typename Matrix> template<typename M> 
+  void ilutp_precond<Matrix>::do_ilutp(const M& A, row_major) {
+    typedef value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+
+    size_type n = mat_nrows(A);
+    CLU_Matrix CU(n,n);
+    if (n == 0) return;
+    std::vector<T> indiag(n);
+    temporary.resize(n);
+    std::vector<size_type> ipvt(n), ipvtinv(n);
+    for (size_type i = 0; i < n; ++i) ipvt[i] = ipvtinv[i] = i;
+    indperm = unsorted_sub_index(ipvt);
+    indperminv = unsorted_sub_index(ipvtinv);
+    _wsvector w(mat_ncols(A));
+    _rsvector ww(mat_ncols(A));
+    
+    T tmp = T(0);
+    gmm::clear(L); gmm::clear(U);
+    R prec = default_tol(R()); 
+    R max_pivot = gmm::abs(A(0,0)) * prec;
+
+    for (size_type i = 0; i < n; ++i) {
+
+      copy(sub_vector(mat_const_row(A, i), indperm), w);
+      double norm_row = gmm::vect_norm2(mat_const_row(A, i)); 
+
+      typename _wsvector::iterator wkold = w.begin();
+      bool itfirst = true;
+      for (typename _wsvector::iterator wk = w.begin();
+	   wk != w.end() && wk->first < i; )  {
+	size_type k = wk->first;
+	tmp = (wk->second) * indiag[k];
+	if (gmm::abs(tmp) < eps * norm_row) w.erase(k); 
+	else { wk->second += tmp; gmm::add(scaled(mat_row(U, k), -tmp), w); }
+	if (itfirst) wk = w.begin(); else wk = ++wkold;
+	if (wk != w.end() && wk->first == k) { ++wk; itfirst = false; }
+      }
+
+      gmm::clean(w, eps * norm_row);
+      gmm::copy(w, ww);
+
+      std::sort(ww.begin(), ww.end(), elt_rsvector_value_less_<T>());
+      typename _rsvector::const_iterator wit = ww.begin(), wite = ww.end();
+      size_type ip = size_type(-1);
+
+      for (; wit != wite; ++wit)
+	if (wit->c >= i) { ip = wit->c; tmp = wit->e; break; }
+      if (ip == size_type(-1) || gmm::abs(tmp) <= max_pivot)
+	{ GMM_WARNING2("pivot " << i << " too small"); ip=i; ww[i]=tmp=T(1); }
+      max_pivot = std::max(max_pivot, std::min(gmm::abs(tmp) * prec, R(1)));
+      indiag[i] = T(1) / tmp;
+      wit = ww.begin();
+
+      size_type nnl = 0, nnu = 0;
+      L[i].base_resize(K); U[i].base_resize(K+1);
+      typename _rsvector::iterator witL = L[i].begin(), witU = U[i].begin();
+      for (; wit != wite; ++wit) {
+	if (wit->c < i) { if (nnl < K) { *witL++ = *wit; ++nnl; } }
+	else if (nnu < K || wit->c == i)
+	  { CU(i, wit->c) = wit->e; *witU++ = *wit; ++nnu; }
+      }
+      L[i].base_resize(nnl); U[i].base_resize(nnu);
+      std::sort(L[i].begin(), L[i].end());
+      std::sort(U[i].begin(), U[i].end());
+
+      if (ip != i) {
+	typename _wsvector::const_iterator iti = CU.col(i).begin();
+	typename _wsvector::const_iterator itie = CU.col(i).end();
+	typename _wsvector::const_iterator itp = CU.col(ip).begin();
+	typename _wsvector::const_iterator itpe = CU.col(ip).end();
+	
+	while (iti != itie && itp != itpe) {
+	  if (iti->first < itp->first)
+	    { U.row(iti->first).swap_indices(i, ip); ++iti; }
+	  else if (iti->first > itp->first)
+	    { U.row(itp->first).swap_indices(i,ip);++itp; }
+	  else
+	    { U.row(iti->first).swap_indices(i, ip); ++iti; ++itp; }
+	}
+	
+	for( ; iti != itie; ++iti) U.row(iti->first).swap_indices(i, ip);
+	for( ; itp != itpe; ++itp) U.row(itp->first).swap_indices(i, ip);
+
+	CU.swap_col(i, ip);
+	
+	indperm.swap(i, ip);
+	indperminv.swap(ipvt[i], ipvt[ip]);
+	std::swap(ipvtinv[ipvt[i]], ipvtinv[ipvt[ip]]);
+	std::swap(ipvt[i], ipvt[ip]);
+      }
+    }
+  }
+
+  template<typename Matrix> 
+  void ilutp_precond<Matrix>::do_ilutp(const Matrix& A, col_major) {
+    do_ilutp(gmm::transposed(A), row_major());
+    invert = true;
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void mult(const ilutp_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    if (P.invert) {
+      gmm::copy(gmm::sub_vector(v1, P.indperm), v2);
+      gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+      gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+    }
+    else {
+      gmm::copy(v1, P.temporary);
+      gmm::lower_tri_solve(P.L, P.temporary, true);
+      gmm::upper_tri_solve(P.U, P.temporary, false);
+      gmm::copy(gmm::sub_vector(P.temporary, P.indperminv), v2);
+    }
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_mult(const ilutp_precond<Matrix>& P,const V1 &v1,V2 &v2) {
+    if (P.invert) {
+      gmm::copy(v1, P.temporary);
+      gmm::lower_tri_solve(P.L, P.temporary, true);
+      gmm::upper_tri_solve(P.U, P.temporary, false);
+      gmm::copy(gmm::sub_vector(P.temporary, P.indperminv), v2);
+    }
+    else {
+      gmm::copy(gmm::sub_vector(v1, P.indperm), v2);
+      gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+      gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+    }
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void left_mult(const ilutp_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    if (P.invert) {
+      gmm::copy(gmm::sub_vector(v1, P.indperm), v2);
+      gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+    }
+    else {
+      copy(v1, v2);
+      gmm::lower_tri_solve(P.L, v2, true);
+    }
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void right_mult(const ilutp_precond<Matrix>& P, const V1 &v1, V2 &v2) {
+    if (P.invert) {
+      copy(v1, v2);
+      gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+    }
+    else {
+      copy(v1, P.temporary);
+      gmm::upper_tri_solve(P.U, P.temporary, false);
+      gmm::copy(gmm::sub_vector(P.temporary, P.indperminv), v2);
+    }
+  }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_left_mult(const ilutp_precond<Matrix>& P, const V1 &v1,
+			    V2 &v2) {
+    if (P.invert) {
+      copy(v1, P.temporary);
+      gmm::upper_tri_solve(P.U, P.temporary, false);
+      gmm::copy(gmm::sub_vector(P.temporary, P.indperminv), v2);
+    }
+    else {
+      copy(v1, v2);
+      gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
+    }
+  }
+  
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_right_mult(const ilutp_precond<Matrix>& P, const V1 &v1,
+			     V2 &v2) {
+    if (P.invert) {
+      copy(v1, v2);
+      gmm::lower_tri_solve(P.L, v2, true);
+    }
+    else {
+      gmm::copy(gmm::sub_vector(v1, P.indperm), v2);
+      gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
+    }
+  }
+
+}
+
+#endif 
+
diff --git a/Contrib/gmm/gmm_precond_mr_approx_inverse.h b/Contrib/gmm/gmm_precond_mr_approx_inverse.h
new file mode 100755
index 0000000..cb54822
--- /dev/null
+++ b/Contrib/gmm/gmm_precond_mr_approx_inverse.h
@@ -0,0 +1,148 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 1997-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+// This file is a modified version of approximate_inverse.h from ITL.
+// See http://osl.iu.edu/research/itl/
+// Following the corresponding Copyright notice.
+//===========================================================================
+//
+// Copyright (c) 1997-2001, The Trustees of Indiana University.
+// All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//    * Redistributions of source code must retain the above copyright
+//      notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above copyright
+//      notice, this list of conditions and the following disclaimer in the
+//      documentation and/or other materials provided with the distribution.
+//    * Neither the name of the University of California, Berkeley nor the
+//      names of its contributors may be used to endorse or promote products
+//      derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE  IS  PROVIDED  BY  THE TRUSTEES  OF  INDIANA UNIVERSITY  AND
+// CONTRIBUTORS  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,  INCLUDING,
+// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS
+// FOR  A PARTICULAR PURPOSE ARE DISCLAIMED. IN  NO  EVENT SHALL THE TRUSTEES
+// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY,  OR CONSEQUENTIAL DAMAGES (INCLUDING,  BUT
+// NOT  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA,  OR PROFITS;  OR BUSINESS  INTERRUPTION)  HOWEVER  CAUSED AND ON ANY
+// THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT  LIABILITY, OR TORT
+// (INCLUDING  NEGLIGENCE  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+// THIS  SOFTWARE,  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//===========================================================================
+
+/**@file gmm_precond_mr_approx_inverse.h
+   @author Andrew Lumsdaine <lums at osl.iu.edu>
+   @author Lie-Quan Lee     <llee at osl.iu.edu>
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date June 5, 2003.
+   @brief Approximate inverse via MR iteration.
+*/
+
+#ifndef GMM_PRECOND_MR_APPROX_INVERSE_H
+#define GMM_PRECOND_MR_APPROX_INVERSE_H
+
+
+#include "gmm_precond.h"
+
+namespace gmm {
+
+  /** Approximate inverse via MR iteration (see P301 of Saad book).
+   */
+  template <typename Matrix>
+  struct mr_approx_inverse_precond {
+
+    typedef typename linalg_traits<Matrix>::value_type value_type;
+    typedef typename number_traits<value_type>::magnitude_type magnitude_type;
+    typedef typename principal_orientation_type<typename
+      linalg_traits<Matrix>::sub_orientation>::potype sub_orientation;
+    typedef wsvector<value_type> VVector;
+    typedef col_matrix<VVector> MMatrix;
+
+    MMatrix M;
+    size_type nb_it;
+    magnitude_type threshold;
+
+    void build_with(const Matrix& A);
+    mr_approx_inverse_precond(const Matrix& A, size_type nb_it_,
+			      magnitude_type threshold_)
+      : M(mat_nrows(A), mat_ncols(A))
+    { threshold = threshold_; nb_it = nb_it_; build_with(A); }
+    mr_approx_inverse_precond(void)
+    { threshold = magnitude_type(1E-7); nb_it = 5; }
+    mr_approx_inverse_precond(size_type nb_it_, magnitude_type threshold_)
+    { threshold = threshold_; nb_it = nb_it_; } 
+    const MMatrix &approx_inverse(void) const { return M; }
+  };
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void mult(const mr_approx_inverse_precond<Matrix>& P, const V1 &v1, V2 &v2)
+  { mult(P.M, v1, v2); }
+
+  template <typename Matrix, typename V1, typename V2> inline
+  void transposed_mult(const mr_approx_inverse_precond<Matrix>& P,
+		       const V1 &v1,V2 &v2)
+  { mult(gmm::conjugated(P.M), v1, v2); }
+
+  template <typename Matrix>
+  void mr_approx_inverse_precond<Matrix>::build_with(const Matrix& A) {
+    gmm::resize(M, mat_nrows(A), mat_ncols(A));
+    typedef value_type T;
+    typedef magnitude_type R;
+    VVector m(mat_ncols(A)),r(mat_ncols(A)),ei(mat_ncols(A)),Ar(mat_ncols(A)); 
+    T alpha = mat_trace(A)/ mat_euclidean_norm_sqr(A);
+    if (alpha == T(0)) alpha = T(1);
+    
+    for (size_type i = 0; i < mat_nrows(A); ++i) {
+      gmm::clear(m); gmm::clear(ei); 
+      m[i] = alpha;
+      ei[i] = T(1);
+      
+      for (size_type j = 0; j < nb_it; ++j) {
+	gmm::mult(A, gmm::scaled(m, T(-1)), r);
+	gmm::add(ei, r);
+	gmm::mult(A, r, Ar);
+	T nAr = vect_sp(Ar,Ar);
+	if (gmm::abs(nAr) > R(0)) {
+	  gmm::add(gmm::scaled(r, gmm::safe_divide(vect_sp(r, Ar), vect_sp(Ar, Ar))), m);
+	  gmm::clean(m, threshold * gmm::vect_norm2(m));
+	} else gmm::clear(m);
+      }
+      if (gmm::vect_norm2(m) == R(0)) m[i] = alpha;
+      gmm::copy(m, M.col(i));
+    }
+  }
+}
+
+#endif 
+
diff --git a/Contrib/gmm/gmm_real_part.h b/Contrib/gmm/gmm_real_part.h
new file mode 100755
index 0000000..b023986
--- /dev/null
+++ b/Contrib/gmm/gmm_real_part.h
@@ -0,0 +1,604 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_real_part.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date September 18, 2003.
+   @brief extract the real/imaginary part of vectors/matrices 
+*/
+#ifndef GMM_REAL_PART_H
+#define GMM_REAL_PART_H
+
+#include "gmm_def.h"
+#include "gmm_vector.h"
+
+namespace gmm {
+
+  struct linalg_real_part {};
+  struct linalg_imag_part {};
+  template <typename R, typename PART> struct which_part {};
+  
+  template <typename C> typename number_traits<C>::magnitude_type 
+  real_or_imag_part(C x, linalg_real_part) { return gmm::real(x); }
+  template <typename C> typename number_traits<C>::magnitude_type 
+  real_or_imag_part(C x, linalg_imag_part) { return gmm::imag(x); }
+  template <typename T, typename C, typename OP> C
+  complex_from(T x, C y, OP op, linalg_real_part) { return std::complex<T>(op(std::real(y), x), std::imag(y)); }
+  template <typename T, typename C, typename OP> C
+  complex_from(T x, C y, OP op,linalg_imag_part) { return std::complex<T>(std::real(y), op(std::imag(y), x)); }
+  
+  template<typename T> struct project2nd {
+    T operator()(T , T b) const { return b; }
+  };
+  
+  template<typename T, typename R, typename PART> class ref_elt_vector<T, which_part<R, PART> > {
+
+    R r;
+    
+    public :
+
+    operator T() const { return real_or_imag_part(std::complex<T>(r), PART()); }
+    ref_elt_vector(R r_) : r(r_) {}
+    inline ref_elt_vector &operator =(T v)
+    { r = complex_from(v, std::complex<T>(r), gmm::project2nd<T>(), PART()); return *this; }
+    inline bool operator ==(T v) const { return (r == v); }
+    inline bool operator !=(T v) const { return (r != v); }
+    inline ref_elt_vector &operator +=(T v)
+    { r = complex_from(v, std::complex<T>(r), std::plus<T>(), PART()); return *this; }
+    inline ref_elt_vector &operator -=(T v)
+      { r = complex_from(v, std::complex<T>(r), std::minus<T>(), PART()); return *this; }
+    inline ref_elt_vector &operator /=(T v)
+      { r = complex_from(v, std::complex<T>(r), std::divides<T>(), PART()); return *this; }
+    inline ref_elt_vector &operator *=(T v)
+      { r = complex_from(v, std::complex<T>(r), std::multiplies<T>(), PART()); return *this; }
+    inline ref_elt_vector &operator =(const ref_elt_vector &re)
+      { *this = T(re); return *this; }
+    T operator +()    { return  T(*this);   } // necessary for unknow reason
+    T operator -()    { return -T(*this);   } // necessary for unknow reason
+    T operator +(T v) { return T(*this)+ v; } // necessary for unknow reason
+    T operator -(T v) { return T(*this)- v; } // necessary for unknow reason
+    T operator *(T v) { return T(*this)* v; } // necessary for unknow reason
+    T operator /(T v) { return T(*this)/ v; } // necessary for unknow reason
+  };
+
+  template<typename reference> struct ref_or_value_type {
+    template <typename T, typename W>
+    static W r(const T &x, linalg_real_part, W) {
+      return gmm::real(x);
+    }
+    template <typename T, typename W>
+    static W r(const T &x, linalg_imag_part, W) {
+      return gmm::imag(x);
+    }
+  };
+  
+  template<typename U, typename R, typename PART> 
+  struct ref_or_value_type<ref_elt_vector<U, which_part<R, PART> > > {
+    template<typename T , typename W> 
+    static const T &r(const T &x, linalg_real_part, W)
+    { return x; }
+    template<typename T, typename W> 
+    static const T &r(const T &x, linalg_imag_part, W) {
+      return x; 
+    }
+    template<typename T , typename W> 
+    static T &r(T &x, linalg_real_part, W)
+    { return x; }
+    template<typename T, typename W> 
+    static T &r(T &x, linalg_imag_part, W) {
+      return x; 
+    }
+  };
+
+  
+  /* ********************************************************************* */
+  /*	Reference to the real part of (complex) vectors            	   */
+  /* ********************************************************************* */
+
+  template <typename IT, typename MIT, typename PART>
+  struct part_vector_iterator {
+    typedef typename std::iterator_traits<IT>::value_type      vtype;
+    typedef typename gmm::number_traits<vtype>::magnitude_type value_type;
+    typedef value_type                                        *pointer;
+    typedef ref_elt_vector<value_type, which_part<typename std::iterator_traits<IT>::reference, PART> > reference;
+    typedef typename std::iterator_traits<IT>::difference_type difference_type;
+    typedef typename std::iterator_traits<IT>::iterator_category
+    iterator_category;
+
+    IT it;
+    
+    part_vector_iterator(void) {}
+    explicit part_vector_iterator(const IT &i) : it(i) {}
+    part_vector_iterator(const part_vector_iterator<MIT, MIT, PART> &i) : it(i.it) {}
+    
+
+    size_type index(void) const { return it.index(); }
+    part_vector_iterator operator ++(int)
+    { part_vector_iterator tmp = *this; ++it; return tmp; }
+    part_vector_iterator operator --(int) 
+    { part_vector_iterator tmp = *this; --it; return tmp; }
+    part_vector_iterator &operator ++() { ++it; return *this; }
+    part_vector_iterator &operator --() { --it; return *this; }
+    part_vector_iterator &operator +=(difference_type i)
+      { it += i; return *this; }
+    part_vector_iterator &operator -=(difference_type i)
+      { it -= i; return *this; }
+    part_vector_iterator operator +(difference_type i) const
+      { part_vector_iterator itb = *this; return (itb += i); }
+    part_vector_iterator operator -(difference_type i) const
+      { part_vector_iterator itb = *this; return (itb -= i); }
+    difference_type operator -(const part_vector_iterator &i) const
+      { return difference_type(it - i.it); }
+    
+    reference operator  *() const { return reference(*it); }
+    reference operator [](size_type ii) const { return reference(it[ii]); }
+    
+    bool operator ==(const part_vector_iterator &i) const
+      { return (i.it == it); }
+    bool operator !=(const part_vector_iterator &i) const
+      { return (i.it != it); }
+    bool operator < (const part_vector_iterator &i) const
+      { return (it < i.it); }
+  };
+
+
+  template <typename PT, typename PART> struct part_vector {
+    typedef part_vector<PT, PART> this_type;
+    typedef typename std::iterator_traits<PT>::value_type V;
+    typedef V * CPT;
+    typedef typename select_ref<typename linalg_traits<V>::const_iterator,
+            typename linalg_traits<V>::iterator, PT>::ref_type iterator;
+    typedef typename linalg_traits<this_type>::reference reference;
+    typedef typename linalg_traits<this_type>::value_type value_type;
+    typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+    iterator begin_, end_;
+    porigin_type origin;
+    size_type size_;
+
+    size_type size(void) const { return size_; }
+   
+    reference operator[](size_type i) const { 
+      return reference(ref_or_value_type<reference>::r(
+	     linalg_traits<V>::access(origin, begin_, end_, i),
+	     PART(), value_type()));
+    }
+
+    part_vector(V &v)
+      : begin_(vect_begin(v)),  end_(vect_end(v)),
+	origin(linalg_origin(v)), size_(gmm::vect_size(v)) {}
+    part_vector(const V &v) 
+      : begin_(vect_begin(const_cast<V &>(v))),
+       end_(vect_end(const_cast<V &>(v))),
+	origin(linalg_origin(const_cast<V &>(v))), size_(gmm::vect_size(v)) {}
+    part_vector() {}
+    part_vector(const part_vector<CPT, PART> &cr)
+      : begin_(cr.begin_),end_(cr.end_),origin(cr.origin), size_(cr.size_) {} 
+  };
+
+  template <typename IT, typename MIT, typename ORG, typename PT,
+	    typename PART> inline
+  void set_to_begin(part_vector_iterator<IT, MIT, PART> &it,
+		    ORG o, part_vector<PT, PART> *, linalg_modifiable) {
+    typedef part_vector<PT, PART> VECT;
+    typedef typename linalg_traits<VECT>::V_reference ref_t;
+    set_to_begin(it.it, o, typename linalg_traits<VECT>::pV(), ref_t());
+  }
+  template <typename IT, typename MIT, typename ORG, typename PT,
+	    typename PART> inline
+  void set_to_begin(part_vector_iterator<IT, MIT, PART> &it,
+		    ORG o, const part_vector<PT, PART> *, linalg_modifiable) {
+    typedef part_vector<PT, PART> VECT;
+    typedef typename linalg_traits<VECT>::V_reference ref_t;
+    set_to_begin(it.it, o, typename linalg_traits<VECT>::pV(), ref_t());
+  }
+  template <typename IT, typename MIT, typename ORG, typename PT,
+	    typename PART> inline
+  void set_to_end(part_vector_iterator<IT, MIT, PART> &it,
+		    ORG o, part_vector<PT, PART> *, linalg_modifiable) {
+    typedef part_vector<PT, PART> VECT;
+    typedef typename linalg_traits<VECT>::V_reference ref_t;
+    set_to_end(it.it, o, typename linalg_traits<VECT>::pV(), ref_t());
+  }
+  template <typename IT, typename MIT, typename ORG,
+	    typename PT, typename PART> inline
+  void set_to_end(part_vector_iterator<IT, MIT, PART> &it,
+		  ORG o, const part_vector<PT, PART> *,
+		  linalg_modifiable) {
+    typedef part_vector<PT, PART> VECT;
+    typedef typename linalg_traits<VECT>::V_reference ref_t;
+    set_to_end(it.it, o, typename linalg_traits<VECT>::pV(), ref_t());
+  }
+  
+  template <typename PT, typename PART>
+  struct linalg_traits<part_vector<PT, PART> > {
+    typedef part_vector<PT, PART> this_type;
+    typedef this_type * pthis_type;
+    typedef PT pV;
+    typedef typename std::iterator_traits<PT>::value_type V;
+    typedef typename linalg_traits<V>::index_sorted index_sorted;
+    typedef typename linalg_traits<V>::is_reference V_reference;
+    typedef typename linalg_traits<V>::origin_type origin_type;
+    typedef typename select_ref<const origin_type *, origin_type *,
+			        PT>::ref_type porigin_type;
+    typedef typename which_reference<PT>::is_reference is_reference;
+    typedef abstract_vector linalg_type;
+    typedef typename linalg_traits<V>::value_type vtype;
+    typedef typename number_traits<vtype>::magnitude_type value_type;
+    typedef typename select_ref<value_type, ref_elt_vector<value_type,
+		     which_part<typename linalg_traits<V>::reference,
+				PART> >, PT>::ref_type reference;
+    typedef typename select_ref<typename linalg_traits<V>::const_iterator,
+	    typename linalg_traits<V>::iterator, PT>::ref_type pre_iterator;
+    typedef typename select_ref<abstract_null_type, 
+	    part_vector_iterator<pre_iterator, pre_iterator, PART>,
+	    PT>::ref_type iterator;
+    typedef part_vector_iterator<typename linalg_traits<V>::const_iterator,
+				 pre_iterator, PART> const_iterator;
+    typedef typename linalg_traits<V>::storage_type storage_type;
+    static size_type size(const this_type &v) { return v.size(); }
+    static iterator begin(this_type &v) {
+      iterator it; it.it = v.begin_;
+      if (!is_const_reference(is_reference()) && is_sparse(storage_type()))
+	set_to_begin(it, v.origin, pthis_type(), is_reference());
+      return it;
+    }
+    static const_iterator begin(const this_type &v) {
+      const_iterator it(v.begin_);
+      if (!is_const_reference(is_reference()) && is_sparse(storage_type()))
+	{ set_to_begin(it, v.origin, pthis_type(), is_reference()); }
+      return it;
+    }
+    static iterator end(this_type &v) {
+      iterator it(v.end_);
+      if (!is_const_reference(is_reference()) && is_sparse(storage_type()))
+	set_to_end(it, v.origin, pthis_type(), is_reference());
+      return it;
+    }
+    static const_iterator end(const this_type &v) {
+      const_iterator it(v.end_);
+      if (!is_const_reference(is_reference()) && is_sparse(storage_type()))
+	set_to_end(it, v.origin, pthis_type(), is_reference());
+      return it;
+    }
+    static origin_type* origin(this_type &v) { return v.origin; }
+    static const origin_type* origin(const this_type &v) { return v.origin; }
+
+    static void clear(origin_type* o, const iterator &begin_,
+		      const iterator &end_, abstract_sparse) {
+      std::deque<size_type> ind;
+      iterator it = begin_;
+      for (; it != end_; ++it) ind.push_front(it.index());
+      for (; !(ind.empty()); ind.pop_back())
+	access(o, begin_, end_, ind.back()) = value_type(0);
+    }
+    static void clear(origin_type* o, const iterator &begin_,
+		      const iterator &end_, abstract_skyline) {
+      clear(o, begin_, end_, abstract_sparse());
+    }
+    static void clear(origin_type* o, const iterator &begin_,
+		      const iterator &end_, abstract_dense) {
+      for (iterator it = begin_; it != end_; ++it) *it = value_type(0);
+    }
+
+   static void clear(origin_type* o, const iterator &begin_,
+		      const iterator &end_) 
+    { clear(o, begin_, end_, storage_type()); }
+    static void do_clear(this_type &v) { clear(v.origin, begin(v), end(v)); }
+    static value_type access(const origin_type *o, const const_iterator &it,
+			     const const_iterator &ite, size_type i) { 
+      return  real_or_imag_part(linalg_traits<V>::access(o, it.it, ite.it,i),
+				PART());
+    }
+    static reference access(origin_type *o, const iterator &it,
+			    const iterator &ite, size_type i)
+    { return reference(linalg_traits<V>::access(o, it.it, ite.it,i)); }
+  };
+
+  template <typename PT, typename PART> std::ostream &operator <<
+    (std::ostream &o, const part_vector<PT, PART>& m)
+  { gmm::write(o,m); return o; }
+
+
+  /* ********************************************************************* */
+  /*	Reference to the real or imaginary part of (complex) matrices      */
+  /* ********************************************************************* */
+
+
+  template <typename PT, typename PART> struct  part_row_ref {
+    
+    typedef part_row_ref<PT, PART> this_type;
+    typedef typename std::iterator_traits<PT>::value_type M;
+    typedef M * CPT;
+    typedef typename std::iterator_traits<PT>::reference ref_M;
+    typedef typename select_ref<typename linalg_traits<this_type>
+            ::const_row_iterator, typename linalg_traits<this_type>
+            ::row_iterator, PT>::ref_type iterator;
+    typedef typename linalg_traits<this_type>::value_type value_type;
+    typedef typename linalg_traits<this_type>::reference reference;
+    typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+    iterator begin_, end_;
+    porigin_type origin;
+    size_type nr, nc;
+
+    part_row_ref(ref_M m)
+      : begin_(mat_row_begin(m)), end_(mat_row_end(m)),
+	origin(linalg_origin(m)), nr(mat_nrows(m)), nc(mat_ncols(m)) {}
+
+    part_row_ref(const part_row_ref<CPT, PART> &cr) :
+      begin_(cr.begin_),end_(cr.end_), origin(cr.origin),nr(cr.nr),nc(cr.nc) {}
+
+    reference operator()(size_type i, size_type j) const {
+      return reference(ref_or_value_type<reference>::r(
+					 linalg_traits<M>::access(begin_+j, i),
+					 PART(), value_type()));
+    }
+  };
+
+  template <typename PT, typename PART>
+  struct linalg_traits<part_row_ref<PT, PART> > {
+    typedef part_row_ref<PT, PART> this_type;
+    typedef typename std::iterator_traits<PT>::value_type M;
+    typedef typename linalg_traits<M>::origin_type origin_type;
+    typedef typename select_ref<const origin_type *, origin_type *,
+			        PT>::ref_type porigin_type;
+    typedef typename which_reference<PT>::is_reference is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef typename linalg_traits<M>::value_type vtype;
+    typedef typename number_traits<vtype>::magnitude_type value_type;
+    typedef typename linalg_traits<M>::storage_type storage_type;
+    typedef abstract_null_type sub_col_type;
+    typedef abstract_null_type const_sub_col_type;
+    typedef abstract_null_type col_iterator;
+    typedef abstract_null_type const_col_iterator;
+    typedef typename linalg_traits<M>::const_sub_row_type
+            pre_const_sub_row_type;
+    typedef typename linalg_traits<M>::sub_row_type pre_sub_row_type;
+    typedef part_vector<const pre_const_sub_row_type *, PART>
+            const_sub_row_type;
+    typedef typename select_ref<abstract_null_type,
+	    part_vector<pre_sub_row_type *, PART>, PT>::ref_type sub_row_type;
+    typedef typename linalg_traits<M>::const_row_iterator const_row_iterator;
+    typedef typename select_ref<abstract_null_type, typename
+            linalg_traits<M>::row_iterator, PT>::ref_type row_iterator;
+    typedef typename select_ref<
+            typename linalg_traits<const_sub_row_type>::reference,
+	    typename linalg_traits<sub_row_type>::reference,
+				PT>::ref_type reference;
+    typedef row_major sub_orientation;
+    typedef typename linalg_traits<M>::index_sorted index_sorted;
+    static size_type ncols(const this_type &v) { return v.nc; }
+    static size_type nrows(const this_type &v) { return v.nr; }
+    static const_sub_row_type row(const const_row_iterator &it)
+    { return const_sub_row_type(linalg_traits<M>::row(it)); }
+    static sub_row_type row(const row_iterator &it)
+    { return sub_row_type(linalg_traits<M>::row(it)); }
+    static row_iterator row_begin(this_type &m) { return m.begin_; }
+    static row_iterator row_end(this_type &m) { return m.end_; }
+    static const_row_iterator row_begin(const this_type &m)
+    { return m.begin_; }
+    static const_row_iterator row_end(const this_type &m) { return m.end_; }
+    static origin_type* origin(this_type &v) { return v.origin; }
+    static const origin_type* origin(const this_type &v) { return v.origin; }
+    static void do_clear(this_type &v);
+    static value_type access(const const_row_iterator &itrow, size_type i)
+    { return real_or_imag_part(linalg_traits<M>::access(itrow, i), PART()); }
+    static reference access(const row_iterator &itrow, size_type i) {
+      return reference(ref_or_value_type<reference>::r(
+					 linalg_traits<M>::access(itrow, i),
+					 PART(), value_type()));
+    }
+  };
+   
+  template <typename PT, typename PART> 
+  void linalg_traits<part_row_ref<PT, PART> >::do_clear(this_type &v) { 
+    row_iterator it = mat_row_begin(v), ite = mat_row_end(v);
+    for (; it != ite; ++it) clear(row(it));
+  }
+  
+  template<typename PT, typename PART> std::ostream &operator <<
+    (std::ostream &o, const part_row_ref<PT, PART>& m)
+  { gmm::write(o,m); return o; }
+
+  template <typename PT, typename PART> struct  part_col_ref {
+    
+    typedef part_col_ref<PT, PART> this_type;
+    typedef typename std::iterator_traits<PT>::value_type M;
+    typedef M * CPT;
+    typedef typename std::iterator_traits<PT>::reference ref_M;
+    typedef typename select_ref<typename linalg_traits<this_type>
+            ::const_col_iterator, typename linalg_traits<this_type>
+            ::col_iterator, PT>::ref_type iterator;
+    typedef typename linalg_traits<this_type>::value_type value_type;
+    typedef typename linalg_traits<this_type>::reference reference;
+    typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+    iterator begin_, end_;
+    porigin_type origin;
+    size_type nr, nc;
+
+    part_col_ref(ref_M m)
+      : begin_(mat_col_begin(m)), end_(mat_col_end(m)),
+	origin(linalg_origin(m)), nr(mat_nrows(m)), nc(mat_ncols(m)) {}
+
+    part_col_ref(const part_col_ref<CPT, PART> &cr) :
+      begin_(cr.begin_),end_(cr.end_), origin(cr.origin),nr(cr.nr),nc(cr.nc) {}
+
+    reference operator()(size_type i, size_type j) const {
+      return reference(ref_or_value_type<reference>::r(
+					 linalg_traits<M>::access(begin_+j, i),
+					 PART(), value_type()));
+    }
+  };
+
+  template <typename PT, typename PART>
+  struct linalg_traits<part_col_ref<PT, PART> > {
+    typedef part_col_ref<PT, PART> this_type;
+    typedef typename std::iterator_traits<PT>::value_type M;
+    typedef typename linalg_traits<M>::origin_type origin_type;
+    typedef typename select_ref<const origin_type *, origin_type *,
+			        PT>::ref_type porigin_type;
+    typedef typename which_reference<PT>::is_reference is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef typename linalg_traits<M>::value_type vtype;
+    typedef typename number_traits<vtype>::magnitude_type value_type;
+    typedef typename linalg_traits<M>::storage_type storage_type;
+    typedef abstract_null_type sub_row_type;
+    typedef abstract_null_type const_sub_row_type;
+    typedef abstract_null_type row_iterator;
+    typedef abstract_null_type const_row_iterator;
+    typedef typename linalg_traits<M>::const_sub_col_type
+            pre_const_sub_col_type;
+    typedef typename linalg_traits<M>::sub_col_type pre_sub_col_type;
+    typedef part_vector<const pre_const_sub_col_type *, PART>
+            const_sub_col_type;
+    typedef typename select_ref<abstract_null_type,
+	    part_vector<pre_sub_col_type *, PART>, PT>::ref_type sub_col_type;
+    typedef typename linalg_traits<M>::const_col_iterator const_col_iterator;
+    typedef typename select_ref<abstract_null_type, typename
+            linalg_traits<M>::col_iterator, PT>::ref_type col_iterator;
+    typedef typename select_ref<
+            typename linalg_traits<const_sub_col_type>::reference,
+	    typename linalg_traits<sub_col_type>::reference,
+				PT>::ref_type reference;
+    typedef col_major sub_orientation;
+    typedef typename linalg_traits<M>::index_sorted index_sorted;
+    static size_type nrows(const this_type &v) { return v.nr; }
+    static size_type ncols(const this_type &v) { return v.nc; }
+    static const_sub_col_type col(const const_col_iterator &it)
+    { return const_sub_col_type(linalg_traits<M>::col(it)); }
+    static sub_col_type col(const col_iterator &it)
+    { return sub_col_type(linalg_traits<M>::col(it)); }
+    static col_iterator col_begin(this_type &m) { return m.begin_; }
+    static col_iterator col_end(this_type &m) { return m.end_; }
+    static const_col_iterator col_begin(const this_type &m)
+    { return m.begin_; }
+    static const_col_iterator col_end(const this_type &m) { return m.end_; }
+    static origin_type* origin(this_type &v) { return v.origin; }
+    static const origin_type* origin(const this_type &v) { return v.origin; }
+    static void do_clear(this_type &v);
+    static value_type access(const const_col_iterator &itcol, size_type i)
+    { return real_or_imag_part(linalg_traits<M>::access(itcol, i), PART()); }
+    static reference access(const col_iterator &itcol, size_type i) {
+      return reference(ref_or_value_type<reference>::r(
+					 linalg_traits<M>::access(itcol, i),
+					 PART(), value_type()));
+    }
+  };
+   
+  template <typename PT, typename PART> 
+  void linalg_traits<part_col_ref<PT, PART> >::do_clear(this_type &v) { 
+    col_iterator it = mat_col_begin(v), ite = mat_col_end(v);
+    for (; it != ite; ++it) clear(col(it));
+  }
+  
+  template<typename PT, typename PART> std::ostream &operator <<
+    (std::ostream &o, const part_col_ref<PT, PART>& m)
+  { gmm::write(o,m); return o; }
+
+  
+
+
+
+
+template <typename TYPE, typename PART, typename PT>
+  struct part_return_ {
+    typedef abstract_null_type return_type;
+  };
+  template <typename PT, typename PART>
+  struct part_return_<row_major, PART, PT> {
+    typedef typename std::iterator_traits<PT>::value_type L;
+    typedef typename select_return<part_row_ref<const L *, PART>,
+		     part_row_ref< L *, PART>, PT>::return_type return_type;
+  };
+  template <typename PT, typename PART>
+  struct part_return_<col_major, PART, PT> {
+    typedef typename std::iterator_traits<PT>::value_type L;
+    typedef typename select_return<part_col_ref<const L *, PART>,
+		     part_col_ref<L *, PART>, PT>::return_type return_type;
+  };
+
+  template <typename PT, typename PART, typename LT> struct part_return__{
+    typedef abstract_null_type return_type;
+  };
+
+  template <typename PT, typename PART>
+  struct part_return__<PT, PART, abstract_matrix> {
+    typedef typename std::iterator_traits<PT>::value_type L;
+    typedef typename part_return_<typename principal_orientation_type<
+      typename linalg_traits<L>::sub_orientation>::potype, PART,
+      PT>::return_type return_type;
+  };
+
+  template <typename PT, typename PART>
+  struct part_return__<PT, PART, abstract_vector> {
+    typedef typename std::iterator_traits<PT>::value_type L;
+    typedef typename select_return<part_vector<const L *, PART>,
+      part_vector<L *, PART>, PT>::return_type return_type;
+  };
+
+  template <typename PT, typename PART> struct part_return {
+    typedef typename std::iterator_traits<PT>::value_type L;
+    typedef typename part_return__<PT, PART,
+      typename linalg_traits<L>::linalg_type>::return_type return_type;
+  };
+
+  template <typename L> inline 
+  typename part_return<const L *, linalg_real_part>::return_type
+  real_part(const L &l) {
+    return typename part_return<const L *, linalg_real_part>::return_type
+      (linalg_cast(const_cast<L &>(l)));
+  }
+
+  template <typename L> inline 
+  typename part_return<L *, linalg_real_part>::return_type
+  real_part(L &l) {
+    return typename part_return<L *, linalg_real_part>::return_type(linalg_cast(l));
+  }
+
+  template <typename L> inline 
+  typename part_return<const L *, linalg_imag_part>::return_type
+  imag_part(const L &l) {
+    return typename part_return<const L *, linalg_imag_part>::return_type
+      (linalg_cast(const_cast<L &>(l)));
+  }
+
+  template <typename L> inline 
+  typename part_return<L *, linalg_imag_part>::return_type
+  imag_part(L &l) {
+    return typename part_return<L *, linalg_imag_part>::return_type(linalg_cast(l));
+  }
+
+
+
+}
+
+#endif //  GMM_REAL_PART_H
diff --git a/Contrib/gmm/gmm_ref.h b/Contrib/gmm/gmm_ref.h
new file mode 100755
index 0000000..0f6c745
--- /dev/null
+++ b/Contrib/gmm/gmm_ref.h
@@ -0,0 +1,525 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2000-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+
+#ifndef GMM_REF_H__
+#define GMM_REF_H__
+
+/** @file gmm_ref.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date August 26, 2000.
+ *  @brief Provide some simple pseudo-containers.
+ *  
+ *  WARNING : modifiying the container infirm the validity of references.
+ */
+
+
+#include <iterator>
+#include "gmm_except.h"
+
+namespace gmm {
+
+  /* ********************************************************************* */
+  /* Simple reference.                                                     */
+  /* ********************************************************************* */
+
+  template<typename ITER> class tab_ref {
+
+    protected :
+
+      ITER begin_, end_;
+
+    public :
+
+      typedef typename std::iterator_traits<ITER>::value_type  value_type;
+      typedef typename std::iterator_traits<ITER>::pointer     pointer;
+      typedef typename std::iterator_traits<ITER>::pointer     const_pointer;
+      typedef typename std::iterator_traits<ITER>::reference   reference;
+      typedef typename std::iterator_traits<ITER>::reference   const_reference;
+      typedef typename std::iterator_traits<ITER>::difference_type
+	                                                       difference_type;
+      typedef ITER                            iterator;
+      typedef ITER                            const_iterator;
+      typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+      typedef std::reverse_iterator<iterator> reverse_iterator;
+      typedef size_t size_type;
+    
+      bool empty(void) const { return begin_ == end_; }
+      size_type size(void) const { return end_ - begin_; }
+
+      const iterator &begin(void) { return begin_; }
+      const const_iterator &begin(void) const { return begin_; }
+      const iterator &end(void) { return end_; }
+      const const_iterator &end(void) const { return end_; }
+      reverse_iterator rbegin(void) { return reverse_iterator(end()); }
+      const_reverse_iterator rbegin(void) const
+      { return const_reverse_iterator(end()); }
+      reverse_iterator rend(void) { return reverse_iterator(begin()); }
+      const_reverse_iterator rend(void) const
+      { return const_reverse_iterator(begin()); }
+
+      reference front(void) { return *begin(); }
+      const_reference front(void) const { return *begin(); }
+      reference back(void) { return *(--(end())); }
+      const_reference back(void) const { return *(--(end())); }
+      void pop_front(void) { ++begin_; }
+
+      const_reference operator [](size_type ii) const { return *(begin_ + ii);}
+      reference operator [](size_type ii) { return *(begin_ + ii); }
+
+      tab_ref(void) {}
+      tab_ref(const ITER &b, const ITER &e) : begin_(b), end_(e) {}
+  };
+
+
+  /* ********************************************************************* */
+  /* Reference with index.                                                 */
+  /* ********************************************************************* */
+
+//   template<typename ITER> struct tab_ref_index_iterator_
+//     : public dynamic_array<size_t>::const_iterator
+//   {
+//     typedef typename std::iterator_traits<ITER>::value_type  value_type;
+//     typedef typename std::iterator_traits<ITER>::pointer     pointer;
+//     typedef typename std::iterator_traits<ITER>::reference   reference;
+//     typedef typename std::iterator_traits<ITER>::difference_type  
+//     difference_type;
+//     typedef std::random_access_iterator_tag iterator_category;
+//     typedef size_t size_type;
+//     typedef dynamic_array<size_type>::const_iterator dnas_iterator_;
+//     typedef tab_ref_index_iterator_<ITER> iterator;
+    
+
+//     ITER piter;
+    
+//     iterator operator ++(int)
+//     { iterator tmp = *this; ++(*((dnas_iterator_ *)(this))); return tmp; }
+//     iterator operator --(int)
+//     { iterator tmp = *this; --(*((dnas_iterator_ *)(this))); return tmp; }
+//     iterator &operator ++()
+//     { ++(*((dnas_iterator_ *)(this))); return *this; }
+//     iterator &operator --()
+//     { --(*((dnas_iterator_ *)(this))); return *this; }
+//     iterator &operator +=(difference_type i)
+//     { (*((dnas_iterator_ *)(this))) += i; return *this; }
+//     iterator &operator -=(difference_type i)
+//     { (*((dnas_iterator_ *)(this))) -= i; return *this; }
+//     iterator operator +(difference_type i) const
+//     { iterator it = *this; return (it += i); }
+//     iterator operator -(difference_type i) const
+//     { iterator it = *this; return (it -= i); }
+//     difference_type operator -(const iterator &i) const
+//     { return *((dnas_iterator_ *)(this)) - *((dnas_iterator_ *)(&i)); }
+	
+//     reference operator *() const
+//     { return *(piter + *((*((dnas_iterator_ *)(this))))); }
+//     reference operator [](int ii)
+//     { return *(piter + *((*((dnas_iterator_ *)(this+ii))))); }
+    
+//     bool operator ==(const iterator &i) const
+//     { 
+//       return ((piter) == ((i.piter))
+//        && *((dnas_iterator_ *)(this)) == *((*((dnas_iterator_ *)(this)))));
+//     }
+//     bool operator !=(const iterator &i) const
+//     { return !(i == *this); }
+//     bool operator < (const iterator &i) const
+//     { 
+//       return ((piter) == ((i.piter))
+// 	 && *((dnas_iterator_ *)(this)) < *((*((dnas_iterator_ *)(this)))));
+//     }
+
+//     tab_ref_index_iterator_(void) {}
+//     tab_ref_index_iterator_(const ITER &iter, const dnas_iterator_ &dnas_iter)
+//       : dnas_iterator_(dnas_iter), piter(iter) {}
+//   };
+
+
+//   template<typename ITER> class tab_ref_index
+//   {
+//     public :
+
+//       typedef typename std::iterator_traits<ITER>::value_type value_type;
+//       typedef typename std::iterator_traits<ITER>::pointer    pointer;
+//       typedef typename std::iterator_traits<ITER>::pointer    const_pointer;
+//       typedef typename std::iterator_traits<ITER>::reference  reference;
+//       typedef typename std::iterator_traits<ITER>::reference  const_reference;
+//       typedef typename std::iterator_traits<ITER>::difference_type
+// 	                                                       difference_type;
+//       typedef size_t size_type; 
+//       typedef tab_ref_index_iterator_<ITER> iterator;
+//       typedef iterator                          const_iterator;
+//       typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+//       typedef std::reverse_iterator<iterator> reverse_iterator;
+    
+//     protected :
+
+//       ITER begin_;
+//       dynamic_array<size_type> index_;
+
+//     public :
+
+//       bool empty(void) const { return index_.empty(); }
+//       size_type size(void) const { return index_.size(); }
+
+
+//       iterator begin(void) { return iterator(begin_, index_.begin()); }
+//       const_iterator begin(void) const
+//       { return iterator(begin_, index_.begin()); }
+//       iterator end(void) { return iterator(begin_, index_.end()); }
+//       const_iterator end(void) const { return iterator(begin_, index_.end()); }
+//       reverse_iterator rbegin(void) { return reverse_iterator(end()); }
+//       const_reverse_iterator rbegin(void) const
+//       { return const_reverse_iterator(end()); }
+//       reverse_iterator rend(void) { return reverse_iterator(begin()); }
+//       const_reverse_iterator rend(void) const
+//       { return const_reverse_iterator(begin()); }
+
+
+//       reference front(void) { return *(begin_ +index_[0]); }
+//       const_reference front(void) const { return *(begin_ +index_[0]); }
+//       reference back(void) { return *(--(end())); }
+//       const_reference back(void) const { return *(--(end())); }
+   
+//       tab_ref_index(void) {}
+//       tab_ref_index(const ITER &b, const dynamic_array<size_type> &ind)
+//       { begin_ = b; index_ = ind; }
+
+//     // to be changed in a const_reference ?
+//       value_type operator [](size_type ii) const
+//       { return *(begin_ + index_[ii]);}
+//       reference operator [](size_type ii) { return *(begin_ + index_[ii]); }
+
+//   };
+
+
+  /// iterator over a gmm::tab_ref_index_ref<ITER,ITER_INDEX>
+  template<typename ITER, typename ITER_INDEX>
+    struct tab_ref_index_ref_iterator_
+    {
+      typedef typename std::iterator_traits<ITER>::value_type value_type;
+      typedef typename std::iterator_traits<ITER>::pointer    pointer;
+      typedef typename std::iterator_traits<ITER>::reference  reference;
+      typedef typename std::iterator_traits<ITER>::difference_type
+                                                              difference_type;
+      typedef std::random_access_iterator_tag iterator_category;
+      typedef tab_ref_index_ref_iterator_<ITER, ITER_INDEX> iterator;
+      typedef size_t size_type;
+
+      ITER piter;
+      ITER_INDEX iter_index;
+      
+      iterator operator ++(int)
+      { iterator tmp = *this; ++iter_index; return tmp; }
+      iterator operator --(int)
+      { iterator tmp = *this; --iter_index; return tmp; }
+      iterator &operator ++() { ++iter_index; return *this; }
+      iterator &operator --() { --iter_index; return *this; }
+      iterator &operator +=(difference_type i)
+      { iter_index += i; return *this; }
+      iterator &operator -=(difference_type i)
+      { iter_index -= i; return *this; }
+      iterator operator +(difference_type i) const
+      { iterator it = *this; return (it += i); }
+      iterator operator -(difference_type i) const
+      { iterator it = *this; return (it -= i); }
+      difference_type operator -(const iterator &i) const
+      { return iter_index - i.iter_index; }
+	
+      reference operator *() const
+      { return *(piter + *iter_index); }
+      reference operator [](int ii) const
+      { return *(piter + *(iter_index+ii)); }
+      
+      bool operator ==(const iterator &i) const
+      { return ((piter) == ((i.piter)) && iter_index == i.iter_index); }
+      bool operator !=(const iterator &i) const { return !(i == *this); }
+      bool operator < (const iterator &i) const
+      { return ((piter) == ((i.piter)) && iter_index < i.iter_index); }
+
+      tab_ref_index_ref_iterator_(void) {}
+      tab_ref_index_ref_iterator_(const ITER &iter, 
+				  const ITER_INDEX &dnas_iter)
+	: piter(iter), iter_index(dnas_iter) {}
+      
+    };
+
+  /** 
+      convenience template function for quick obtention of a indexed iterator
+      without having to specify its (long) typename
+  */
+  template<typename ITER, typename ITER_INDEX>
+  tab_ref_index_ref_iterator_<ITER,ITER_INDEX>
+  index_ref_iterator(ITER it, ITER_INDEX it_i) {
+    return tab_ref_index_ref_iterator_<ITER,ITER_INDEX>(it, it_i);
+  }
+
+  /** indexed array reference (given a container X, and a set of indexes I, 
+      this class provides a pseudo-container Y such that
+      @code Y[i] = X[I[i]] @endcode
+  */
+  template<typename ITER, typename ITER_INDEX> class tab_ref_index_ref {
+  public :
+    
+    typedef std::iterator_traits<ITER>            traits_type;
+    typedef typename traits_type::value_type      value_type;
+    typedef typename traits_type::pointer         pointer;
+    typedef typename traits_type::pointer         const_pointer;
+    typedef typename traits_type::reference       reference;
+    typedef typename traits_type::reference       const_reference;
+    typedef typename traits_type::difference_type difference_type;
+    typedef size_t                                size_type;
+    typedef tab_ref_index_ref_iterator_<ITER, ITER_INDEX>   iterator;
+    typedef iterator                              const_iterator;
+    typedef std::reverse_iterator<const_iterator>     const_reverse_iterator;
+    typedef std::reverse_iterator<iterator>           reverse_iterator;
+    
+  protected :
+
+    ITER begin_;
+    ITER_INDEX index_begin_, index_end_;
+
+  public :
+    
+    bool empty(void) const { return index_begin_ == index_end_; }
+    size_type size(void) const { return index_end_ - index_begin_; }
+    
+    iterator begin(void) { return iterator(begin_, index_begin_); }
+    const_iterator begin(void) const
+    { return iterator(begin_, index_begin_); }
+    iterator end(void) { return iterator(begin_, index_end_); }
+    const_iterator end(void) const { return iterator(begin_, index_end_); }
+    reverse_iterator rbegin(void) { return reverse_iterator(end()); }
+    const_reverse_iterator rbegin(void) const
+    { return const_reverse_iterator(end()); }
+    reverse_iterator rend(void) { return reverse_iterator(begin()); }
+    const_reverse_iterator rend(void) const
+    { return const_reverse_iterator(begin()); }
+    
+    reference front(void) { return *(begin_ + *index_begin_); }
+    const_reference front(void) const { return *(begin_ + *index_begin_); }
+    reference back(void) { return *(--(end())); }
+    const_reference back(void) const { return *(--(end())); }
+    void pop_front(void) { ++index_begin_; }
+    
+    tab_ref_index_ref(void) {}
+    tab_ref_index_ref(const ITER &b, const ITER_INDEX &bi,
+		      const ITER_INDEX &ei)
+      : begin_(b), index_begin_(bi), index_end_(ei) {}
+    
+    // to be changed in a const_reference ?
+    const_reference operator [](size_type ii) const
+    { return *(begin_ + index_begin_[ii]);}
+    reference operator [](size_type ii)
+    { return *(begin_ + index_begin_[ii]); }
+
+  };
+
+
+  /* ********************************************************************* */
+  /* Reference on regularly spaced elements.                               */
+  /* ********************************************************************* */
+
+  template<typename ITER> struct tab_ref_reg_spaced_iterator_ {
+    
+    typedef typename std::iterator_traits<ITER>::value_type value_type;
+    typedef typename std::iterator_traits<ITER>::pointer    pointer;
+    typedef typename std::iterator_traits<ITER>::reference  reference;
+    typedef typename std::iterator_traits<ITER>::difference_type
+                                                            difference_type;
+    typedef typename std::iterator_traits<ITER>::iterator_category
+                                                            iterator_category;
+    typedef size_t size_type;
+    typedef tab_ref_reg_spaced_iterator_<ITER> iterator;
+    
+    ITER it;
+    size_type N, i;
+    
+    iterator operator ++(int) { iterator tmp = *this; i++; return tmp; }
+    iterator operator --(int) { iterator tmp = *this; i--; return tmp; }
+    iterator &operator ++()   { i++; return *this; }
+    iterator &operator --()   { i--; return *this; }
+    iterator &operator +=(difference_type ii) { i+=ii; return *this; }
+    iterator &operator -=(difference_type ii) { i-=ii; return *this; }
+    iterator operator +(difference_type ii) const 
+    { iterator itt = *this; return (itt += ii); }
+    iterator operator -(difference_type ii) const
+    { iterator itt = *this; return (itt -= ii); }
+    difference_type operator -(const iterator &ii) const
+    { return (N ? (it - ii.it) / N : 0) + i - ii.i; }
+
+    reference operator *() const { return *(it + i*N); }
+    reference operator [](int ii) const { return *(it + (i+ii)*N); }
+
+    bool operator ==(const iterator &ii) const
+    { return (*this - ii) == difference_type(0); }
+    bool operator !=(const iterator &ii) const
+    { return  (*this - ii) != difference_type(0); }
+    bool operator < (const iterator &ii) const
+    { return (*this - ii) < difference_type(0); }
+
+    tab_ref_reg_spaced_iterator_(void) {}
+    tab_ref_reg_spaced_iterator_(const ITER &iter, size_type n, size_type ii)
+      : it(iter), N(n), i(ii) { }
+    
+  };
+
+  /** 
+      convenience template function for quick obtention of a strided iterator
+      without having to specify its (long) typename
+  */
+  template<typename ITER> tab_ref_reg_spaced_iterator_<ITER> 
+  reg_spaced_iterator(ITER it, size_t stride) {
+    return tab_ref_reg_spaced_iterator_<ITER>(it, stride);
+  }
+
+  /**
+     provide a "strided" view a of container
+  */
+  template<typename ITER> class tab_ref_reg_spaced {
+  public :
+
+    typedef typename std::iterator_traits<ITER>::value_type value_type;
+    typedef typename std::iterator_traits<ITER>::pointer    pointer;
+    typedef typename std::iterator_traits<ITER>::pointer    const_pointer;
+    typedef typename std::iterator_traits<ITER>::reference  reference;
+    typedef typename std::iterator_traits<ITER>::reference  const_reference;
+    typedef typename std::iterator_traits<ITER>::difference_type
+            difference_type;
+    typedef size_t size_type;
+    typedef tab_ref_reg_spaced_iterator_<ITER> iterator;
+    typedef iterator                          const_iterator;
+    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+    typedef std::reverse_iterator<iterator> reverse_iterator;
+    
+  protected :
+
+    ITER begin_;
+    size_type N, size_;
+    
+  public :
+    
+    bool empty(void) const { return size_ == 0; }
+    size_type size(void) const { return size_; }
+    
+    iterator begin(void) { return iterator(begin_, N, 0); }
+    const_iterator begin(void) const { return iterator(begin_, N, 0); }
+    iterator end(void) { return iterator(begin_, N, size_); }
+    const_iterator end(void) const { return iterator(begin_, N, size_); }
+    reverse_iterator rbegin(void) { return reverse_iterator(end()); }
+    const_reverse_iterator rbegin(void) const
+    { return const_reverse_iterator(end()); }
+    reverse_iterator rend(void) { return reverse_iterator(begin()); }
+    const_reverse_iterator rend(void) const
+    { return const_reverse_iterator(begin()); }
+    
+    reference front(void) { return *begin_; }
+    const_reference front(void) const { return *begin_; }
+    reference back(void) { return *(begin_ + N * (size_-1)); }
+    const_reference back(void) const { return *(begin_ + N * (size_-1)); }
+    void pop_front(void) { begin_ += N; }
+    
+    tab_ref_reg_spaced(void) {}
+    tab_ref_reg_spaced(const ITER &b, size_type n, size_type s)
+      : begin_(b), N(n), size_(s) {}
+    
+    
+    const_reference operator [](size_type ii) const
+    { return *(begin_ + ii * N);}
+    reference operator [](size_type ii) { return *(begin_ + ii * N); }
+    
+  };
+
+  /// iterator over a tab_ref_with_selection
+  template<typename ITER, typename COND> 
+  struct tab_ref_with_selection_iterator_ : public ITER {
+    typedef typename std::iterator_traits<ITER>::value_type value_type;
+    typedef typename std::iterator_traits<ITER>::pointer    pointer;
+    typedef typename std::iterator_traits<ITER>::reference  reference;
+    typedef typename std::iterator_traits<ITER>::difference_type
+                                                              difference_type;
+    typedef std::forward_iterator_tag iterator_category;
+    typedef tab_ref_with_selection_iterator_<ITER, COND> iterator;
+    const COND cond;
+    
+    void forward(void) { while (!(cond)(*this)) ITER::operator ++(); }
+    iterator &operator ++()
+    { ITER::operator ++(); forward(); return *this; }
+    iterator operator ++(int)
+    { iterator tmp = *this; ++(*this); return tmp; }
+    
+    tab_ref_with_selection_iterator_(void) {}
+    tab_ref_with_selection_iterator_(const ITER &iter, const COND c)
+      : ITER(iter), cond(c) {}
+    
+  };
+
+  /**
+     given a container X and a predicate P, provide pseudo-container Y
+     of all elements of X such that P(X[i]).
+  */
+  template<typename ITER, typename COND> class tab_ref_with_selection {
+    
+  protected :
+    
+    ITER begin_, end_;
+    COND cond;
+    
+  public :
+    
+    typedef typename std::iterator_traits<ITER>::value_type value_type;
+    typedef typename std::iterator_traits<ITER>::pointer    pointer;
+    typedef typename std::iterator_traits<ITER>::pointer    const_pointer;
+    typedef typename std::iterator_traits<ITER>::reference  reference;
+    typedef typename std::iterator_traits<ITER>::reference  const_reference;
+    typedef size_t  size_type;
+    typedef tab_ref_with_selection_iterator_<ITER, COND> iterator;
+    typedef iterator   const_iterator;
+    
+    iterator begin(void) const
+    { iterator it(begin_, cond); it.forward(); return it; }
+    iterator end(void) const { return iterator(end_, cond); }
+    bool empty(void) const { return begin_ == end_; }
+    
+    value_type front(void) const { return *begin(); }
+    void pop_front(void) { ++begin_; begin_ = begin(); }
+    
+    COND &condition(void) { return cond; }
+    const COND &condition(void) const { return cond; }
+    
+    tab_ref_with_selection(void) {}
+    tab_ref_with_selection(const ITER &b, const ITER &e, const COND &c)
+      : begin_(b), end_(e), cond(c) { begin_ = begin(); }
+    
+  };
+
+}
+
+#endif /* GMM_REF_H__  */
diff --git a/Contrib/gmm/gmm_scaled.h b/Contrib/gmm/gmm_scaled.h
new file mode 100755
index 0000000..281ef59
--- /dev/null
+++ b/Contrib/gmm/gmm_scaled.h
@@ -0,0 +1,427 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_scaled.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date November 10, 2002.
+   @brief get a scaled view of a vector/matrix.
+*/
+#ifndef GMM_SCALED_H__
+#define GMM_SCALED_H__
+
+#include "gmm_def.h"
+
+namespace gmm {
+
+  /* ********************************************************************* */
+  /*		Scaled references on vectors            		   */
+  /* ********************************************************************* */
+
+  template <typename IT, typename S> struct scaled_const_iterator {
+    typedef typename strongest_numeric_type<typename std::iterator_traits<IT>::value_type,
+					    S>::T value_type;
+
+    typedef typename std::iterator_traits<IT>::pointer         pointer;
+    typedef typename std::iterator_traits<IT>::reference       reference;
+    typedef typename std::iterator_traits<IT>::difference_type difference_type;
+    typedef typename std::iterator_traits<IT>::iterator_category
+    iterator_category;
+
+    IT it;
+    S r;
+    
+    scaled_const_iterator(void) {}
+    scaled_const_iterator(const IT &i, S x) : it(i), r(x) {}
+    
+    inline size_type index(void) const { return it.index(); }
+    inline scaled_const_iterator operator ++(int)
+    { scaled_const_iterator tmp = *this; ++it; return tmp; }
+    inline scaled_const_iterator operator --(int) 
+    { scaled_const_iterator tmp = *this; --it; return tmp; }
+    inline scaled_const_iterator &operator ++() { ++it; return *this; }
+    inline scaled_const_iterator &operator --() { --it; return *this; }
+    inline scaled_const_iterator &operator +=(difference_type i)
+      { it += i; return *this; }
+    inline scaled_const_iterator &operator -=(difference_type i)
+      { it -= i; return *this; }
+    inline scaled_const_iterator operator +(difference_type i) const
+      { scaled_const_iterator itb = *this; return (itb += i); }
+    inline scaled_const_iterator operator -(difference_type i) const
+      { scaled_const_iterator itb = *this; return (itb -= i); }
+    inline difference_type operator -(const scaled_const_iterator &i) const
+      { return difference_type(it - i.it); }
+    
+    inline value_type operator  *() const { return (*it) * r; }
+    inline value_type operator [](size_type ii) const { return it[ii] * r; }
+    
+    inline bool operator ==(const scaled_const_iterator &i) const
+      { return (i.it == it); }
+    inline bool operator !=(const scaled_const_iterator &i) const
+      { return (i.it != it); }
+    inline bool operator < (const scaled_const_iterator &i) const
+      { return (it < i.it); }
+  };
+
+  template <typename V, typename S> struct scaled_vector_const_ref {
+    typedef scaled_vector_const_ref<V,S> this_type;
+    typedef typename linalg_traits<this_type>::value_type value_type;
+    typedef typename linalg_traits<V>::const_iterator iterator;
+    typedef typename linalg_traits<this_type>::reference reference;
+    typedef typename linalg_traits<this_type>::origin_type origin_type;
+
+    iterator begin_, end_;
+    const origin_type *origin;
+    size_type size_;
+    S r;
+
+    scaled_vector_const_ref(const V &v, S rr)
+      : begin_(vect_const_begin(v)), end_(vect_const_end(v)),
+	origin(linalg_origin(v)), size_(vect_size(v)), r(rr) {}
+
+    reference operator[](size_type i) const
+    { return r * linalg_traits<V>::access(origin, begin_, end_, i); }
+  };
+
+  template <typename V, typename S> struct linalg_traits<scaled_vector_const_ref<V,S> > {
+    typedef scaled_vector_const_ref<V,S> this_type;
+    typedef linalg_const is_reference;
+    typedef abstract_vector linalg_type;
+    typedef typename strongest_numeric_type<S, typename linalg_traits<V>::value_type>::T value_type;
+    typedef typename linalg_traits<V>::origin_type origin_type;
+    typedef value_type reference;
+    typedef abstract_null_type iterator;
+    typedef scaled_const_iterator<typename linalg_traits<V>::const_iterator, S>
+      const_iterator;
+    typedef typename linalg_traits<V>::storage_type storage_type;
+    typedef typename linalg_traits<V>::index_sorted index_sorted;
+    static size_type size(const this_type &v) { return v.size_; }
+    static const_iterator begin(const this_type &v)
+    { return const_iterator(v.begin_, v.r); }
+    static const_iterator end(const this_type &v)
+    { return const_iterator(v.end_, v.r); }
+    static const origin_type* origin(const this_type &v) { return v.origin; }
+    static value_type access(const origin_type *o, const const_iterator &it,
+			     const const_iterator &ite, size_type i)
+    { return it.r * (linalg_traits<V>::access(o, it.it, ite.it, i)); }
+
+  };
+
+   template<typename V, typename S> std::ostream &operator <<
+     (std::ostream &o, const scaled_vector_const_ref<V,S>& m)
+  { gmm::write(o,m); return o; }
+
+  /* ********************************************************************* */
+  /*		Scaled references on matrices            		   */
+  /* ********************************************************************* */
+
+  template <typename M, typename S> struct scaled_row_const_iterator {
+    typedef scaled_row_const_iterator<M,S> iterator;
+    typedef typename linalg_traits<M>::const_row_iterator ITER;
+    typedef ptrdiff_t difference_type;
+    typedef size_t size_type;
+
+    ITER it;
+    S r;
+
+    inline iterator operator ++(int) { iterator tmp=*this; it++; return tmp; }
+    inline iterator operator --(int) { iterator tmp=*this; it--; return tmp; }
+    inline iterator &operator ++()   { it++; return *this; }
+    inline iterator &operator --()   { it--; return *this; }
+    iterator &operator +=(difference_type i) { it += i; return *this; }
+    iterator &operator -=(difference_type i) { it -= i; return *this; }
+    iterator operator +(difference_type i) const 
+    { iterator itt = *this; return (itt += i); }
+    iterator operator -(difference_type i) const
+    { iterator itt = *this; return (itt -= i); }
+    difference_type operator -(const iterator &i) const
+    { return it - i.it; }
+
+    inline ITER operator *() const { return it; }
+    inline ITER operator [](int i) { return it + i; }
+
+    inline bool operator ==(const iterator &i) const { return (it == i.it); }
+    inline bool operator !=(const iterator &i) const { return !(i == *this); }
+    inline bool operator < (const iterator &i) const { return (it < i.it); }
+
+    scaled_row_const_iterator(void) {}
+    scaled_row_const_iterator(const ITER &i, S rr)
+      : it(i), r(rr) { }
+
+  };
+
+  template <typename M, typename S> struct  scaled_row_matrix_const_ref {
+    
+    typedef scaled_row_matrix_const_ref<M,S> this_type;
+    typedef typename linalg_traits<M>::const_row_iterator iterator;
+    typedef typename linalg_traits<this_type>::value_type value_type;
+    typedef typename linalg_traits<this_type>::origin_type origin_type;
+
+    iterator begin_, end_;
+    const origin_type *origin;
+    S r;
+    size_type nr, nc;
+
+    scaled_row_matrix_const_ref(const M &m, S rr)
+      : begin_(mat_row_begin(m)), end_(mat_row_end(m)),
+	origin(linalg_origin(m)), r(rr), nr(mat_nrows(m)), nc(mat_ncols(m)) {}
+
+    value_type operator()(size_type i, size_type j) const
+    { return r * linalg_traits<M>::access(begin_+i, j); }
+  };
+
+  template <typename M, typename S> struct linalg_traits<scaled_row_matrix_const_ref<M,S> > {
+    typedef scaled_row_matrix_const_ref<M,S> this_type;
+    typedef linalg_const is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef typename linalg_traits<M>::origin_type origin_type;
+    typedef typename strongest_numeric_type<S, typename linalg_traits<M>::value_type>::T value_type;
+    typedef value_type reference;
+    typedef typename linalg_traits<M>::storage_type storage_type;
+    typedef typename linalg_traits<M>::const_sub_row_type vector_type;
+    typedef scaled_vector_const_ref<vector_type,S> sub_row_type;
+    typedef scaled_vector_const_ref<vector_type,S> const_sub_row_type;
+    typedef scaled_row_const_iterator<M,S> row_iterator;
+    typedef scaled_row_const_iterator<M,S> const_row_iterator;
+    typedef abstract_null_type const_sub_col_type;
+    typedef abstract_null_type sub_col_type;
+    typedef abstract_null_type const_col_iterator;
+    typedef abstract_null_type col_iterator;
+    typedef row_major sub_orientation;
+    typedef typename linalg_traits<M>::index_sorted index_sorted;
+    static size_type nrows(const this_type &m)
+    { return m.nr; }
+    static size_type ncols(const this_type &m)
+    { return m.nc; }
+    static const_sub_row_type row(const const_row_iterator &it)
+    { return scaled(linalg_traits<M>::row(it.it), it.r); }
+    static const_row_iterator row_begin(const this_type &m)
+    { return const_row_iterator(m.begin_, m.r); }
+    static const_row_iterator row_end(const this_type &m)
+    { return const_row_iterator(m.end_, m.r); }
+    static const origin_type* origin(const this_type &m) { return m.origin; }
+    static value_type access(const const_row_iterator &it, size_type i)
+    { return it.r * (linalg_traits<M>::access(it.it, i)); }
+  };
+
+  template<typename M, typename S> std::ostream &operator <<
+    (std::ostream &o, const scaled_row_matrix_const_ref<M,S>& m)
+  { gmm::write(o,m); return o; }
+
+
+  template <typename M, typename S> struct scaled_col_const_iterator {
+    typedef scaled_col_const_iterator<M,S> iterator;
+    typedef typename linalg_traits<M>::const_col_iterator ITER;
+    typedef ptrdiff_t difference_type;
+    typedef size_t size_type;
+
+    ITER it;
+    S r;
+
+    iterator operator ++(int) { iterator tmp = *this; it++; return tmp; }
+    iterator operator --(int) { iterator tmp = *this; it--; return tmp; }
+    iterator &operator ++()   { it++; return *this; }
+    iterator &operator --()   { it--; return *this; }
+    iterator &operator +=(difference_type i) { it += i; return *this; }
+    iterator &operator -=(difference_type i) { it -= i; return *this; }
+    iterator operator +(difference_type i) const 
+    { iterator itt = *this; return (itt += i); }
+    iterator operator -(difference_type i) const
+    { iterator itt = *this; return (itt -= i); }
+    difference_type operator -(const iterator &i) const
+    { return it - i.it; }
+
+    ITER operator *() const { return it; }
+    ITER operator [](int i) { return it + i; }
+
+    bool operator ==(const iterator &i) const { return (it == i.it); }
+    bool operator !=(const iterator &i) const { return !(i == *this); }
+    bool operator < (const iterator &i) const { return (it < i.it); }
+
+    scaled_col_const_iterator(void) {}
+    scaled_col_const_iterator(const ITER &i, S rr)
+      : it(i), r(rr) { }
+
+  };
+
+  template <typename M, typename S> struct  scaled_col_matrix_const_ref {
+    
+    typedef scaled_col_matrix_const_ref<M,S> this_type;
+    typedef typename linalg_traits<M>::const_col_iterator iterator;
+    typedef typename linalg_traits<this_type>::value_type value_type;
+    typedef typename linalg_traits<this_type>::origin_type origin_type;
+
+    iterator begin_, end_;
+    const origin_type *origin;
+    S r;
+    size_type nr, nc;
+
+    scaled_col_matrix_const_ref(const M &m, S rr)
+      : begin_(mat_col_begin(m)), end_(mat_col_end(m)),
+	origin(linalg_origin(m)), r(rr), nr(mat_nrows(m)), nc(mat_ncols(m)) {}
+
+    value_type operator()(size_type i, size_type j) const
+    { return r * linalg_traits<M>::access(begin_+j, i); }
+  };
+
+  template <typename M, typename S> struct linalg_traits<scaled_col_matrix_const_ref<M,S> > {
+    typedef scaled_col_matrix_const_ref<M,S> this_type;
+    typedef linalg_const is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef typename strongest_numeric_type<S, typename linalg_traits<M>::value_type>::T value_type;
+    typedef typename linalg_traits<M>::origin_type origin_type;
+    typedef value_type reference;
+    typedef typename linalg_traits<M>::storage_type storage_type;
+    typedef typename linalg_traits<M>::const_sub_col_type vector_type;
+    typedef abstract_null_type sub_col_type;
+    typedef scaled_vector_const_ref<vector_type,S> const_sub_col_type;
+    typedef abstract_null_type  col_iterator;
+    typedef scaled_col_const_iterator<M,S> const_col_iterator;
+    typedef abstract_null_type const_sub_row_type;
+    typedef abstract_null_type sub_row_type;
+    typedef abstract_null_type const_row_iterator;
+    typedef abstract_null_type row_iterator;
+    typedef col_major sub_orientation;
+    typedef typename linalg_traits<M>::index_sorted index_sorted;
+    static size_type ncols(const this_type &m)
+    { return m.nc; }
+    static size_type nrows(const this_type &m)
+    { return m.nr; }
+    static const_sub_col_type col(const const_col_iterator &it)
+    { return scaled(linalg_traits<M>::col(it.it), it.r); }
+    static const_col_iterator col_begin(const this_type &m)
+    { return const_col_iterator(m.begin_, m.r); }
+    static const_col_iterator col_end(const this_type &m)
+    { return const_col_iterator(m.end_, m.r); }
+    static const origin_type* origin(const this_type &m) { return m.origin; }
+    static value_type access(const const_col_iterator &it, size_type i)
+    { return it.r * (linalg_traits<M>::access(it.it, i)); }
+  };
+
+  template<typename M, typename S> std::ostream &operator <<
+    (std::ostream &o, const scaled_col_matrix_const_ref<M,S>& m)
+  { gmm::write(o,m); return o; }
+
+
+  template <typename L, typename S, typename R> struct scaled_return__ {
+    typedef abstract_null_type return_type;
+  };
+  template <typename L, typename S> struct scaled_return__<L, S, row_major> 
+  { typedef scaled_row_matrix_const_ref<L,S> return_type; };
+  template <typename L, typename S> struct scaled_return__<L, S, col_major> 
+  { typedef scaled_col_matrix_const_ref<L,S> return_type; };
+  
+
+  template <typename L, typename S, typename LT> struct scaled_return_ {
+    typedef abstract_null_type return_type;
+  };
+  template <typename L, typename S> struct scaled_return_<L, S, abstract_vector> 
+  { typedef scaled_vector_const_ref<L,S> return_type; };
+  template <typename L, typename S> struct scaled_return_<L, S, abstract_matrix> {
+    typedef typename scaled_return__<L, S, 
+      typename principal_orientation_type<typename
+      linalg_traits<L>::sub_orientation>::potype>::return_type return_type;
+  };
+
+  template <typename L, typename S> struct scaled_return {
+    typedef typename scaled_return_<L, S, typename
+      linalg_traits<L>::linalg_type>::return_type return_type;
+  };
+
+  template <typename L, typename S> inline
+  typename scaled_return<L,S>::return_type
+  scaled(const L &v, S x)
+  { return scaled(v, x, typename linalg_traits<L>::linalg_type()); }
+
+  template <typename V, typename S> inline
+  typename scaled_return<V,S>::return_type
+  scaled(const V &v, S x, abstract_vector)
+  { return scaled_vector_const_ref<V,S>(v, x); }
+
+  template <typename M, typename S> inline
+  typename scaled_return<M,S>::return_type
+  scaled(const M &m, S x,abstract_matrix) {
+    return scaled(m, x,  typename principal_orientation_type<typename
+		  linalg_traits<M>::sub_orientation>::potype());
+  }
+
+  template <typename M, typename S> inline
+  typename scaled_return<M,S>::return_type
+  scaled(const M &m, S x, row_major) {
+    return scaled_row_matrix_const_ref<M,S>(m, x);
+  }
+
+  template <typename M, typename S> inline
+  typename scaled_return<M,S>::return_type
+  scaled(const M &m, S x, col_major) {
+    return scaled_col_matrix_const_ref<M,S>(m, x);
+  }
+
+  
+  /* ******************************************************************** */
+  /*	matrix or vector scale                                	          */
+  /* ******************************************************************** */
+
+  template <typename L> inline
+  void scale(L& l, typename linalg_traits<L>::value_type a)
+  { scale(l, a, typename linalg_traits<L>::linalg_type()); }
+
+  template <typename L> inline
+  void scale(const L& l, typename linalg_traits<L>::value_type a)
+  { scale(linalg_const_cast(l), a); }
+
+  template <typename L> inline
+  void scale(L& l, typename linalg_traits<L>::value_type a, abstract_vector) {
+    typename linalg_traits<L>::iterator it = vect_begin(l), ite = vect_end(l);
+    for ( ; it != ite; ++it) *it *= a;
+  }
+
+  template <typename L> 
+  void scale(L& l, typename linalg_traits<L>::value_type a, abstract_matrix) {
+    scale(l, a, typename principal_orientation_type<typename
+	  linalg_traits<L>::sub_orientation>::potype());
+  }
+
+  template <typename L> 
+  void scale(L& l, typename linalg_traits<L>::value_type a, row_major) {
+    typename linalg_traits<L>::row_iterator it = mat_row_begin(l),
+      ite = mat_row_end(l);
+    for ( ; it != ite; ++it) scale(linalg_traits<L>::row(it), a);
+  }
+
+  template <typename L> 
+  void scale(L& l, typename linalg_traits<L>::value_type a, col_major) {
+    typename linalg_traits<L>::col_iterator it = mat_col_begin(l),
+      ite = mat_col_end(l);
+    for ( ; it != ite; ++it) scale(linalg_traits<L>::col(it), a);
+  }
+
+}
+
+#endif //  GMM_SCALED_H__
diff --git a/Contrib/gmm/gmm_solver_Newton.h b/Contrib/gmm/gmm_solver_Newton.h
new file mode 100755
index 0000000..34c95dd
--- /dev/null
+++ b/Contrib/gmm/gmm_solver_Newton.h
@@ -0,0 +1,137 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2006-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_solver_Newton.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @author  Michel Fournie <fournie at mip.ups-tlse.fr>
+   @date January 24, 2006.
+*/
+#ifndef GMM_SOLVERS_NEWTON_H__
+#define GMM_SOLVERS_NEWTON_H__ 
+
+namespace gmm {
+
+#include "gmm_kernel.h"
+
+  /* ***************************************************************** */
+  /*     Line search definition                                        */
+  /* ***************************************************************** */
+
+  struct abstract_newton_line_search {
+    double conv_alpha, conv_r;
+    size_t it, itmax, glob_it;
+    virtual void init_search(double r, size_t git) = 0;
+    virtual double next_try(void) = 0;
+    virtual bool is_converged(double) = 0;
+    virtual double converged_value(void) { return conv_alpha; };
+    virtual double converged_residual(void) { return conv_r; };
+    virtual ~abstract_newton_line_search() {}
+  };
+
+
+  struct simplest_newton_line_search : public abstract_newton_line_search {
+    double alpha, alpha_mult, first_res, alpha_max_ratio, alpha_min;
+    virtual void init_search(double r, size_t git) {
+      glob_it = git;
+      conv_alpha = alpha = double(1); conv_r = first_res = r; it = 0;
+    }
+    virtual double next_try(void)
+    { conv_alpha = alpha; alpha *= alpha_mult; ++it; return conv_alpha; }
+    virtual bool is_converged(double r) {
+      conv_r = r;
+      return ((it <= 1 && r < first_res)
+	      || (r <= first_res * alpha_max_ratio)
+	      || (conv_alpha <= alpha_min)
+	      || it >= itmax);
+    }
+    simplest_newton_line_search
+    (size_t imax = size_t(-1), double a_max_ratio = 6.0/5.0,
+     double a_min = 1.0/1000.0, double a_mult = 3.0/5.0)
+      : alpha_mult(a_mult), alpha_max_ratio(a_max_ratio), alpha_min(a_min)
+      { itmax = imax; }
+  };
+
+  struct default_newton_line_search : public abstract_newton_line_search {
+    double alpha, alpha_mult, first_res, alpha_max_ratio;
+    double alpha_min, prev_res, alpha_max_augment;
+    virtual void init_search(double r, size_t git) {
+      glob_it = git;
+      conv_alpha = alpha = double(1);
+      prev_res = conv_r = first_res = r; it = 0;
+    }
+    virtual double next_try(void)
+    { conv_alpha = alpha; alpha *= alpha_mult; ++it; return conv_alpha; }
+    virtual bool is_converged(double r) {
+      if (glob_it == 0 || (r < first_res / double(2))
+	  || (conv_alpha <= alpha_min && r < first_res * alpha_max_augment)
+	  || it >= itmax)
+	{ conv_r = r; return true; }
+      if (it > 1 && r > prev_res && prev_res < alpha_max_ratio * first_res)
+	return true;
+      prev_res = conv_r = r;
+      return false;
+    }
+    default_newton_line_search
+    (size_t imax = size_t(-1),
+     double a_max_ratio = 5.0/3.0,
+     double a_min = 1.0/1000.0, double a_mult = 3.0/5.0, double a_augm = 2.0)
+      : alpha_mult(a_mult), alpha_max_ratio(a_max_ratio),
+	alpha_min(a_min), alpha_max_augment(a_augm) { itmax = imax; }
+  };
+
+
+  struct systematic_newton_line_search : public abstract_newton_line_search {
+    double alpha, alpha_mult, first_res;
+    double alpha_min, prev_res;
+    bool first;
+    virtual void init_search(double r, size_t git) {
+      glob_it = git;
+      conv_alpha = alpha = double(1);
+      prev_res = conv_r = first_res = r; it = 0; first = true;
+    }
+    virtual double next_try(void)
+    { double a = alpha; alpha *= alpha_mult; ++it; return a; }
+    virtual bool is_converged(double r) {
+      // cout << "a = " << alpha / alpha_mult << " r = " << r << endl;
+      if (r < conv_r || first)
+	{ conv_r = r; conv_alpha = alpha / alpha_mult; first = false; }
+      if ((alpha <= alpha_min*alpha_mult) || it >= itmax) return true;
+      return false;
+    }
+    systematic_newton_line_search
+    (size_t imax = size_t(-1),
+     double a_min = 1.0/10000.0, double a_mult = 3.0/5.0)
+      : alpha_mult(a_mult), alpha_min(a_min)  { itmax = imax; }
+  };
+
+}
+
+
+#endif
diff --git a/Contrib/gmm/gmm_solver_Schwarz_additive.h b/Contrib/gmm/gmm_solver_Schwarz_additive.h
new file mode 100755
index 0000000..7f4c958
--- /dev/null
+++ b/Contrib/gmm/gmm_solver_Schwarz_additive.h
@@ -0,0 +1,746 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_solver_Schwarz_additive.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @author  Michel Fournie <fournie at mip.ups-tlse.fr>
+   @date October 13, 2002.
+*/
+
+#ifndef GMM_SOLVERS_SCHWARZ_ADDITIVE_H__
+#define GMM_SOLVERS_SCHWARZ_ADDITIVE_H__ 
+
+#include "gmm_kernel.h"
+#include "gmm_superlu_interface.h"
+#include "gmm_solver_cg.h"
+#include "gmm_solver_gmres.h"
+#include "gmm_solver_bicgstab.h"
+#include "gmm_solver_qmr.h"
+#include "gmm_solver_Newton.h"
+
+namespace gmm {
+      
+  /* ******************************************************************** */
+  /*		Additive Schwarz interfaced local solvers                 */
+  /* ******************************************************************** */
+
+  struct using_cg {};
+  struct using_gmres {};
+  struct using_bicgstab {};
+  struct using_qmr {};
+
+  template <typename P, typename local_solver, typename Matrix>
+  struct actual_precond {
+    typedef P APrecond;
+    static const APrecond &transform(const P &PP) { return PP; }
+  };
+
+  template <typename Matrix1, typename Precond, typename Vector> 
+  void AS_local_solve(using_cg, const Matrix1 &A, Vector &x, const Vector &b,
+		 const Precond &P, iteration &iter)
+  { cg(A, x, b, P, iter); }
+
+  template <typename Matrix1, typename Precond, typename Vector> 
+  void AS_local_solve(using_gmres, const Matrix1 &A, Vector &x,
+		      const Vector &b, const Precond &P, iteration &iter)
+  { gmres(A, x, b, P, 100, iter); }
+  
+  template <typename Matrix1, typename Precond, typename Vector> 
+  void AS_local_solve(using_bicgstab, const Matrix1 &A, Vector &x,
+		      const Vector &b, const Precond &P, iteration &iter)
+  { bicgstab(A, x, b, P, iter); }
+
+  template <typename Matrix1, typename Precond, typename Vector> 
+  void AS_local_solve(using_qmr, const Matrix1 &A, Vector &x,
+		      const Vector &b, const Precond &P, iteration &iter)
+  { qmr(A, x, b, P, iter); }
+
+#if defined(GMM_USES_SUPERLU)
+  struct using_superlu {};
+
+  template <typename P, typename Matrix>
+  struct actual_precond<P, using_superlu, Matrix> {
+    typedef typename linalg_traits<Matrix>::value_type value_type;
+    typedef SuperLU_factor<value_type> APrecond;
+    template <typename PR>
+    static APrecond transform(const PR &) { return APrecond(); }
+    static const APrecond &transform(const APrecond &PP) { return PP; }
+  };
+
+  template <typename Matrix1, typename Precond, typename Vector> 
+  void AS_local_solve(using_superlu, const Matrix1 &, Vector &x,
+		      const Vector &b, const Precond &P, iteration &iter)
+  { P.solve(x, b); iter.set_iteration(1); }
+#endif
+
+  /* ******************************************************************** */
+  /*		Additive Schwarz Linear system                            */
+  /* ******************************************************************** */
+
+  template <typename Matrix1, typename Matrix2, typename Precond,
+	    typename local_solver>
+  struct add_schwarz_mat{
+    typedef typename linalg_traits<Matrix1>::value_type value_type;
+
+    const Matrix1 *A;
+    const std::vector<Matrix2> *vB;
+    std::vector<Matrix2> vAloc;
+    mutable iteration iter;
+    double residual;
+    mutable size_type itebilan;
+    mutable std::vector<std::vector<value_type> > gi, fi;
+    std::vector<typename actual_precond<Precond, local_solver,
+					Matrix1>::APrecond> precond1;
+
+    void init(const Matrix1 &A_, const std::vector<Matrix2> &vB_,
+	      iteration iter_, const Precond &P, double residual_);
+
+    add_schwarz_mat(void) {}
+    add_schwarz_mat(const Matrix1 &A_, const std::vector<Matrix2> &vB_,
+		iteration iter_, const Precond &P, double residual_)
+    { init(A_, vB_, iter_, P, residual_); }
+  };
+
+  template <typename Matrix1, typename Matrix2, typename Precond,
+	    typename local_solver>
+  void add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver>::init(
+       const Matrix1 &A_, const std::vector<Matrix2> &vB_,
+       iteration iter_, const Precond &P, double residual_) {
+
+    vB = &vB_; A = &A_; iter = iter_;
+    residual = residual_;
+    
+    size_type nb_sub = vB->size();
+    vAloc.resize(nb_sub);
+    gi.resize(nb_sub); fi.resize(nb_sub);
+    precond1.resize(nb_sub);
+    std::fill(precond1.begin(), precond1.end(),
+	      actual_precond<Precond, local_solver, Matrix1>::transform(P));
+    itebilan = 0;
+    
+    if (iter.get_noisy()) cout << "Init pour sub dom ";
+#ifdef GMM_USES_MPI
+    int size,tranche,borne_sup,borne_inf,rank,tag1=11,tag2=12,tag3=13,sizepr = 0;
+    //    int tab[4];
+    double t_ref,t_final;
+    MPI_Status status;
+    t_ref=MPI_Wtime();
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+    tranche=nb_sub/size;
+    borne_inf=rank*tranche;
+    borne_sup=(rank+1)*tranche;
+    // if (rank==size-1) borne_sup = nb_sub;
+
+    cout << "Nombre de sous domaines " << borne_sup - borne_inf << endl;
+
+    int sizeA = mat_nrows(*A);
+    gmm::csr_matrix<value_type> Acsr(sizeA, sizeA), Acsrtemp(sizeA, sizeA);
+    gmm::copy(gmm::eff_matrix(*A), Acsr);
+    int next = (rank + 1) % size;
+    int previous = (rank + size - 1) % size;
+    //communication of local information on ring pattern
+    //Each process receive  Nproc-1 contributions 
+
+    for (int nproc = 0; nproc < size; ++nproc) {
+       for (size_type i = size_type(borne_inf); i < size_type(borne_sup); ++i) {
+// 	for (size_type i = 0; i < nb_sub/size; ++i) {
+// 	for (size_type i = 0; i < nb_sub; ++i) {
+	// size_type i=(rank+size*(j-1)+nb_sub)%nb_sub;
+
+	cout << "Sous domaines " << i << " : " << mat_ncols((*vB)[i]) << endl;
+#else
+	for (size_type i = 0; i < nb_sub; ++i) {
+#endif
+	  
+	  if (iter.get_noisy()) cout << i << " " << std::flush;
+	  Matrix2 Maux(mat_ncols((*vB)[i]), mat_nrows((*vB)[i]));
+	  
+#ifdef GMM_USES_MPI
+	  Matrix2 Maux2(mat_ncols((*vB)[i]), mat_ncols((*vB)[i]));
+	  if (nproc == 0) {
+	    gmm::resize(vAloc[i], mat_ncols((*vB)[i]), mat_ncols((*vB)[i]));
+	    gmm::clear(vAloc[i]);
+	  }
+	  gmm::mult(gmm::transposed((*vB)[i]), Acsr, Maux);
+	  gmm::mult(Maux, (*vB)[i], Maux2);
+	  gmm::add(Maux2, vAloc[i]);
+#else
+	  gmm::resize(vAloc[i], mat_ncols((*vB)[i]), mat_ncols((*vB)[i]));
+	  gmm::mult(gmm::transposed((*vB)[i]), *A, Maux);
+	  gmm::mult(Maux, (*vB)[i], vAloc[i]);
+#endif
+
+#ifdef GMM_USES_MPI
+	  if (nproc == size - 1 ) {
+#endif
+	    precond1[i].build_with(vAloc[i]);
+	    gmm::resize(fi[i], mat_ncols((*vB)[i]));
+	    gmm::resize(gi[i], mat_ncols((*vB)[i]));
+#ifdef GMM_USES_MPI
+	  }
+#else
+	}
+#endif
+#ifdef GMM_USES_MPI
+     }
+      if (nproc != size - 1) {
+	MPI_Sendrecv(Acsr.jc, sizeA+1, MPI_INT, next, tag2,
+		     Acsrtemp.jc, sizeA+1,MPI_INT,previous,tag2,
+		     MPI_COMM_WORLD,&status);
+	if (Acsrtemp.jc[sizeA] > size_type(sizepr)) {
+	  sizepr = Acsrtemp.jc[sizeA];
+	  delete[] Acsrtemp.pr; delete[] Acsrtemp.ir;
+	  Acsrtemp.pr = new value_type[sizepr];
+	  Acsrtemp.ir = new unsigned int[sizepr];
+	}
+	MPI_Sendrecv(Acsr.ir, Acsr.jc[sizeA], MPI_INT, next, tag1,
+		     Acsrtemp.ir, Acsrtemp.jc[sizeA],MPI_INT,previous,tag1,
+		     MPI_COMM_WORLD,&status);
+	
+	MPI_Sendrecv(Acsr.pr, Acsr.jc[sizeA], mpi_type(value_type()), next, tag3, 
+		     Acsrtemp.pr, Acsrtemp.jc[sizeA],mpi_type(value_type()),previous,tag3,
+		     MPI_COMM_WORLD,&status);
+	gmm::copy(Acsrtemp, Acsr);
+      }
+    }
+      t_final=MPI_Wtime();
+    cout<<"temps boucle precond "<< t_final-t_ref<<endl;
+#endif
+    if (iter.get_noisy()) cout << "\n";
+  }
+  
+  template <typename Matrix1, typename Matrix2, typename Precond,
+	    typename Vector2, typename Vector3, typename local_solver>
+  void mult(const add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver> &M,
+	    const Vector2 &p, Vector3 &q) {
+    size_type itebilan = 0;
+#ifdef GMM_USES_MPI
+    static double tmult_tot = 0.0;
+    double t_ref = MPI_Wtime();
+#endif
+    // cout << "tmult AS begin " << endl;
+    mult(*(M.A), p, q);
+#ifdef GMM_USES_MPI
+    tmult_tot += MPI_Wtime()-t_ref;
+    cout << "tmult_tot = " << tmult_tot << endl;
+#endif
+    std::vector<double> qbis(gmm::vect_size(q));
+    std::vector<double> qter(gmm::vect_size(q));
+#ifdef GMM_USES_MPI
+    //    MPI_Status status;
+    //    MPI_Request request,request1;
+    //    int tag=111;
+    int size,tranche,borne_sup,borne_inf,rank;
+    size_type nb_sub=M.fi.size();
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+    tranche=nb_sub/size;
+    borne_inf=rank*tranche;
+    borne_sup=(rank+1)*tranche;
+    // if (rank==size-1) borne_sup=nb_sub;
+    //    int next = (rank + 1) % size;
+    //    int previous = (rank + size - 1) % size;
+    t_ref = MPI_Wtime();
+     for (size_type i = size_type(borne_inf); i < size_type(borne_sup); ++i)
+//        for (size_type i = 0; i < nb_sub/size; ++i)
+      // for (size_type j = 0; j < nb_sub; ++j)
+#else
+    for (size_type i = 0; i < M.fi.size(); ++i)
+#endif
+      {
+#ifdef GMM_USES_MPI
+	// size_type i=j; // (rank+size*(j-1)+nb_sub)%nb_sub;
+#endif
+	gmm::mult(gmm::transposed((*(M.vB))[i]), q, M.fi[i]);
+       M.iter.init();
+       AS_local_solve(local_solver(), (M.vAloc)[i], (M.gi)[i],
+		      (M.fi)[i],(M.precond1)[i],M.iter);
+       itebilan = std::max(itebilan, M.iter.get_iteration());
+       }
+
+#ifdef GMM_USES_MPI
+    cout << "First  AS loop time " <<  MPI_Wtime() - t_ref << endl;
+#endif
+
+    gmm::clear(q);
+#ifdef GMM_USES_MPI
+    t_ref = MPI_Wtime();
+    // for (size_type j = 0; j < nb_sub; ++j)
+    for (size_type i = size_type(borne_inf); i < size_type(borne_sup); ++i)
+
+#else
+      for (size_type i = 0; i < M.gi.size(); ++i)
+#endif
+	{
+
+#ifdef GMM_USES_MPI
+	  // size_type i=j; // (rank+size*(j-1)+nb_sub)%nb_sub;
+// 	  gmm::mult((*(M.vB))[i], M.gi[i], qbis,qbis);
+	  gmm::mult((*(M.vB))[i], M.gi[i], qter);
+	  add(qter,qbis,qbis);
+#else
+	  gmm::mult((*(M.vB))[i], M.gi[i], q, q);
+#endif
+	}
+#ifdef GMM_USES_MPI
+     //WARNING this add only if you use the ring pattern below
+  // need to do this below if using a n explicit ring pattern communication
+
+//      add(qbis,q,q);
+    cout << "Second AS loop time " <<  MPI_Wtime() - t_ref << endl;
+#endif
+
+
+#ifdef GMM_USES_MPI
+    //    int tag1=11;
+    static double t_tot = 0.0;
+    double t_final;
+    t_ref=MPI_Wtime();
+//     int next = (rank + 1) % size;
+//     int previous = (rank + size - 1) % size;
+    //communication of local information on ring pattern
+    //Each process receive  Nproc-1 contributions 
+
+//     if (size > 1) {
+//     for (int nproc = 0; nproc < size-1; ++nproc) 
+//       {
+
+// 	MPI_Sendrecv(&(qbis[0]), gmm::vect_size(q), MPI_DOUBLE, next, tag1,
+// 		   &(qter[0]), gmm::vect_size(q),MPI_DOUBLE,previous,tag1,
+// 		   MPI_COMM_WORLD,&status);
+// 	gmm::copy(qter, qbis);
+// 	add(qbis,q,q);
+//       }
+//     }
+    MPI_Allreduce(&(qbis[0]), &(q[0]),gmm::vect_size(q), MPI_DOUBLE,
+		  MPI_SUM,MPI_COMM_WORLD);
+    t_final=MPI_Wtime();
+    t_tot += t_final-t_ref;
+     cout<<"["<< rank<<"] temps reduce Resol "<< t_final-t_ref << " t_tot = " << t_tot << endl;
+#endif 
+
+    if (M.iter.get_noisy() > 0) cout << "itebloc = " << itebilan << endl;
+    M.itebilan += itebilan;
+    M.iter.set_resmax((M.iter.get_resmax() + M.residual) * 0.5);
+  }
+
+  template <typename Matrix1, typename Matrix2, typename Precond,
+	    typename Vector2, typename Vector3, typename local_solver>
+  void mult(const add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver> &M,
+	    const Vector2 &p, const Vector3 &q) {
+    mult(M, p, const_cast<Vector3 &>(q));
+  }
+
+  template <typename Matrix1, typename Matrix2, typename Precond,
+	    typename Vector2, typename Vector3, typename Vector4,
+	    typename local_solver>
+  void mult(const add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver> &M,
+	    const Vector2 &p, const Vector3 &p2, Vector4 &q)
+  { mult(M, p, q); add(p2, q); }
+
+  template <typename Matrix1, typename Matrix2, typename Precond,
+	    typename Vector2, typename Vector3, typename Vector4,
+	    typename local_solver>
+  void mult(const add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver> &M,
+	    const Vector2 &p, const Vector3 &p2, const Vector4 &q)
+  { mult(M, p, const_cast<Vector4 &>(q)); add(p2, q); }
+
+  /* ******************************************************************** */
+  /*		Additive Schwarz interfaced global solvers                */
+  /* ******************************************************************** */
+
+  template <typename ASM_type, typename Vect>
+  void AS_global_solve(using_cg, const ASM_type &ASM, Vect &x,
+		       const Vect &b, iteration &iter)
+  { cg(ASM, x, b, *(ASM.A), identity_matrix(), iter); }
+
+  template <typename ASM_type, typename Vect>
+  void AS_global_solve(using_gmres, const ASM_type &ASM, Vect &x,
+		       const Vect &b, iteration &iter)
+  { gmres(ASM, x, b, identity_matrix(), 100, iter); }
+
+  template <typename ASM_type, typename Vect>
+  void AS_global_solve(using_bicgstab, const ASM_type &ASM, Vect &x,
+		       const Vect &b, iteration &iter)
+  { bicgstab(ASM, x, b, identity_matrix(), iter); }
+
+  template <typename ASM_type, typename Vect>
+  void AS_global_solve(using_qmr,const ASM_type &ASM, Vect &x,
+		       const Vect &b, iteration &iter)
+  { qmr(ASM, x, b, identity_matrix(), iter); }
+
+#if defined(GMM_USES_SUPERLU)
+  template <typename ASM_type, typename Vect>
+  void AS_global_solve(using_superlu, const ASM_type &, Vect &,
+		       const Vect &, iteration &) {
+    GMM_ASSERT1(false, "You cannot use SuperLU as "
+		"global solver in additive Schwarz meethod");
+  }
+#endif
+  
+  /* ******************************************************************** */
+  /*	            Linear Additive Schwarz method                        */
+  /* ******************************************************************** */
+  /* ref : Domain decomposition algorithms for the p-version finite       */
+  /*       element method for elliptic problems, Luca F. Pavarino,        */
+  /*       PhD thesis, Courant Institute of Mathematical Sciences, 1992.  */
+  /* ******************************************************************** */
+
+  /** Function to call if the ASM matrix is precomputed for successive solve
+   * with the same system.
+   */
+  template <typename Matrix1, typename Matrix2,
+	    typename Vector2, typename Vector3, typename Precond,
+	    typename local_solver, typename global_solver>
+  void additive_schwarz(
+    add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver> &ASM, Vector3 &u,
+    const Vector2 &f, iteration &iter, const global_solver&) {
+
+    typedef typename linalg_traits<Matrix1>::value_type value_type;
+
+    size_type nb_sub = ASM.vB->size(), nb_dof = gmm::vect_size(f);
+    ASM.itebilan = 0;
+    std::vector<value_type> g(nb_dof);
+    std::vector<value_type> gbis(nb_dof);
+#ifdef GMM_USES_MPI
+    double t_init=MPI_Wtime();
+    int size,tranche,borne_sup,borne_inf,rank;
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+    tranche=nb_sub/size;
+    borne_inf=rank*tranche;
+    borne_sup=(rank+1)*tranche;
+    // if (rank==size-1) borne_sup=nb_sub*size;
+    for (size_type i = size_type(borne_inf); i < size_type(borne_sup); ++i)
+//     for (size_type i = 0; i < nb_sub/size; ++i)
+      // for (size_type j = 0; j < nb_sub; ++j)
+      // for (size_type i = rank; i < nb_sub; i+=size)
+#else
+    for (size_type i = 0; i < nb_sub; ++i)
+#endif
+    {
+
+#ifdef GMM_USES_MPI
+      // size_type i=j; // (rank+size*(j-1)+nb_sub)%nb_sub;
+#endif
+      gmm::mult(gmm::transposed((*(ASM.vB))[i]), f, ASM.fi[i]);
+      ASM.iter.init();
+      AS_local_solve(local_solver(), ASM.vAloc[i], ASM.gi[i], ASM.fi[i],
+		     ASM.precond1[i], ASM.iter);
+      ASM.itebilan = std::max(ASM.itebilan, ASM.iter.get_iteration());
+#ifdef GMM_USES_MPI
+    gmm::mult((*(ASM.vB))[i], ASM.gi[i], gbis,gbis);
+#else   
+    gmm::mult((*(ASM.vB))[i], ASM.gi[i], g, g);
+#endif
+    }
+#ifdef GMM_USES_MPI
+    cout<<"temps boucle init "<< MPI_Wtime()-t_init<<endl;
+    double t_ref,t_final;
+    t_ref=MPI_Wtime();
+    MPI_Allreduce(&(gbis[0]), &(g[0]),gmm::vect_size(g), MPI_DOUBLE,
+		  MPI_SUM,MPI_COMM_WORLD);
+    t_final=MPI_Wtime();
+    cout<<"temps reduce init "<< t_final-t_ref<<endl;
+#endif
+#ifdef GMM_USES_MPI
+    t_ref=MPI_Wtime();
+    cout<<"begin global AS"<<endl;
+#endif
+    AS_global_solve(global_solver(), ASM, u, g, iter);
+#ifdef GMM_USES_MPI
+    t_final=MPI_Wtime();
+    cout<<"temps AS Global Solve "<< t_final-t_ref<<endl;
+#endif
+    if (iter.get_noisy())
+      cout << "Total number of internal iterations : " << ASM.itebilan << endl;
+  }
+
+  /** Global function. Compute the ASM matrix and call the previous function.
+   *  The ASM matrix represent the preconditionned linear system.
+   */
+  template <typename Matrix1, typename Matrix2,
+	    typename Vector2, typename Vector3, typename Precond,
+	    typename local_solver, typename global_solver>
+  void additive_schwarz(const Matrix1 &A, Vector3 &u,
+				  const Vector2 &f, const Precond &P,
+				  const std::vector<Matrix2> &vB,
+				  iteration &iter, local_solver,
+				  global_solver) {
+    iter.set_rhsnorm(vect_norm2(f));
+    if (iter.get_rhsnorm() == 0.0) { gmm::clear(u); return; }
+    iteration iter2 = iter; iter2.reduce_noisy();
+    iter2.set_maxiter(size_type(-1));
+    add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver>
+      ASM(A, vB, iter2, P, iter.get_resmax());
+    additive_schwarz(ASM, u, f, iter, global_solver());
+  }
+
+  /* ******************************************************************** */
+  /*		Sequential Non-Linear Additive Schwarz method             */
+  /* ******************************************************************** */
+  /* ref : Nonlinearly Preconditionned Inexact Newton Algorithms,         */
+  /*       Xiao-Chuan Cai, David E. Keyes,                                */
+  /*       SIAM J. Sci. Comp. 24: p183-200.  l                             */
+  /* ******************************************************************** */
+
+  template <typename Matrixt, typename MatrixBi> 
+  class NewtonAS_struct {
+    
+  public :
+    typedef Matrixt tangent_matrix_type;
+    typedef MatrixBi B_matrix_type;
+    typedef typename linalg_traits<Matrixt>::value_type value_type;
+    typedef std::vector<value_type> Vector;
+    
+    virtual size_type size(void) = 0;
+    virtual const std::vector<MatrixBi> &get_vB() = 0;
+    
+    virtual void compute_F(Vector &f, Vector &x) = 0;
+    virtual void compute_tangent_matrix(Matrixt &M, Vector &x) = 0;
+    // compute Bi^T grad(F(X)) Bi
+    virtual void compute_sub_tangent_matrix(Matrixt &Mloc, Vector &x,
+					    size_type i) = 0;
+    // compute Bi^T F(X)
+    virtual void compute_sub_F(Vector &fi, Vector &x, size_type i) = 0;
+
+    virtual ~NewtonAS_struct() {}
+  };
+
+  template <typename Matrixt, typename MatrixBi> 
+  struct AS_exact_gradient {
+    const std::vector<MatrixBi> &vB;
+    std::vector<Matrixt> vM;
+    std::vector<Matrixt> vMloc;
+
+    void init(void) {
+      for (size_type i = 0; i < vB.size(); ++i) {
+	Matrixt aux(gmm::mat_ncols(vB[i]), gmm::mat_ncols(vM[i]));
+	gmm::resize(vMloc[i], gmm::mat_ncols(vB[i]), gmm::mat_ncols(vB[i]));
+	gmm::mult(gmm::transposed(vB[i]), vM[i], aux);
+	gmm::mult(aux, vB[i], vMloc[i]);
+      }
+    }
+    AS_exact_gradient(const std::vector<MatrixBi> &vB_) : vB(vB_) {
+      vM.resize(vB.size()); vMloc.resize(vB.size());
+      for (size_type i = 0; i < vB.size(); ++i) {
+	gmm::resize(vM[i], gmm::mat_nrows(vB[i]), gmm::mat_nrows(vB[i]));
+      }
+    }
+  };
+
+  template <typename Matrixt, typename MatrixBi,
+	    typename Vector2, typename Vector3>
+  void mult(const AS_exact_gradient<Matrixt, MatrixBi> &M,
+	    const Vector2 &p, Vector3 &q) {
+    gmm::clear(q);
+    typedef typename gmm::linalg_traits<Vector3>::value_type T;
+    std::vector<T> v(gmm::vect_size(p)), w, x;
+    for (size_type i = 0; i < M.vB.size(); ++i) {
+      w.resize(gmm::mat_ncols(M.vB[i]));
+      x.resize(gmm::mat_ncols(M.vB[i]));
+      gmm::mult(M.vM[i], p, v);
+      gmm::mult(gmm::transposed(M.vB[i]), v, w);
+      double rcond;
+      SuperLU_solve(M.vMloc[i], x, w, rcond);
+      // gmm::iteration iter(1E-10, 0, 100000);
+      //gmm::gmres(M.vMloc[i], x, w, gmm::identity_matrix(), 50, iter);
+      gmm::mult_add(M.vB[i], x, q);
+    }
+  }
+
+  template <typename Matrixt, typename MatrixBi,
+	    typename Vector2, typename Vector3>
+  void mult(const AS_exact_gradient<Matrixt, MatrixBi> &M,
+	    const Vector2 &p, const Vector3 &q) {
+    mult(M, p, const_cast<Vector3 &>(q));
+  }
+
+  template <typename Matrixt, typename MatrixBi,
+	    typename Vector2, typename Vector3, typename Vector4>
+  void mult(const AS_exact_gradient<Matrixt, MatrixBi> &M,
+	    const Vector2 &p, const Vector3 &p2, Vector4 &q)
+  { mult(M, p, q); add(p2, q); }
+
+  template <typename Matrixt, typename MatrixBi,
+	    typename Vector2, typename Vector3, typename Vector4>
+  void mult(const AS_exact_gradient<Matrixt, MatrixBi> &M,
+	    const Vector2 &p, const Vector3 &p2, const Vector4 &q)
+  { mult(M, p, const_cast<Vector4 &>(q)); add(p2, q); }
+  
+
+  
+  template <typename Matrixt, typename MatrixBi, typename Vector,
+	    typename Precond, typename local_solver, typename global_solver>
+  void Newton_additive_Schwarz(NewtonAS_struct<Matrixt, MatrixBi> &NS,
+			       const Vector &u_,
+			       iteration &iter, const Precond &P,
+			       local_solver, global_solver) {
+    Vector &u = const_cast<Vector &>(u_);
+    typedef typename linalg_traits<Vector>::value_type value_type;
+    typedef typename number_traits<value_type>::magnitude_type mtype;
+    typedef actual_precond<Precond, local_solver, Matrixt> chgt_precond;
+    
+    double residual = iter.get_resmax();
+
+    default_newton_line_search internal_ls;
+    default_newton_line_search external_ls(size_t(-1), 5.0/3, 1.0/1000, 3.0/5);
+
+    // systematic_newton_line_search external_ls(size_t(-1), 1.0/10000.0, 3.0/100.0);
+
+    typename chgt_precond::APrecond PP = chgt_precond::transform(P);
+    iter.set_rhsnorm(mtype(1));
+    iteration iternc(iter);
+    iternc.reduce_noisy(); iternc.set_maxiter(size_type(-1));
+    iteration iter2(iternc);
+    iteration iter3(iter2); iter3.reduce_noisy();
+    iteration iter4(iter3);
+    iternc.set_name("Local Newton");
+    iter2.set_name("Linear System for Global Newton");
+    iternc.set_resmax(residual/100.0);
+    iter3.set_resmax(residual/10000.0);
+    iter2.set_resmax(residual/1000.0);
+    iter4.set_resmax(residual/1000.0);
+    std::vector<value_type> rhs(NS.size()), x(NS.size()), d(NS.size());
+    std::vector<value_type> xi, xii, fi, di;
+
+    std::vector< std::vector<value_type> > vx(NS.get_vB().size());
+    for (size_type i = 0; i < NS.get_vB().size(); ++i) // for exact gradient
+      vx[i].resize(NS.size()); // for exact gradient
+
+    Matrixt Mloc, M(NS.size(), NS.size());
+    NS.compute_F(rhs, u);
+    mtype act_res=gmm::vect_norm2(rhs), act_res_new(0), precond_res = act_res;
+    mtype alpha;
+    
+    while(!iter.finished(std::min(act_res, precond_res))) {
+      for (int SOR_step = 0;  SOR_step >= 0; --SOR_step) {
+	gmm::clear(rhs);
+	for (size_type isd = 0; isd < NS.get_vB().size(); ++isd) {
+	  const MatrixBi &Bi = (NS.get_vB())[isd];
+	  size_type si = mat_ncols(Bi);
+	  gmm::resize(Mloc, si, si);
+	  xi.resize(si); xii.resize(si); fi.resize(si); di.resize(si);
+	  
+	  iternc.init();
+	  iternc.set_maxiter(30); // ?
+	  if (iternc.get_noisy())
+	    cout << "Non-linear local problem " << isd << endl;
+	  gmm::clear(xi);
+	  gmm::copy(u, x);
+	  NS.compute_sub_F(fi, x, isd); gmm::scale(fi, value_type(-1));
+	  mtype r = gmm::vect_norm2(fi), r_t(r);
+	  if (r > value_type(0)) {
+	    iternc.set_rhsnorm(std::max(r, mtype(1)));
+	    while(!iternc.finished(r)) {
+	      NS.compute_sub_tangent_matrix(Mloc, x, isd);
+
+	      PP.build_with(Mloc);
+	      iter3.init();
+	      AS_local_solve(local_solver(), Mloc, di, fi, PP, iter3);
+	      
+	      internal_ls.init_search(r, iternc.get_iteration());
+	      do {
+		alpha = internal_ls.next_try();
+		gmm::add(xi, gmm::scaled(di, -alpha), xii);
+		gmm::mult(Bi, gmm::scaled(xii, -1.0), u, x);
+		NS.compute_sub_F(fi, x, isd); gmm::scale(fi, value_type(-1));
+		r_t = gmm::vect_norm2(fi);
+	      } while (!internal_ls.is_converged(r_t));
+	      
+	      if (alpha != internal_ls.converged_value()) {
+		alpha = internal_ls.converged_value();
+		gmm::add(xi, gmm::scaled(di, -alpha), xii);
+		gmm::mult(Bi, gmm::scaled(xii, -1.0), u, x);
+		NS.compute_sub_F(fi, x, isd); gmm::scale(fi, value_type(-1));
+		r_t = gmm::vect_norm2(fi);
+	      }
+	      gmm::copy(x, vx[isd]); // for exact gradient
+
+	      if (iternc.get_noisy()) cout << "(step=" << alpha << ")\t";
+	      ++iternc; r = r_t; gmm::copy(xii, xi); 
+	    }
+	    if (SOR_step) gmm::mult(Bi, gmm::scaled(xii, -1.0), u, u);
+	    gmm::mult(Bi, gmm::scaled(xii, -1.0), rhs, rhs);
+	  }
+	}
+	precond_res = gmm::vect_norm2(rhs);
+	if (SOR_step) cout << "SOR step residual = " << precond_res << endl;
+	if (precond_res < residual) break;
+	cout << "Precond residual = " << precond_res << endl;
+      }
+
+      iter2.init();
+      // solving linear system for the global Newton method
+      if (0) {
+	NS.compute_tangent_matrix(M, u);
+	add_schwarz_mat<Matrixt, MatrixBi, Precond, local_solver>
+	  ASM(M, NS.get_vB(), iter4, P, iter.get_resmax());
+	AS_global_solve(global_solver(), ASM, d, rhs, iter2);
+      }
+      else {  // for exact gradient
+	AS_exact_gradient<Matrixt, MatrixBi> eg(NS.get_vB());
+	for (size_type i = 0; i < NS.get_vB().size(); ++i) {
+	  NS.compute_tangent_matrix(eg.vM[i], vx[i]);
+	}
+	eg.init();
+	gmres(eg, d, rhs, gmm::identity_matrix(), 50, iter2);
+      }
+
+      //      gmm::add(gmm::scaled(rhs, 0.1), u); ++iter;
+      external_ls.init_search(act_res, iter.get_iteration());
+      do {
+	alpha = external_ls.next_try();
+	gmm::add(gmm::scaled(d, alpha), u, x);
+	NS.compute_F(rhs, x);
+	act_res_new = gmm::vect_norm2(rhs);
+      } while (!external_ls.is_converged(act_res_new));
+      
+      if (alpha != external_ls.converged_value()) {
+	alpha = external_ls.converged_value();
+	gmm::add(gmm::scaled(d, alpha), u, x);
+	NS.compute_F(rhs, x);
+	act_res_new = gmm::vect_norm2(rhs);
+      }
+
+      if (iter.get_noisy() > 1) cout << endl;
+      act_res = act_res_new; 
+      if (iter.get_noisy()) cout << "(step=" << alpha << ")\t unprecond res = " << act_res << " ";
+      
+      
+      ++iter; gmm::copy(x, u);
+    }
+  }
+
+}
+
+
+#endif //  GMM_SOLVERS_SCHWARZ_ADDITIVE_H__
diff --git a/Contrib/gmm/gmm_solver_bfgs.h b/Contrib/gmm/gmm_solver_bfgs.h
new file mode 100755
index 0000000..297b802
--- /dev/null
+++ b/Contrib/gmm/gmm_solver_bfgs.h
@@ -0,0 +1,207 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2004-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_solver_bfgs.h 
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 14 2004.
+   @brief Implements BFGS (Broyden, Fletcher, Goldfarb, Shanno) algorithm.
+ */
+#ifndef GMM_BFGS_H
+#define GMM_BFGS_H
+
+#include "gmm_kernel.h"
+#include "gmm_iter.h"
+
+namespace gmm {
+
+  // BFGS algorithm (Broyden, Fletcher, Goldfarb, Shanno)
+  // Quasi Newton method for optimization problems.
+  // with Wolfe Line search.
+
+
+  // delta[k] = x[k+1] - x[k]
+  // gamma[k] = grad f(x[k+1]) - grad f(x[k])
+  // H[0] = I
+  // BFGS : zeta[k] = delta[k] - H[k] gamma[k]
+  // DFP  : zeta[k] = H[k] gamma[k]
+  // tau[k] = gamma[k]^T zeta[k]
+  // rho[k] = 1 / gamma[k]^T delta[k]
+  // BFGS : H[k+1] = H[k] + rho[k](zeta[k] delta[k]^T + delta[k] zeta[k]^T)
+  //                 - rho[k]^2 tau[k] delta[k] delta[k]^T
+  // DFP  : H[k+1] = H[k] + rho[k] delta[k] delta[k]^T 
+  //                 - (1/tau[k])zeta[k] zeta[k]^T 
+
+  // Object representing the inverse of the Hessian
+  template <typename VECTOR> struct bfgs_invhessian {
+    
+    typedef typename linalg_traits<VECTOR>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+
+    std::vector<VECTOR> delta, gamma, zeta;
+    std::vector<T> tau, rho;
+    int version;
+
+    template<typename VEC1, typename VEC2> void hmult(const VEC1 &X, VEC2 &Y) {
+      copy(X, Y);
+      for (size_type k = 0 ; k < delta.size(); ++k) {
+	T xdelta = vect_sp(X, delta[k]), xzeta = vect_sp(X, zeta[k]);
+	switch (version) {
+	case 0 : // BFGS
+	  add(scaled(zeta[k], rho[k]*xdelta), Y);
+	  add(scaled(delta[k], rho[k]*(xzeta-rho[k]*tau[k]*xdelta)), Y);
+	  break;
+	case 1 : // DFP
+	  add(scaled(delta[k], rho[k]*xdelta), Y);
+	  add(scaled(zeta[k], -xzeta/tau[k]), Y);
+	  break;
+	}
+      }
+    }
+    
+    void restart(void) {
+      delta.resize(0); gamma.resize(0); zeta.resize(0); 
+      tau.resize(0); rho.resize(0);
+    }
+    
+    template<typename VECT1, typename VECT2>
+    void update(const VECT1 &deltak, const VECT2 &gammak) {
+      size_type N = vect_size(deltak), k = delta.size();
+      VECTOR Y(N);
+      hmult(gammak, Y);
+      delta.resize(k+1); gamma.resize(k+1); zeta.resize(k+1);
+      tau.resize(k+1); rho.resize(k+1);
+      resize(delta[k], N); resize(gamma[k], N); resize(zeta[k], N); 
+      gmm::copy(deltak, delta[k]);
+      gmm::copy(gammak, gamma[k]);
+      rho[k] = R(1) / vect_sp(deltak, gammak);
+      if (version == 0)
+	add(delta[k], scaled(Y, -1), zeta[k]);
+      else
+	gmm::copy(Y, zeta[k]);
+      tau[k] = vect_sp(gammak,  zeta[k]);
+    }
+    
+    bfgs_invhessian(int v = 0) { version = v; }
+  };
+
+
+  template <typename FUNCTION, typename DERIVATIVE, typename VECTOR> 
+  void bfgs(FUNCTION f, DERIVATIVE grad, VECTOR &x,
+	    int restart, iteration& iter, int version = 0,
+	    float lambda_init=0.001, float print_norm=1.0) {
+
+    typedef typename linalg_traits<VECTOR>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+    
+    bfgs_invhessian<VECTOR> invhessian(version);
+    VECTOR r(vect_size(x)), d(vect_size(x)), y(vect_size(x)), r2(vect_size(x));
+    grad(x, r);
+    R lambda = lambda_init, valx = f(x), valy;
+    int nb_restart(0);
+    
+    if (iter.get_noisy() >= 1) cout << "value " << valx / print_norm << " ";
+    while (! iter.finished_vect(r)) {
+
+      invhessian.hmult(r, d); gmm::scale(d, T(-1));
+      
+      // Wolfe Line search
+      R derivative = gmm::vect_sp(r, d);    
+      R lambda_min(0), lambda_max(0), m1 = 0.27, m2 = 0.57;
+      bool unbounded = true, blocked = false, grad_computed = false;
+      
+      for(;;) {
+	add(x, scaled(d, lambda), y);
+	valy = f(y);
+	if (iter.get_noisy() >= 2) {
+	  cout.precision(15);
+	  cout << "Wolfe line search, lambda = " << lambda 
+ 	       << " value = " << valy /print_norm << endl;
+// 	       << " derivative = " << derivative
+// 	       << " lambda min = " << lambda_min << " lambda max = "
+// 	       << lambda_max << endl; getchar();
+	}
+	if (valy <= valx + m1 * lambda * derivative) {
+	  grad(y, r2); grad_computed = true;
+	  T derivative2 = gmm::vect_sp(r2, d);
+	  if (derivative2 >= m2*derivative) break;
+	  lambda_min = lambda;
+	}
+	else {
+	  lambda_max = lambda;
+	  unbounded = false;
+	}
+	if (unbounded) lambda *= R(10);
+	else  lambda = (lambda_max + lambda_min) / R(2);
+	if (lambda == lambda_max || lambda == lambda_min) break;
+	// valy <= R(2)*valx replaced by
+	// valy <= valx + gmm::abs(derivative)*lambda_init
+	// for compatibility with negative values (08.24.07).
+	if (valy <= valx + R(2)*gmm::abs(derivative)*lambda &&
+	    (lambda < R(lambda_init*1E-8) ||
+	     (!unbounded && lambda_max-lambda_min < R(lambda_init*1E-8))))
+	{ blocked = true; lambda = lambda_init; break; }
+      }
+
+      // Rank two update
+      ++iter;
+      if (!grad_computed) grad(y, r2);
+      gmm::add(scaled(r2, -1), r);
+      if (iter.get_iteration() % restart == 0 || blocked) { 
+	if (iter.get_noisy() >= 1) cout << "Restart\n";
+	invhessian.restart();
+	if (++nb_restart > 10) {
+	  if (iter.get_noisy() >= 1) cout << "BFGS is blocked, exiting\n";
+	  return;
+	}
+      }
+      else {
+	invhessian.update(gmm::scaled(d,lambda), gmm::scaled(r,-1));
+	nb_restart = 0;
+      }
+      copy(r2, r); copy(y, x); valx = valy;
+      if (iter.get_noisy() >= 1)
+	cout << "BFGS value " << valx/print_norm << "\t";
+    }
+
+  }
+
+
+  template <typename FUNCTION, typename DERIVATIVE, typename VECTOR> 
+  inline void dfp(FUNCTION f, DERIVATIVE grad, VECTOR &x,
+	    int restart, iteration& iter, int version = 1) {
+    bfgs(f, grad, x, restart, iter, version);
+
+  }
+
+
+}
+
+#endif 
+
diff --git a/Contrib/gmm/gmm_solver_bicgstab.h b/Contrib/gmm/gmm_solver_bicgstab.h
new file mode 100755
index 0000000..0fa6ab8
--- /dev/null
+++ b/Contrib/gmm/gmm_solver_bicgstab.h
@@ -0,0 +1,160 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+// This file is a modified version of bicgstab.h from ITL.
+// See http://osl.iu.edu/research/itl/
+// Following the corresponding Copyright notice.
+//===========================================================================
+//
+// Copyright (c) 1997-2001, The Trustees of Indiana University.
+// All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//    * Redistributions of source code must retain the above copyright
+//      notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above copyright
+//      notice, this list of conditions and the following disclaimer in the
+//      documentation and/or other materials provided with the distribution.
+//    * Neither the name of the University of California, Berkeley nor the
+//      names of its contributors may be used to endorse or promote products
+//      derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE  IS  PROVIDED  BY  THE TRUSTEES  OF  INDIANA UNIVERSITY  AND
+// CONTRIBUTORS  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,  INCLUDING,
+// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS
+// FOR  A PARTICULAR PURPOSE ARE DISCLAIMED. IN  NO  EVENT SHALL THE TRUSTEES
+// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY,  OR CONSEQUENTIAL DAMAGES (INCLUDING,  BUT
+// NOT  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA,  OR PROFITS;  OR BUSINESS  INTERRUPTION)  HOWEVER  CAUSED AND ON ANY
+// THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT  LIABILITY, OR TORT
+// (INCLUDING  NEGLIGENCE  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+// THIS  SOFTWARE,  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//===========================================================================
+
+/**@file gmm_solver_bicgstab.h
+   @author Andrew Lumsdaine <lums at osl.iu.edu>
+   @author Lie-Quan Lee <llee at osl.iu.edu>
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 13, 2002.
+   @brief BiCGStab iterative solver.
+*/
+
+#ifndef GMM_SOLVER_BICGSTAB_H__
+#define GMM_SOLVER_BICGSTAB_H__
+
+#include "gmm_kernel.h"
+#include "gmm_iter.h"
+
+namespace gmm {
+
+  /* ******************************************************************** */
+  /*		BiConjugate Gradient Stabilized               		  */
+  /* (preconditionned, with parametrable scalar product)        	  */
+  /* ******************************************************************** */
+
+  template <typename Matrix, typename Vector, typename VectorB,
+	    typename Preconditioner>
+  void bicgstab(const Matrix& A, Vector& x, const VectorB& b,
+	       const Preconditioner& M, iteration &iter) {
+
+    typedef typename linalg_traits<Vector>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+    typedef typename temporary_dense_vector<Vector>::vector_type temp_vector;
+    
+    T rho_1, rho_2(0), alpha(0), beta, omega(0);
+    temp_vector p(vect_size(x)), phat(vect_size(x)), s(vect_size(x)),
+      shat(vect_size(x)), 
+      t(vect_size(x)), v(vect_size(x)), r(vect_size(x)), rtilde(vect_size(x));
+    
+    gmm::mult(A, gmm::scaled(x, -T(1)), b, r);	  
+    gmm::copy(r, rtilde);
+    R norm_r = gmm::vect_norm2(r);
+    iter.set_rhsnorm(gmm::vect_norm2(b));
+
+    if (iter.get_rhsnorm() == 0.0) { clear(x); return; }
+    
+    while (!iter.finished(norm_r)) {
+      
+      rho_1 = gmm::vect_sp(rtilde, r);
+      if (rho_1 == T(0)) {
+	if (iter.get_maxiter() == size_type(-1)) 
+	  { GMM_ASSERT1(false, "Bicgstab failed to converge"); }
+	else { GMM_WARNING1("Bicgstab failed to converge"); return; }
+      }
+      
+      if (iter.first())
+	gmm::copy(r, p);
+      else {
+	if (omega == T(0)) {
+	  if (iter.get_maxiter() == size_type(-1))
+	    { GMM_ASSERT1(false, "Bicgstab failed to converge"); }
+	  else { GMM_WARNING1("Bicgstab failed to converge"); return; }
+	}
+	
+	beta = (rho_1 / rho_2) * (alpha / omega);
+	
+	gmm::add(gmm::scaled(v, -omega), p);
+	gmm::add(r, gmm::scaled(p, beta), p);      
+      }
+      gmm::mult(M, p, phat);
+      gmm::mult(A, phat, v);	
+      alpha = rho_1 / gmm::vect_sp(v, rtilde);
+      gmm::add(r, gmm::scaled(v, -alpha), s);
+      
+      if (iter.finished_vect(s)) 
+	{ gmm::add(gmm::scaled(phat, alpha), x); break; }
+      
+      gmm::mult(M, s, shat);	
+      gmm::mult(A, shat, t);
+      omega = gmm::vect_sp(t, s) / gmm::vect_norm2_sqr(t);
+      
+      gmm::add(gmm::scaled(phat, alpha), x); 
+      gmm::add(gmm::scaled(shat, omega), x);
+      gmm::add(s, gmm::scaled(t, -omega), r); 
+      norm_r = gmm::vect_norm2(r);
+      rho_2 = rho_1;
+      
+      ++iter;
+    }
+  }
+  
+  template <typename Matrix, typename Vector, typename VectorB,
+	    typename Preconditioner>
+  void bicgstab(const Matrix& A, const Vector& x, const VectorB& b,
+	       const Preconditioner& M, iteration &iter)
+  { bicgstab(A, linalg_const_cast(x), b, M, iter); }
+  
+}
+
+
+#endif //  GMM_SOLVER_BICGSTAB_H__
diff --git a/Contrib/gmm/gmm_solver_cg.h b/Contrib/gmm/gmm_solver_cg.h
new file mode 100755
index 0000000..a6d29ae
--- /dev/null
+++ b/Contrib/gmm/gmm_solver_cg.h
@@ -0,0 +1,212 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+// This file is a modified version of cg.h from ITL.
+// See http://osl.iu.edu/research/itl/
+// Following the corresponding Copyright notice.
+//===========================================================================
+//
+// Copyright (c) 1997-2001, The Trustees of Indiana University.
+// All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//    * Redistributions of source code must retain the above copyright
+//      notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above copyright
+//      notice, this list of conditions and the following disclaimer in the
+//      documentation and/or other materials provided with the distribution.
+//    * Neither the name of the University of California, Berkeley nor the
+//      names of its contributors may be used to endorse or promote products
+//      derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE  IS  PROVIDED  BY  THE TRUSTEES  OF  INDIANA UNIVERSITY  AND
+// CONTRIBUTORS  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,  INCLUDING,
+// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS
+// FOR  A PARTICULAR PURPOSE ARE DISCLAIMED. IN  NO  EVENT SHALL THE TRUSTEES
+// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY,  OR CONSEQUENTIAL DAMAGES (INCLUDING,  BUT
+// NOT  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA,  OR PROFITS;  OR BUSINESS  INTERRUPTION)  HOWEVER  CAUSED AND ON ANY
+// THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT  LIABILITY, OR TORT
+// (INCLUDING  NEGLIGENCE  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+// THIS  SOFTWARE,  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//===========================================================================
+
+/**@file gmm_solver_cg.h
+   @author  Andrew Lumsdaine <lums at osl.iu.edu>
+   @author  Lie-Quan Lee <llee at osl.iu.edu>
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 13, 2002.
+   @brief Conjugate gradient iterative solver. 
+*/
+#ifndef GMM_SOLVER_CG_H__
+#define GMM_SOLVER_CG_H__
+
+#include "gmm_kernel.h"
+#include "gmm_iter.h"
+
+namespace gmm {
+
+  /* ******************************************************************** */
+  /*		conjugate gradient                           		  */
+  /* (preconditionned, with parametrable additional scalar product)       */
+  /* ******************************************************************** */
+
+  template <typename Matrix, typename Matps, typename Precond, 
+            typename Vector1, typename Vector2>
+  void cg(const Matrix& A, Vector1& x, const Vector2& b, const Matps& PS,
+	  const Precond &P, iteration &iter) {
+
+    typedef typename temporary_dense_vector<Vector1>::vector_type temp_vector;
+    typedef typename linalg_traits<Vector1>::value_type T;
+
+    T rho, rho_1(0), a;
+    temp_vector p(vect_size(x)), q(vect_size(x)), r(vect_size(x)),
+      z(vect_size(x));
+    iter.set_rhsnorm(gmm::sqrt(gmm::abs(vect_hp(PS, b, b))));
+
+    if (iter.get_rhsnorm() == 0.0)
+      clear(x);
+    else {
+      mult(A, scaled(x, T(-1)), b, r);
+      mult(P, r, z);
+      rho = vect_hp(PS, z, r);
+      copy(z, p);
+
+// #ifdef GMM_USES_MPI
+//       double t_ref, t_prec = MPI_Wtime(), t_tot = 0;
+//       static double tmult_tot = 0.0;
+// #endif
+      while (!iter.finished_vect(r)) {
+
+	if (!iter.first()) { 
+	  mult(P, r, z);
+	  rho = vect_hp(PS, z, r);
+	  add(z, scaled(p, rho / rho_1), p);
+	}
+// #ifdef GMM_USES_MPI
+// t_ref = MPI_Wtime();
+//     cout << "mult CG " << endl;
+// #endif	
+	mult(A, p, q);
+// #ifdef GMM_USES_MPI
+//     tmult_tot += MPI_Wtime()-t_ref;
+//     cout << "tmult_tot CG = " << tmult_tot << endl;
+// #endif
+	a = rho / vect_hp(PS, q, p);	
+	add(scaled(p, a), x);
+	add(scaled(q, -a), r);
+	rho_1 = rho;
+
+// #ifdef GMM_USES_MPI
+// 	t_tot = MPI_Wtime() - t_prec;
+// 	cout << "temps CG : " << t_tot << endl; 
+// #endif
+	++iter;
+      }
+    }
+  }
+
+  template <typename Matrix, typename Matps, typename Precond, 
+            typename Vector1, typename Vector2>
+  void cg(const Matrix& A, Vector1& x, const Vector2& b, const Matps& PS,
+	  const gmm::identity_matrix &, iteration &iter) {
+
+    typedef typename temporary_dense_vector<Vector1>::vector_type temp_vector;
+    typedef typename linalg_traits<Vector1>::value_type T;
+
+    T rho, rho_1(0), a;
+    temp_vector p(vect_size(x)), q(vect_size(x)), r(vect_size(x));
+    iter.set_rhsnorm(gmm::sqrt(gmm::abs(vect_hp(PS, b, b))));
+
+    if (iter.get_rhsnorm() == 0.0)
+      clear(x);
+    else {
+      mult(A, scaled(x, T(-1)), b, r);
+      rho = vect_hp(PS, r, r);
+      copy(r, p);
+
+// #ifdef GMM_USES_MPI
+//       double t_ref, t_prec = MPI_Wtime(), t_tot = 0;
+//       static double tmult_tot = 0.0;
+// #endif
+      while (!iter.finished_vect(r)) {
+
+	if (!iter.first()) { 
+	  rho = vect_hp(PS, r, r);
+	  add(r, scaled(p, rho / rho_1), p);
+	}
+// #ifdef GMM_USES_MPI
+// t_ref = MPI_Wtime();
+//     cout << "mult CG " << endl;
+// #endif	
+	mult(A, p, q);
+// #ifdef GMM_USES_MPI
+//     tmult_tot += MPI_Wtime()-t_ref;
+//     cout << "tmult_tot CG = " << tmult_tot << endl;
+// #endif
+	a = rho / vect_hp(PS, q, p);	
+	add(scaled(p, a), x);
+	add(scaled(q, -a), r);
+	rho_1 = rho;
+
+// #ifdef GMM_USES_MPI
+// 	t_tot = MPI_Wtime() - t_prec;
+// 	cout << "temps CG : " << t_tot << endl; 
+// #endif
+	++iter;
+      }
+    }
+  }
+
+  template <typename Matrix, typename Matps, typename Precond, 
+            typename Vector1, typename Vector2> inline 
+  void cg(const Matrix& A, const Vector1& x, const Vector2& b, const Matps& PS,
+	 const Precond &P, iteration &iter)
+  { cg(A, linalg_const_cast(x), b, PS, P, iter); }
+
+  template <typename Matrix, typename Precond, 
+            typename Vector1, typename Vector2> inline
+  void cg(const Matrix& A, Vector1& x, const Vector2& b,
+	 const Precond &P, iteration &iter)
+  { cg(A, x , b, identity_matrix(), P, iter); }
+
+  template <typename Matrix, typename Precond, 
+            typename Vector1, typename Vector2> inline
+  void cg(const Matrix& A, const Vector1& x, const Vector2& b,
+	 const Precond &P, iteration &iter)
+  { cg(A, x , b , identity_matrix(), P , iter); }
+  
+}
+
+
+#endif //  GMM_SOLVER_CG_H__
diff --git a/Contrib/gmm/gmm_solver_constrained_cg.h b/Contrib/gmm/gmm_solver_constrained_cg.h
new file mode 100755
index 0000000..c7442c8
--- /dev/null
+++ b/Contrib/gmm/gmm_solver_constrained_cg.h
@@ -0,0 +1,166 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_solver_constrained_cg.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 13, 2002.
+   @brief Constrained conjugate gradient. */
+//  preconditionning does not work
+
+#ifndef GMM_SOLVER_CCG_H__
+#define GMM_SOLVER_CCG_H__
+
+#include "gmm_kernel.h"
+#include "gmm_iter.h"
+
+namespace gmm {
+
+  template <typename CMatrix, typename CINVMatrix, typename Matps,
+	    typename VectorX>
+  void pseudo_inverse(const CMatrix &C, CINVMatrix &CINV,
+		      const Matps& /* PS */, VectorX&) {
+    // compute the pseudo inverse of the non-square matrix C such
+    // CINV = inv(C * trans(C)) * C.
+    // based on a conjugate gradient method.
+    
+    // optimisable : copie de la ligne, precalcul de C * trans(C).
+    
+    typedef VectorX TmpVec;
+    typedef size_t size_type;
+    typedef typename linalg_traits<VectorX>::value_type value_type;
+    
+    size_type nr = mat_nrows(C), nc = mat_ncols(C);
+    
+    TmpVec d(nr), e(nr), l(nc), p(nr), q(nr), r(nr);
+    value_type rho, rho_1, alpha;
+    clear(d);
+    clear(CINV);
+    
+    for (size_type i = 0; i < nr; ++i) {
+      d[i] = 1.0; rho = 1.0;
+      clear(e);
+      copy(d, r);
+      copy(d, p);
+      
+      while (rho >= 1E-38) { /* conjugate gradient to compute e             */
+	                     /* which is the i nd row of inv(C * trans(C))  */
+	mult(gmm::transposed(C), p, l);
+	mult(C, l, q);	  
+	alpha = rho / vect_sp(p, q);
+	add(scaled(p, alpha), e);  
+	add(scaled(q, -alpha), r); 
+	rho_1 = rho;
+	rho = vect_sp(r, r);
+	add(r, scaled(p, rho / rho_1), p);
+      }
+      
+      mult(transposed(C), e, l); /* l is the i nd row of CINV     */
+      // cout << "l = " << l << endl;
+      clean(l, 1E-15);
+      copy(l, mat_row(CINV, i));
+      
+      d[i] = 0.0;
+    }
+  }
+  
+  /** Compute the minimum of @f$ 1/2((Ax).x) - bx @f$ under the contraint @f$ Cx <= f @f$ */
+  template < typename Matrix,  typename CMatrix, typename Matps,
+	     typename VectorX, typename VectorB, typename VectorF,
+	     typename Preconditioner >
+  void constrained_cg(const Matrix& A, const CMatrix& C, VectorX& x,
+		      const VectorB& b, const VectorF& f,const Matps& PS,
+		      const Preconditioner& M, iteration &iter) {
+    typedef typename temporary_dense_vector<VectorX>::vector_type TmpVec;
+    typedef typename temporary_vector<CMatrix>::vector_type TmpCVec;
+    typedef row_matrix<TmpCVec> TmpCmat;
+    
+    typedef size_t size_type;
+    typedef typename linalg_traits<VectorX>::value_type value_type;
+    value_type rho = 1.0, rho_1, lambda, gamma;
+    TmpVec p(vect_size(x)), q(vect_size(x)), q2(vect_size(x)),
+      r(vect_size(x)), old_z(vect_size(x)), z(vect_size(x)),
+      memox(vect_size(x));
+    std::vector<bool> satured(mat_nrows(C));
+    clear(p);
+    iter.set_rhsnorm(sqrt(vect_sp(PS, b, b)));
+    if (iter.get_rhsnorm() == 0.0) iter.set_rhsnorm(1.0);
+   
+    TmpCmat CINV(mat_nrows(C), mat_ncols(C));
+    pseudo_inverse(C, CINV, PS, x);
+    
+    while(true) {
+      // computation of residu
+      copy(z, old_z);
+      copy(x, memox);
+      mult(A, scaled(x, -1.0), b, r);
+      mult(M, r, z); // preconditionner not coherent
+      bool transition = false;
+      for (size_type i = 0; i < mat_nrows(C); ++i) {
+	value_type al = vect_sp(mat_row(C, i), x) - f[i];
+	if (al >= -1.0E-15) {
+	  if (!satured[i]) { satured[i] = true; transition = true; }
+	  value_type bb = vect_sp(mat_row(CINV, i), z);
+	  if (bb > 0.0) add(scaled(mat_row(C, i), -bb), z);
+	}
+	else
+	  satured[i] = false;
+      }
+    
+      // descent direction
+      rho_1 = rho; rho = vect_sp(PS, r, z); // ...
+      
+      if (iter.finished(rho)) break;
+      
+      if (iter.get_noisy() > 0 && transition) std::cout << "transition\n";
+      if (transition || iter.first()) gamma = 0.0;
+      else gamma = std::max(0.0, (rho - vect_sp(PS, old_z, z) ) / rho_1);
+      // std::cout << "gamma = " << gamma << endl;
+      // itl::add(r, itl::scaled(p, gamma), p);
+      add(z, scaled(p, gamma), p); // ...
+      
+      ++iter;
+      // one dimensionnal optimization
+      mult(A, p, q);
+      lambda = rho / vect_sp(PS, q, p);
+      for (size_type i = 0; i < mat_nrows(C); ++i)
+	if (!satured[i]) {
+	  value_type bb = vect_sp(mat_row(C, i), p) - f[i];
+	  if (bb > 0.0)
+	    lambda = std::min(lambda, (f[i]-vect_sp(mat_row(C, i), x)) / bb);
+	}
+      add(x, scaled(p, lambda), x);
+      add(memox, scaled(x, -1.0), memox);
+      
+    }
+  }
+  
+}
+
+#endif //  GMM_SOLVER_CCG_H__
diff --git a/Contrib/gmm/gmm_solver_gmres.h b/Contrib/gmm/gmm_solver_gmres.h
new file mode 100755
index 0000000..fde56e4
--- /dev/null
+++ b/Contrib/gmm/gmm_solver_gmres.h
@@ -0,0 +1,173 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 1997-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+// This file is a modified version of gmres.h from ITL.
+// See http://osl.iu.edu/research/itl/
+// Following the corresponding Copyright notice.
+//===========================================================================
+//
+// Copyright (c) 1997-2001, The Trustees of Indiana University.
+// All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//    * Redistributions of source code must retain the above copyright
+//      notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above copyright
+//      notice, this list of conditions and the following disclaimer in the
+//      documentation and/or other materials provided with the distribution.
+//    * Neither the name of the University of California, Berkeley nor the
+//      names of its contributors may be used to endorse or promote products
+//      derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE  IS  PROVIDED  BY  THE TRUSTEES  OF  INDIANA UNIVERSITY  AND
+// CONTRIBUTORS  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,  INCLUDING,
+// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS
+// FOR  A PARTICULAR PURPOSE ARE DISCLAIMED. IN  NO  EVENT SHALL THE TRUSTEES
+// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY,  OR CONSEQUENTIAL DAMAGES (INCLUDING,  BUT
+// NOT  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA,  OR PROFITS;  OR BUSINESS  INTERRUPTION)  HOWEVER  CAUSED AND ON ANY
+// THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT  LIABILITY, OR TORT
+// (INCLUDING  NEGLIGENCE  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+// THIS  SOFTWARE,  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//===========================================================================
+
+/**@file gmm_solver_gmres.h
+   @author  Andrew Lumsdaine <lums at osl.iu.edu>
+   @author  Lie-Quan Lee     <llee at osl.iu.edu>
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 13, 2002.
+   @brief GMRES (Generalized Minimum Residual) iterative solver.
+*/
+#ifndef GMM_KRYLOV_GMRES_H
+#define GMM_KRYLOV_GMRES_H
+
+#include "gmm_kernel.h"
+#include "gmm_iter.h"
+#include "gmm_modified_gram_schmidt.h"
+
+namespace gmm {
+
+  /** Generalized Minimum Residual
+   
+      This solve the unsymmetric linear system Ax = b using restarted GMRES.
+      
+      See: Y. Saad and M. Schulter. GMRES: A generalized minimum residual
+      algorithm for solving nonsysmmetric linear systems, SIAM
+      J. Sci. Statist. Comp.  7(1986), pp, 856-869
+  */
+  template <typename Mat, typename Vec, typename VecB, typename Precond,
+	    typename Basis >
+  void gmres(const Mat &A, Vec &x, const VecB &b, const Precond &M,
+	     int restart, iteration &outer, Basis& KS) {
+
+    typedef typename linalg_traits<Vec>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+
+    std::vector<T> w(vect_size(x)), r(vect_size(x)), u(vect_size(x));
+    std::vector<T> c_rot(restart+1), s_rot(restart+1), s(restart+1);
+    gmm::dense_matrix<T> H(restart+1, restart);
+#ifdef GMM_USES_MPI
+      double t_ref, t_prec = MPI_Wtime(), t_tot = 0;
+      static double tmult_tot = 0.0;
+t_ref = MPI_Wtime();
+    cout << "GMRES " << endl;
+#endif
+    mult(M,b,r);
+    outer.set_rhsnorm(gmm::vect_norm2(r));
+    if (outer.get_rhsnorm() == 0.0) { clear(x); return; }
+    
+    mult(A, scaled(x, -1), b, w);
+    mult(M, w, r);
+    R beta = gmm::vect_norm2(r), beta_old = beta;
+    int blocked = 0;
+
+    iteration inner = outer;
+    inner.reduce_noisy();
+    inner.set_maxiter(restart);
+    inner.set_name("GMRes inner");
+
+    while (! outer.finished(beta)) {
+      
+      gmm::copy(gmm::scaled(r, R(1)/beta), KS[0]);
+      gmm::clear(s);
+      s[0] = beta;
+      
+      size_type i = 0; inner.init();
+      
+      do {
+	mult(A, KS[i], u);
+	mult(M, u, KS[i+1]);
+	orthogonalize(KS, mat_col(H, i), i);
+	R a = gmm::vect_norm2(KS[i+1]);
+	H(i+1, i) = T(a);
+	gmm::scale(KS[i+1], T(1) / a);
+	for (size_type k = 0; k < i; ++k)
+	  Apply_Givens_rotation_left(H(k,i), H(k+1,i), c_rot[k], s_rot[k]);
+	
+	Givens_rotation(H(i,i), H(i+1,i), c_rot[i], s_rot[i]);
+	Apply_Givens_rotation_left(H(i,i), H(i+1,i), c_rot[i], s_rot[i]);
+	Apply_Givens_rotation_left(s[i], s[i+1], c_rot[i], s_rot[i]);
+	
+	++inner, ++outer, ++i;
+      } while (! inner.finished(gmm::abs(s[i])));
+
+      upper_tri_solve(H, s, i, false);
+      combine(KS, s, x, i);
+      mult(A, gmm::scaled(x, -1), b, w);
+      mult(M, w, r);
+      beta_old = std::min(beta, beta_old); beta = gmm::vect_norm2(r);
+      if (int(inner.get_iteration()) < restart -1 || beta_old <= beta)
+	++blocked; else blocked = 0;
+      if (blocked > 10) {
+	if (outer.get_noisy()) cout << "Gmres is blocked, exiting\n";
+	break;
+      }
+#ifdef GMM_USES_MPI
+	t_tot = MPI_Wtime() - t_ref;
+	cout << "temps GMRES : " << t_tot << endl; 
+#endif
+    }
+  }
+
+
+  template <typename Mat, typename Vec, typename VecB, typename Precond >
+  void gmres(const Mat &A, Vec &x, const VecB &b,
+	     const Precond &M, int restart, iteration& outer) {
+    typedef typename linalg_traits<Vec>::value_type T;
+    modified_gram_schmidt<T> orth(restart, vect_size(x));
+    gmres(A, x, b, M, restart, outer, orth); 
+  }
+
+}
+
+#endif
diff --git a/Contrib/gmm/gmm_solver_idgmres.h b/Contrib/gmm/gmm_solver_idgmres.h
new file mode 100755
index 0000000..2a472ce
--- /dev/null
+++ b/Contrib/gmm/gmm_solver_idgmres.h
@@ -0,0 +1,804 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_solver_idgmres.h
+   @author  Caroline Lecalvez <Caroline.Lecalvez at gmm.insa-tlse.fr>
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 6, 2003.
+   @brief Implicitly restarted and deflated Generalized Minimum Residual.
+*/
+#ifndef GMM_IDGMRES_H
+#define GMM_IDGMRES_H
+
+#include "gmm_kernel.h"
+#include "gmm_iter.h"
+#include "gmm_dense_sylvester.h"
+
+namespace gmm {
+
+  template <typename T> compare_vp {
+    bool operator()(const std::pair<T, size_type> &a,
+		    const std::pair<T, size_type> &b) const
+    { return (gmm::abs(a.first) > gmm::abs(b.first)); }
+  }
+
+  struct idgmres_state {
+    size_type m, tb_deb, tb_def, p, k, nb_want, nb_unwant;
+    size_type nb_nolong, tb_deftot, tb_defwant, conv, nb_un, fin;
+    bool ok;
+
+    idgmres_state(size_type mm, size_type pp, size_type kk)
+      : m(mm), tb_deb(1), tb_def(0), p(pp), k(kk), nb_want(0),
+	nb_unwant(0), nb_nolong(0), tb_deftot(0), tb_defwant(0),
+	conv(0), nb_un(0), fin(0), ok(false); {}
+  }
+
+    idgmres_state(size_type mm, size_type pp, size_type kk)
+      : m(mm), tb_deb(1), tb_def(0), p(pp), k(kk), nb_want(0),
+	nb_unwant(0), nb_nolong(0), tb_deftot(0), tb_defwant(0),
+	conv(0), nb_un(0), fin(0), ok(false); {}
+  
+
+  template <typename CONT, typename IND>
+  apply_permutation(CONT &cont, const IND &ind) {
+    size_type m = ind.end() - ind.begin();
+    std::vector<bool> sorted(m, false);
+    
+    for (size_type l = 0; l < m; ++l)
+      if (!sorted[l] && ind[l] != l) {
+
+	typeid(cont[0]) aux = cont[l];
+	k = ind[l];
+	cont[l] = cont[k];
+	sorted[l] = true;
+	
+	for(k2 = ind[k]; k2 != l; k2 = ind[k]) {
+	  cont[k] = cont[k2];
+	  sorted[k] = true;
+	  k = k2;
+	}
+	cont[k] = aux;
+      }
+  }
+
+
+  /** Implicitly restarted and deflated Generalized Minimum Residual
+
+      See: C. Le Calvez, B. Molina, Implicitly restarted and deflated
+      FOM and GMRES, numerical applied mathematics,
+      (30) 2-3 (1999) pp191-212.
+      
+      @param A Real or complex unsymmetric matrix.
+      @param x initial guess vector and final result.
+      @param b right hand side
+      @param M preconditionner
+      @param m size of the subspace between two restarts
+      @param p number of converged ritz values seeked
+      @param k size of the remaining Krylov subspace when the p ritz values
+      have not yet converged 0 <= p <= k < m.
+      @param tol_vp : tolerance on the ritz values.
+      @param outer
+      @param KS
+  */
+  template < typename Mat, typename Vec, typename VecB, typename Precond,
+	     typename Basis >
+  void idgmres(const Mat &A, Vec &x, const VecB &b, const Precond &M,
+	     size_type m, size_type p, size_type k, double tol_vp,
+	     iteration &outer, Basis& KS) {
+
+    typedef typename linalg_traits<Mat>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+    
+    R a, beta;
+    idgmres_state st(m, p, k);
+
+    std::vector<T> w(vect_size(x)), r(vect_size(x)), u(vect_size(x));
+    std::vector<T> c_rot(m+1), s_rot(m+1), s(m+1);
+    std::vector<T> y(m+1), ztest(m+1), gam(m+1);
+    std::vector<T> gamma(m+1);
+    gmm::dense_matrix<T> H(m+1, m), Hess(m+1, m),
+      Hobl(m+1, m), W(vect_size(x), m+1);
+
+    gmm::clear(H);
+
+    outer.set_rhsnorm(gmm::vect_norm2(b));
+    if (outer.get_rhsnorm() == 0.0) { clear(x); return; }
+    
+    mult(A, scaled(x, -1.0), b, w);
+    mult(M, w, r);
+    beta = gmm::vect_norm2(r);
+
+    iteration inner = outer;
+    inner.reduce_noisy();
+    inner.set_maxiter(m);
+    inner.set_name("GMRes inner iter");
+    
+    while (! outer.finished(beta)) {
+      
+      gmm::copy(gmm::scaled(r, 1.0/beta), KS[0]);
+      gmm::clear(s);
+      s[0] = beta;
+      gmm::copy(s, gamma);
+
+      inner.set_maxiter(m - st.tb_deb + 1);
+      size_type i = st.tb_deb - 1; inner.init();
+      
+      do {
+	mult(A, KS[i], u);
+	mult(M, u, KS[i+1]);
+	orthogonalize_with_refinment(KS, mat_col(H, i), i);
+	H(i+1, i) = a = gmm::vect_norm2(KS[i+1]);
+	gmm::scale(KS[i+1], R(1) / a);
+
+	gmm::copy(mat_col(H, i), mat_col(Hess, i));
+	gmm::copy(mat_col(H, i), mat_col(Hobl, i));
+	
+
+	for (size_type l = 0; l < i; ++l)
+	  Apply_Givens_rotation_left(H(l,i), H(l+1,i), c_rot[l], s_rot[l]);
+	
+	Givens_rotation(H(i,i), H(i+1,i), c_rot[i], s_rot[i]);
+	Apply_Givens_rotation_left(H(i,i), H(i+1,i), c_rot[i], s_rot[i]);
+	H(i+1, i) = T(0); 
+	Apply_Givens_rotation_left(s[i], s[i+1], c_rot[i], s_rot[i]);
+	
+	++inner, ++outer, ++i;
+      } while (! inner.finished(gmm::abs(s[i])));
+
+      if (inner.converged()) {
+	gmm::copy(s, y);
+	upper_tri_solve(H, y, i, false);
+	combine(KS, y, x, i);
+	mult(A, gmm::scaled(x, T(-1)), b, w);
+	mult(M, w, r);
+	beta = gmm::vect_norm2(r); // + verif sur beta ... à faire
+	break;
+      }
+
+      gmm::clear(gam); gam[m] = s[i];
+      for (size_type l = m; l > 0; --l)
+	Apply_Givens_rotation_left(gam[l-1], gam[l], gmm::conj(c_rot[l-1]),
+				   -s_rot[l-1]);
+
+      mult(KS.mat(), gam, r);
+      beta = gmm::vect_norm2(r);
+      
+      mult(Hess, scaled(y, T(-1)), gamma, ztest);
+      // En fait, d'après Caroline qui s'y connait ztest et gam devrait
+      // être confondus
+      // Quand on aura vérifié que ça marche, il faudra utiliser gam à la 
+      // place de ztest.
+      if (st.tb_def < p) {
+        T nss = H(m,m-1) / ztest[m];
+	nss /= gmm::abs(nss); // ns à calculer plus tard aussi
+	gmm::copy(KS.mat(), W); gmm::copy(scaled(r, nss /beta), mat_col(W, m));
+	
+	// Computation of the oblique matrix
+	sub_interval SUBI(0, m);
+	add(scaled(sub_vector(ztest, SUBI), -Hobl(m, m-1) / ztest[m]),
+	    sub_vector(mat_col(Hobl, m-1), SUBI));
+	Hobl(m, m-1) *= nss * beta / ztest[m]; 
+
+	/* **************************************************************** */
+	/*  Locking                                                         */
+	/* **************************************************************** */
+
+	// Computation of the Ritz eigenpairs.
+	std::vector<std::complex<R> > eval(m);
+	dense_matrix<T> YB(m-st.tb_def, m-st.tb_def);
+	std::vector<char> pure(m-st.tb_def, 0);
+	gmm::clear(YB);
+
+	select_eval(Hobl, eval, YB, pure, st);
+
+	if (st.conv != 0) {
+	  // DEFLATION using the QR Factorization of YB
+	  
+	  T alpha = Lock(W, Hobl,
+			 sub_matrix(YB,  sub_interval(0, m-st.tb_def)),
+			 sub_interval(st.tb_def, m-st.tb_def), 
+			 (st.tb_defwant < p)); 
+	  // ns *= alpha; // à calculer plus tard ??
+	  //  V(:,m+1) = alpha*V(:, m+1); ça devait servir à qlq chose ...
+
+
+	  //       Clean the portions below the diagonal corresponding
+	  //       to the lock Schur vectors
+
+	  for (size_type j = st.tb_def; j < st.tb_deftot; ++j) {
+	    if ( pure[j-st.tb_def] == 0)
+	      gmm::clear(sub_vector(mat_col(Hobl,j), sub_interval(j+1,m-j)));
+	    else if (pure[j-st.tb_def] == 1) {
+	      gmm::clear(sub_matrix(Hobl, sub_interval(j+2,m-j-1),
+				    sub_interval(j, 2))); 
+	      ++j;
+	    }
+	    else GMM_ASSERT3(false, "internal error");
+	  }
+	  
+	  if (!st.ok) {
+
+	    // attention si m = 0;
+	    size_type mm = std::min(k+st.nb_unwant+st.nb_nolong, m-1);
+
+	    if (eval_sort[m-mm-1].second != R(0)
+		&& eval_sort[m-mm-1].second == -eval_sort[m-mm].second) ++mm;
+
+	    std::vector<complex<R> > shifts(m-mm);
+	    for (size_type i = 0; i < m-mm; ++i)
+	      shifts[i] = eval_sort[i].second;
+
+	    apply_shift_to_Arnoldi_factorization(W, Hobl, shifts, mm,
+						 m-mm, true);
+
+	    st.fin = mm;
+	  }
+	  else
+	    st.fin = st.tb_deftot;
+
+
+	  /* ************************************************************** */
+	  /*  Purge                                                         */
+	  /* ************************************************************** */
+
+	  if (st.nb_nolong + st.nb_unwant > 0) {
+
+	    std::vector<std::complex<R> > eval(m);
+	    dense_matrix<T> YB(st.fin, st.tb_deftot);
+	    std::vector<char> pure(st.tb_deftot, 0);
+	    gmm::clear(YB);
+	    st.nb_un = st.nb_nolong + st.nb_unwant;
+	    
+	    select_eval_for_purging(Hobl, eval, YB, pure, st);
+	    
+	    T alpha = Lock(W, Hobl, YB, sub_interval(0, st.fin), ok);
+
+	    //       Clean the portions below the diagonal corresponding
+	    //       to the unwanted lock Schur vectors
+	    
+	    for (size_type j = 0; j < st.tb_deftot; ++j) {
+	      if ( pure[j] == 0)
+		gmm::clear(sub_vector(mat_col(Hobl,j), sub_interval(j+1,m-j)));
+	      else if (pure[j] == 1) {
+		gmm::clear(sub_matrix(Hobl, sub_interval(j+2,m-j-1),
+				      sub_interval(j, 2))); 
+		++j;
+	      }
+	      else GMM_ASSERT3(false, "internal error");
+	    }
+
+	    gmm::dense_matrix<T> z(st.nb_un, st.fin - st.nb_un);
+	    sub_interval SUBI(0, st.nb_un), SUBJ(st.nb_un, st.fin - st.nb_un);
+	    sylvester(sub_matrix(Hobl, SUBI),
+		      sub_matrix(Hobl, SUBJ),
+		      sub_matrix(gmm::scaled(Hobl, -T(1)), SUBI, SUBJ), z);
+	    
+	  }
+
+	}
+	
+      }
+    }
+  }
+  
+
+  template < typename Mat, typename Vec, typename VecB, typename Precond >
+    void idgmres(const Mat &A, Vec &x, const VecB &b,
+		 const Precond &M, size_type m, iteration& outer) {
+    typedef typename linalg_traits<Mat>::value_type T;
+    modified_gram_schmidt<T> orth(m, vect_size(x));
+    gmres(A, x, b, M, m, outer, orth); 
+  }
+
+
+  // Lock stage of an implicit restarted Arnoldi process.
+  // 1- QR factorization of YB through Householder matrices
+  //    Q(Rl) = YB
+  //     (0 )
+  // 2- Update of the Arnoldi factorization.
+  //    H <- Q*HQ,  W <- WQ
+  // 3- Restore the Hessemberg form of H.
+
+  template <typename T, typename MATYB>
+    void Lock(gmm::dense_matrix<T> &W, gmm::dense_matrix<T> &H,
+	      const MATYB &YB, const sub_interval SUB,
+	      bool restore, T &ns) {
+
+    size_type n = mat_nrows(W), m = mat_ncols(W) - 1;
+    size_type ncols = mat_ncols(YB), nrows = mat_nrows(YB);
+    size_type begin = min(SUB); end = max(SUB) - 1;
+    sub_interval SUBR(0, nrows), SUBC(0, ncols);
+    T alpha(1);
+
+    GMM_ASSERT2(((end-begin) == ncols) && (m == mat_nrows(H)) 
+		&& (m+1 == mat_ncols(H)), "dimensions mismatch");
+    
+    // DEFLATION using the QR Factorization of YB
+	  
+    dense_matrix<T> QR(n_rows, n_rows);
+    gmmm::copy(YB, sub_matrix(QR, SUBR, SUBC));
+    gmm::clear(submatrix(QR, SUBR, sub_interval(ncols, nrows-ncols)));
+    qr_factor(QR); 
+
+
+    apply_house_left(QR, sub_matrix(H, SUB));
+    apply_house_right(QR, sub_matrix(H, SUBR, SUB));
+    apply_house_right(QR, sub_matrix(W, sub_interval(0, n), SUB));
+    
+    //       Restore to the initial block hessenberg form
+    
+    if (restore) {
+      
+      // verifier quand m = 0 ...
+      gmm::dense_matrix tab_p(end - st.tb_deftot, end - st.tb_deftot);
+      gmm::copy(identity_matrix(), tab_p);
+      
+      for (size_type j = end-1; j >= st.tb_deftot+2; --j) {
+	
+	size_type jm = j-1;
+	std::vector<T> v(jm - st.tb_deftot);
+	sub_interval SUBtot(st.tb_deftot, jm - st.tb_deftot);
+	sub_interval SUBtot2(st.tb_deftot, end - st.tb_deftot);
+	gmm::copy(sub_vector(mat_row(H, j), SUBtot), v);
+	house_vector_last(v);
+	w.resize(end);
+	col_house_update(sub_matrix(H, SUBI, SUBtot), v, w);
+	w.resize(end - st.tb_deftot);
+	row_house_update(sub_matrix(H, SUBtot, SUBtot2), v, w);
+	gmm::clear(sub_vector(mat_row(H, j),
+			      sub_interval(st.tb_deftot, j-1-st.tb_deftot)));
+	w.resize(end - st.tb_deftot);
+	col_house_update(sub_matrix(tab_p, sub_interval(0, end-st.tb_deftot),
+				    sub_interval(0, jm-st.tb_deftot)), v, w);
+	w.resize(n);
+	col_house_update(sub_matrix(W, sub_interval(0, n), SUBtot), v, w);
+      }
+      
+      //       restore positive subdiagonal elements
+      
+      std::vector<T> d(fin-st.tb_deftot); d[0] = T(1);
+      
+      // We compute d[i+1] in order 
+      // (d[i+1] * H(st.tb_deftot+i+1,st.tb_deftoti)) / d[i] 
+      // be equal to |H(st.tb_deftot+i+1,st.tb_deftot+i))|.
+      for (size_type j = 0; j+1 < end-st.tb_deftot; ++j) {
+	T e = H(st.tb_deftot+j, st.tb_deftot+j-1);
+	d[j+1] = (e == T(0)) ? T(1) :  d[j] * gmm::abs(e) / e;
+	scale(sub_vector(mat_row(H, st.tb_deftot+j+1),
+			 sub_interval(st.tb_deftot, m-st.tb_deftot)), d[j+1]);
+	scale(mat_col(H, st.tb_deftot+j+1), T(1) / d[j+1]);
+	scale(mat_col(W, st.tb_deftot+j+1), T(1) / d[j+1]);
+      }
+
+      alpha = tab_p(end-st.tb_deftot-1, end-st.tb_deftot-1) / d[end-st.tb_deftot-1];
+      alpha /= gmm::abs(alpha);
+      scale(mat_col(W, m), alpha);
+	    
+    }
+	 
+    return alpha;
+  }
+
+
+
+
+
+
+
+
+  // Apply p implicit shifts to the Arnoldi factorization
+  // AV = VH+H(k+p+1,k+p) V(:,k+p+1) e_{k+p}*
+  // and produces the following new Arnoldi factorization
+  // A(VQ) = (VQ)(Q*HQ)+H(k+p+1,k+p) V(:,k+p+1) e_{k+p}* Q
+  // where only the first k columns are relevant.
+  //
+  // Dan Sorensen and Richard J. Radke, 11/95
+  template<typename T, typename C>
+    apply_shift_to_Arnoldi_factorization(dense_matrix<T> V, dense_matrix<T> H,
+					 std::vector<C> Lambda, size_type &k,
+					 size_type p, bool true_shift = false) {
+
+
+    size_type k1 = 0, num = 0, kend = k+p, kp1 = k + 1;
+    bool mark = false;
+    T c, s, x, y, z;
+
+    dense_matrix<T> q(1, kend);
+    gmm::clear(q); q(0,kend-1) = T(1);
+    std::vector<T> hv(3), w(std::max(kend, mat_nrows(V)));
+
+    for(size_type jj = 0; jj < p; ++jj) {
+      //     compute and apply a bulge chase sweep initiated by the
+      //     implicit shift held in w(jj)
+   
+      if (abs(Lambda[jj].real()) == 0.0) {
+	//       apply a real shift using 2 by 2 Givens rotations
+
+	for (size_type k1 = 0, k2 = 0; k2 != kend-1; k1 = k2+1) {
+	  k2 = k1;
+	  while (h(k2+1, k2) != T(0) && k2 < kend-1) ++k2;
+
+	  Givens_rotation(H(k1, k1) - Lambda[jj], H(k1+1, k1), c, s);
+	  
+	  for (i = k1; i <= k2; ++i) {
+            if (i > k1) Givens_rotation(H(i, i-1), H(i+1, i-1), c, s);
+            
+	    // Ne pas oublier de nettoyer H(i+1,i-1) (le mettre à zéro).
+	    // Vérifier qu'au final H(i+1,i) est bien un réel positif.
+
+            // apply rotation from left to rows of H
+	    row_rot(sub_matrix(H, sub_interval(i,2), sub_interval(i, kend-i)),
+		    c, s, 0, 0);
+	    
+	    // apply rotation from right to columns of H
+            size_type ip2 = std::min(i+2, kend);
+            col_rot(sub_matrix(H, sub_interval(0, ip2), sub_interval(i, 2))
+		    c, s, 0, 0);
+            
+            // apply rotation from right to columns of V
+	    col_rot(V, c, s, i, i+1);
+            
+            // accumulate e'  Q so residual can be updated k+p
+	    Apply_Givens_rotation_left(q(0,i), q(0,i+1), c, s);
+	    // peut être que nous utilisons G au lieu de G* et que
+	    // nous allons trop loin en k2.
+	  }
+	}
+	
+	num = num + 1;
+      }
+      else {
+      
+	// Apply a double complex shift using 3 by 3 Householder 
+	// transformations
+      
+	if (jj == p || mark)
+	  mark = false;     // skip application of conjugate shift
+	else {
+	  num = num + 2;    // mark that a complex conjugate
+	  mark = true;      // pair has been applied
+
+	  // Indices de fin de boucle à surveiller... de près !
+	  for (size_type k1 = 0, k3 = 0; k3 != kend-2; k1 = k3+1) {
+	    k3 = k1;
+	    while (h(k3+1, k3) != T(0) && k3 < kend-2) ++k3;
+	    size_type k2 = k1+1;
+
+
+            x = H(k1,k1) * H(k1,k1) + H(k1,k2) * H(k2,k1)
+	      - 2.0*Lambda[jj].real() * H(k1,k1) + gmm::abs_sqr(Lambda[jj]);
+	    y = H(k2,k1) * (H(k1,k1) + H(k2,k2) - 2.0*Lambda[jj].real());
+	    z = H(k2+1,k2) * H(k2,k1);
+
+	    for (size_type i = k1; i <= k3; ++i) {
+	      if (i > k1) {
+		x = H(i, i-1);
+		y = H(i+1, i-1);
+		z = H(i+2, i-1);
+		// Ne pas oublier de nettoyer H(i+1,i-1) et H(i+2,i-1) 
+		// (les mettre à zéro).
+	      }
+
+	      hv[0] = x; hv[1] = y; hv[2] = z;
+	      house_vector(v);
+
+	      // Vérifier qu'au final H(i+1,i) est bien un réel positif
+
+	      // apply transformation from left to rows of H
+	      w.resize(kend-i);
+	      row_house_update(sub_matrix(H, sub_interval(i, 2),
+					  sub_interval(i, kend-i)), v, w);
+               
+	      // apply transformation from right to columns of H
+               
+	      size_type ip3 = std::min(kend, i + 3);
+	      w.resize(ip3);
+              col_house_update(sub_matrix(H, sub_interval(0, ip3),
+					  sub_interval(i, 2)), v, w);
+               
+	      // apply transformation from right to columns of V
+	      
+	      w.resize(mat_nrows(V));
+	      col_house_update(sub_matrix(V, sub_interval(0, mat_nrows(V)),
+					  sub_interval(i, 2)), v, w);
+               
+	      // accumulate e' Q so residual can be updated  k+p
+
+	      w.resize(1);
+	      col_house_update(sub_matrix(q, sub_interval(0,1),
+					  sub_interval(i,2)), v, w);
+               
+	    }
+	  }
+         
+	  //           clean up step with Givens rotation
+
+	  i = kend-2;
+	  c = x; s = y;
+	  if (i > k1) Givens_rotation(H(i, i-1), H(i+1, i-1), c, s);
+            
+	  // Ne pas oublier de nettoyer H(i+1,i-1) (le mettre à zéro).
+	  // Vérifier qu'au final H(i+1,i) est bien un réel positif.
+
+	  // apply rotation from left to rows of H
+	  row_rot(sub_matrix(H, sub_interval(i,2), sub_interval(i, kend-i)),
+		    c, s, 0, 0);
+	    
+	  // apply rotation from right to columns of H
+	  size_type ip2 = std::min(i+2, kend);
+	  col_rot(sub_matrix(H, sub_interval(0, ip2), sub_interval(i, 2))
+		  c, s, 0, 0);
+            
+	  // apply rotation from right to columns of V
+	  col_rot(V, c, s, i, i+1);
+            
+	  // accumulate e'  Q so residual can be updated k+p
+	  Apply_Givens_rotation_left(q(0,i), q(0,i+1), c, s);
+
+	}
+      }
+    }
+
+    //  update residual and store in the k+1 -st column of v
+
+    k = kend - num;
+    scale(mat_col(V, kend), q(0, k));
+    
+    if (k < mat_nrows(H)) {
+      if (true_shift)
+	gmm::copy(mat_col(V, kend), mat_col(V, k));
+      else
+	   //   v(:,k+1) = v(:,kend+1) + v(:,k+1)*h(k+1,k);
+	   //   v(:,k+1) = v(:,kend+1) ;
+	gmm::add(scaled(mat_col(V, kend), H(kend, kend-1)), 
+		 scaled(mat_col(V, k), H(k, k-1)), mat_col(V, k));
+    }
+
+    H(k, k-1) = vect_norm2(mat_col(V, k));
+    scale(mat_col(V, kend), T(1) / H(k, k-1));
+  }
+
+
+
+  template<typename MAT, typename EVAL, typename PURE>
+  void select_eval(const MAT &Hobl, EVAL &eval, MAT &YB, PURE &pure,
+		   idgmres_state &st) {
+
+    typedef typename linalg_traits<MAT>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+    size_type m = st.m;
+
+    // Computation of the Ritz eigenpairs.
+    
+    col_matrix< std::vector<T> > evect(m-st.tb_def, m-st.tb_def);
+    // std::vector<std::complex<R> > eval(m);
+    std::vector<R> ritznew(m, T(-1));
+	
+    // dense_matrix<T> evect_lock(st.tb_def, st.tb_def);
+    
+    sub_interval SUB1(st.tb_def, m-st.tb_def);
+    implicit_qr_algorithm(sub_matrix(Hobl, SUB1),
+			  sub_vector(eval, SUB1), evect);
+    sub_interval SUB2(0, st.tb_def);
+    implicit_qr_algorithm(sub_matrix(Hobl, SUB2),
+			  sub_vector(eval, SUB2), /* evect_lock */);
+    
+    for (size_type l = st.tb_def; l < m; ++l)
+      ritznew[l] = gmm::abs(evect(m-st.tb_def-1, l-st.tb_def) * Hobl(m, m-1));
+    
+    std::vector< std::pair<T, size_type> > eval_sort(m);
+    for (size_type l = 0; l < m; ++l)
+      eval_sort[l] = std::pair<T, size_type>(eval[l], l);
+    std::sort(eval_sort.begin(), eval_sort.end(), compare_vp());
+    
+    std::vector<size_type> index(m);
+    for (size_type l = 0; l < m; ++l) index[l] = eval_sort[l].second;
+    
+    std::vector<bool> kept(m, false);
+    std::fill(kept.begin(), kept.begin()+st.tb_def, true);
+
+    apply_permutation(eval, index);
+    apply_permutation(evect, index);
+    apply_permutation(ritznew, index);
+    apply_permutation(kept, index);
+
+    //	Which are the eigenvalues that converged ?
+    //
+    //	nb_want is the number of eigenvalues of 
+    //	Hess(tb_def+1:n,tb_def+1:n) that converged and are WANTED
+    //
+    //	nb_unwant is the number of eigenvalues of 
+    //	Hess(tb_def+1:n,tb_def+1:n) that converged and are UNWANTED
+    //
+    //	nb_nolong is the number of eigenvalues of 
+    //	Hess(1:tb_def,1:tb_def) that are NO LONGER WANTED. 
+    //
+    //	tb_deftot is the number of the deflated eigenvalues
+    //	that is tb_def + nb_want + nb_unwant
+    //
+    //	tb_defwant is the number of the wanted deflated eigenvalues
+    //	that is tb_def + nb_want - nb_nolong
+    
+    st.nb_want = 0, st.nb_unwant = 0, st.nb_nolong = 0;
+    size_type j, ind;
+    
+    for (j = 0, ind = 0; j < m-p; ++j) {
+      if (ritznew[j] == R(-1)) {
+	if (std::imag(eval[j]) != R(0)) {
+	  st.nb_nolong += 2; ++j; //  à adapter dans le cas complexe ...
+	} 
+	else st.nb_nolong++;
+      }
+      else {
+	if (ritznew[j]
+	    < tol_vp * gmm::abs(eval[j])) {
+	  
+	  for (size_type l = 0, l < m-st.tb_def; ++l)
+	    YB(l, ind) = std::real(evect(l, j));
+	  kept[j] = true;
+	  ++j; ++st.nb_unwant; ind++;
+	  
+	  if (std::imag(eval[j]) != R(0)) {
+	    for (size_type l = 0, l < m-st.tb_def; ++l)
+	      YB(l, ind) = std::imag(evect(l, j));
+	    pure[ind-1] = 1;
+	    pure[ind] = 2;
+	    
+	    kept[j] = true;
+	    
+	    st.nb_unwant++;
+	    ++ind;
+	  }
+	}
+      }
+    }
+    
+    
+    for (; j < m; ++j) {
+      if (ritznew[j] != R(-1)) {
+
+	for (size_type l = 0, l < m-st.tb_def; ++l)
+	  YB(l, ind) = std::real(evect(l, j));
+	pure[ind] = 1;
+	++ind;
+	kept[j] = true;
+	++st.nb_want;
+	
+	if (ritznew[j]
+	    < tol_vp * gmm::abs(eval[j])) {
+	  for (size_type l = 0, l < m-st.tb_def; ++l)
+	    YB(l, ind) = std::imag(evect(l, j));
+	  pure[ind] = 2;
+	  
+	  j++;
+	  kept[j] = true;
+	  
+	  st.nb_want++;
+	  ++ind;	      
+	}
+      }
+    }
+    
+    std::vector<T> shift(m - st.tb_def - st.nb_want - st.nb_unwant);
+    for (size_type j = 0, i = 0; j < m; ++j)
+      if (!kept[j]) shift[i++] = eval[j];
+    
+    // st.conv (st.nb_want+st.nb_unwant) is the number of eigenpairs that
+    //   have just converged.
+    // st.tb_deftot is the total number of eigenpairs that have converged.
+    
+    size_type st.conv = ind;
+    size_type st.tb_deftot = st.tb_def + st.conv;
+    size_type st.tb_defwant = st.tb_def + st.nb_want - st.nb_nolong;
+    
+    sub_interval SUBYB(0, st.conv);
+    
+    if ( st.tb_defwant >= p ) { // An invariant subspace has been found.
+      
+      st.nb_unwant = 0;
+      st.nb_want = p + st.nb_nolong - st.tb_def;
+      st.tb_defwant = p;
+      
+      if ( pure[st.conv - st.nb_want + 1] == 2 ) {
+	++st.nb_want; st.tb_defwant = ++p;// il faudrait que ce soit un p local
+      }
+      
+      SUBYB = sub_interval(st.conv - st.nb_want, st.nb_want);
+      // YB = YB(:, st.conv-st.nb_want+1 : st.conv); // On laisse en suspend ..
+      // pure = pure(st.conv-st.nb_want+1 : st.conv,1); // On laisse suspend ..
+      st.conv = st.nb_want;
+      st.tb_deftot = st.tb_def + st.conv;
+      st.ok = true;
+    }
+    
+  }
+
+
+
+  template<typename MAT, typename EVAL, typename PURE>
+  void select_eval_for_purging(const MAT &Hobl, EVAL &eval, MAT &YB,
+			       PURE &pure, idgmres_state &st) {
+
+    typedef typename linalg_traits<MAT>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+    size_type m = st.m;
+
+    // Computation of the Ritz eigenpairs.
+    
+    col_matrix< std::vector<T> > evect(st.tb_deftot, st.tb_deftot);
+    
+    sub_interval SUB1(0, st.tb_deftot);
+    implicit_qr_algorithm(sub_matrix(Hobl, SUB1),
+			  sub_vector(eval, SUB1), evect);
+    std::fill(eval.begin() + st.tb_deftot, eval.end(), std::complex<R>(0));
+    
+    std::vector< std::pair<T, size_type> > eval_sort(m);
+    for (size_type l = 0; l < m; ++l)
+      eval_sort[l] = std::pair<T, size_type>(eval[l], l);
+    std::sort(eval_sort.begin(), eval_sort.end(), compare_vp());
+
+    std::vector<bool> sorted(m);
+    std::fill(sorted.begin(), sorted.end(), false);
+    
+    std::vector<size_type> ind(m);
+    for (size_type l = 0; l < m; ++l) ind[l] = eval_sort[l].second;
+    
+    std::vector<bool> kept(m, false);
+    std::fill(kept.begin(), kept.begin()+st.tb_def, true);
+
+    apply_permutation(eval, ind);
+    apply_permutation(evect, ind);
+    
+    size_type j;
+    for (j = 0; j < st.tb_deftot; ++j) {
+	  
+      for (size_type l = 0, l < st.tb_deftot; ++l)
+	YB(l, j) = std::real(evect(l, j));
+      
+      if (std::imag(eval[j]) != R(0)) {
+	for (size_type l = 0, l < m-st.tb_def; ++l)
+	  YB(l, j+1) = std::imag(evect(l, j));
+	pure[j] = 1;
+	pure[j+1] = 2;
+	
+	j += 2;
+      }
+      else ++j;
+    }
+  }
+  
+
+
+
+
+
+}
+
+#endif
diff --git a/Contrib/gmm/gmm_solver_qmr.h b/Contrib/gmm/gmm_solver_qmr.h
new file mode 100755
index 0000000..a9a5582
--- /dev/null
+++ b/Contrib/gmm/gmm_solver_qmr.h
@@ -0,0 +1,209 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 1997-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+// This file is a modified version of qmr.h from ITL.
+// See http://osl.iu.edu/research/itl/
+// Following the corresponding Copyright notice.
+//===========================================================================
+//
+// Copyright (c) 1997-2001, The Trustees of Indiana University.
+// All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//    * Redistributions of source code must retain the above copyright
+//      notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above copyright
+//      notice, this list of conditions and the following disclaimer in the
+//      documentation and/or other materials provided with the distribution.
+//    * Neither the name of the University of California, Berkeley nor the
+//      names of its contributors may be used to endorse or promote products
+//      derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE  IS  PROVIDED  BY  THE TRUSTEES  OF  INDIANA UNIVERSITY  AND
+// CONTRIBUTORS  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,  INCLUDING,
+// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS
+// FOR  A PARTICULAR PURPOSE ARE DISCLAIMED. IN  NO  EVENT SHALL THE TRUSTEES
+// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY,  OR CONSEQUENTIAL DAMAGES (INCLUDING,  BUT
+// NOT  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA,  OR PROFITS;  OR BUSINESS  INTERRUPTION)  HOWEVER  CAUSED AND ON ANY
+// THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT  LIABILITY, OR TORT
+// (INCLUDING  NEGLIGENCE  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+// THIS  SOFTWARE,  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//===========================================================================
+
+/**@file gmm_solver_qmr.h
+   @author Andrew Lumsdaine <lums at osl.iu.edu>
+   @author Lie-Quan Lee     <llee at osl.iu.edu>
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 13, 2002.
+   @brief Quasi-Minimal Residual iterative solver.
+*/
+#ifndef GMM_QMR_H
+#define GMM_QMR_H
+
+#include "gmm_kernel.h"
+#include "gmm_iter.h"
+
+namespace gmm {
+
+  /** Quasi-Minimal Residual.
+     
+     This routine solves the unsymmetric linear system Ax = b using
+     the Quasi-Minimal Residual method.
+   
+     See: R. W. Freund and N. M. Nachtigal, A quasi-minimal residual
+     method for non-Hermitian linear systems, Numerical Math.,
+     60(1991), pp. 315-339
+  
+     Preconditioner -  Incomplete LU, Incomplete LU with threshold,
+                       SSOR or identity_preconditioner.
+  */
+  template <typename Matrix, typename Vector, typename VectorB,
+	    typename Precond1>
+  void qmr(const Matrix &A, Vector &x, const VectorB &b, const Precond1 &M1,
+	   iteration& iter) {
+
+    typedef typename linalg_traits<Vector>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+
+    T delta(0), ep(0), beta(0), theta_1(0), gamma_1(0);
+    T theta(0), gamma(1), eta(-1);
+    R rho_1(0), rho, xi;
+
+    typedef typename temporary_vector<Vector>::vector_type TmpVec;
+    size_type nn = vect_size(x);
+    TmpVec r(nn), v_tld(nn), y(nn), w_tld(nn), z(nn), v(nn), w(nn);
+    TmpVec y_tld(nn), z_tld(nn), p(nn), q(nn), p_tld(nn), d(nn), s(nn);
+
+    iter.set_rhsnorm(double(gmm::vect_norm2(b)));
+    if (iter.get_rhsnorm() == 0.0) { clear(x); return; }
+
+    gmm::mult(A, gmm::scaled(x, T(-1)), b, r);
+    gmm::copy(r, v_tld);
+
+    gmm::left_mult(M1, v_tld, y);
+    rho = gmm::vect_norm2(y);
+
+    gmm::copy(r, w_tld);
+    gmm::transposed_right_mult(M1, w_tld, z);
+    xi = gmm::vect_norm2(z);
+  
+    while (! iter.finished_vect(r)) {
+    
+      if (rho == R(0) || xi == R(0))
+	if (iter.get_maxiter() == size_type(-1)) 
+	  { GMM_ASSERT1(false, "QMR failed to converge"); }
+	else { GMM_WARNING1("QMR failed to converge"); return; }
+
+      gmm::copy(gmm::scaled(v_tld, T(R(1)/rho)), v);
+      gmm::scale(y, T(R(1)/rho));
+
+      gmm::copy(gmm::scaled(w_tld, T(R(1)/xi)), w);
+      gmm::scale(z, T(R(1)/xi));
+
+      delta = gmm::vect_sp(z, y);
+      if (delta == T(0)) 
+	if (iter.get_maxiter() == size_type(-1)) 
+	  { GMM_ASSERT1(false, "QMR failed to converge"); }
+	else { GMM_WARNING1("QMR failed to converge"); return; }
+
+      gmm::right_mult(M1, y, y_tld);		
+      gmm::transposed_left_mult(M1, z, z_tld);
+
+      if (iter.first()) {
+	gmm::copy(y_tld, p);
+	gmm::copy(z_tld, q);
+      } else {
+	gmm::add(y_tld, gmm::scaled(p, -(T(xi  * delta) / ep)), p);
+	gmm::add(z_tld, gmm::scaled(q, -(T(rho * delta) / ep)), q);
+      }
+    
+      gmm::mult(A, p, p_tld);
+
+      ep = gmm::vect_sp(q, p_tld);
+      if (ep == T(0)) 
+	if (iter.get_maxiter() == size_type(-1)) 
+	  { GMM_ASSERT1(false, "QMR failed to converge"); }
+	else { GMM_WARNING1("QMR failed to converge"); return; }
+
+      beta = ep / delta;
+      if (beta == T(0))
+	if (iter.get_maxiter() == size_type(-1)) 
+	  { GMM_ASSERT1(false, "QMR failed to converge"); }
+	else { GMM_WARNING1("QMR failed to converge"); return; }
+
+      gmm::add(p_tld, gmm::scaled(v, -beta), v_tld);
+      gmm::left_mult(M1, v_tld, y);
+
+      rho_1 = rho;
+      rho = gmm::vect_norm2(y);
+
+      gmm::mult(gmm::transposed(A), q, w_tld);
+      gmm::add(w_tld, gmm::scaled(w, -beta), w_tld);
+      gmm::transposed_right_mult(M1, w_tld, z);
+
+      xi = gmm::vect_norm2(z);
+
+      gamma_1 = gamma;
+      theta_1 = theta;
+
+      theta = rho / (gamma_1 * beta);
+      gamma = T(1) / gmm::sqrt(T(1) + gmm::sqr(theta));
+
+      if (gamma == T(0)) 
+	if (iter.get_maxiter() == size_type(-1)) 
+	  { GMM_ASSERT1(false, "QMR failed to converge"); }
+	else { GMM_WARNING1("QMR failed to converge"); return; }
+      
+      eta = -eta * T(rho_1) * gmm::sqr(gamma) / (beta * gmm::sqr(gamma_1));
+
+      if (iter.first()) {
+	gmm::copy(gmm::scaled(p, eta), d);
+	gmm::copy(gmm::scaled(p_tld, eta), s);
+      } else {
+	T tmp = gmm::sqr(theta_1 * gamma);
+	gmm::add(gmm::scaled(p, eta), gmm::scaled(d, tmp), d);
+	gmm::add(gmm::scaled(p_tld, eta), gmm::scaled(s, tmp), s);
+      }
+      gmm::add(d, x);
+      gmm::add(gmm::scaled(s, T(-1)), r);
+
+      ++iter;
+    }
+  }
+
+
+}
+
+#endif 
+
diff --git a/Contrib/gmm/gmm_std.h b/Contrib/gmm/gmm_std.h
new file mode 100755
index 0000000..4e476d5
--- /dev/null
+++ b/Contrib/gmm/gmm_std.h
@@ -0,0 +1,255 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 1995-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_std.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>,
+   @author  Julien Pommier <Julien.Pommier at insa-toulouse.fr>
+   @date June 01, 1995.
+   @brief basic setup for gmm (includes, typedefs etc.)
+*/
+#ifndef GMM_STD_H__
+#define GMM_STD_H__
+
+#ifndef __USE_STD_IOSTREAM
+# define __USE_STD_IOSTREAM
+#endif
+
+#ifndef __USE_BSD
+# define __USE_BSD
+#endif
+
+#ifndef __USE_ISOC99
+# define __USE_ISOC99
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400 // Secure versions for VC++
+# define GMM_SECURE_CRT
+# define SECURE_NONCHAR_SSCANF sscanf_s
+# define SECURE_NONCHAR_FSCANF fscanf_s
+# define SECURE_STRNCPY(a, la, b, lb) strncpy_s(a, la, b, lb)
+# define SECURE_FOPEN(F, filename, mode) (*(F) = 0,  fopen_s(F, filename, mode))
+# define SECURE_SPRINTF1(S, l, st, p1) sprintf_s(S, l, st, p1) 
+# define SECURE_SPRINTF2(S, l, st, p1, p2) sprintf_s(S, l, st, p1, p2) 
+# define SECURE_SPRINTF4(S, l, st, p1, p2, p3, p4) sprintf_s(S, l, st, p1, p2, p3, p4)
+# define SECURE_STRDUP(s) _strdup(s)
+# ifndef _SCL_SECURE_NO_DEPRECATE
+#   error Add the option /D_SCL_SECURE_NO_DEPRECATE to the compilation command
+# endif
+#else
+# define SECURE_NONCHAR_SSCANF sscanf
+# define SECURE_NONCHAR_FSCANF fscanf
+# define SECURE_STRNCPY(a, la, b, lb) strncpy(a, b, lb)
+# define SECURE_FOPEN(F, filename, mode) ((*(F)) = fopen(filename, mode))
+# define SECURE_SPRINTF1(S, l, st, p1) sprintf(S, st, p1)
+# define SECURE_SPRINTF2(S, l, st, p1, p2) sprintf(S, st, p1, p2)
+# define SECURE_SPRINTF4(S, l, st, p1, p2, p3, p4) sprintf(S, st, p1, p2, p3, p4) 
+# define SECURE_STRDUP(s) strdup(s)
+#endif
+
+
+#if !defined(GMM_USES_MPI) && GETFEM_PARA_LEVEL > 0
+# define GMM_USES_MPI
+#endif
+
+/* ********************************************************************** */
+/*	Compilers detection.						  */
+/* ********************************************************************** */
+
+/* for sun CC 5.0 ...
+#if defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x500
+# include <stdcomp.h>
+# undef _RWSTD_NO_CLASS_PARTIAL_SPEC
+# undef _RWSTD_NO_NAMESPACE
+#endif 
+*/
+/* for VISUAL C++ ...
+   #if defined(_MSC_VER) //  && !defined(__MWERKS__)
+   #define _GETFEM_MSVCPP_ _MSC_VER
+   #endif
+*/
+
+#if defined(__GNUC__)
+#  if (__GNUC__ < 3)
+#    error : PLEASE UPDATE g++ TO AT LEAST 3.0 VERSION
+#  endif
+#endif
+
+/* ********************************************************************** */
+/*	C++ Standard Headers.						  */
+/* ********************************************************************** */
+#include <cstdlib>
+#include <cstddef>
+#include <cmath>
+#include <cstring>
+#include <cctype>
+#include <cassert>
+#include <climits>
+#include <iostream>
+//#include <ios> 
+#include <fstream>
+#include <ctime>
+#include <exception>
+#include <typeinfo>
+#include <stdexcept>
+#include <iterator>
+#include <algorithm>
+#include <vector>
+#include <deque>
+#include <string>
+#include <complex>
+#include <limits>
+#include <sstream>
+#include <numeric>
+
+
+using std::endl; using std::cout; using std::cerr;
+using std::ends; using std::cin;
+
+namespace gmm {
+
+  /* ******************************************************************* */
+  /*       Clock functions.                                              */
+  /* ******************************************************************* */
+  
+# if  defined(HAVE_SYS_TIMES)
+  inline double uclock_sec(void) {
+    static double ttclk = 0.;
+    if (ttclk == 0.) ttclk = sysconf(_SC_CLK_TCK);
+    tms t; times(&t); return double(t.tms_utime) / ttclk;
+  }
+# else
+  inline double uclock_sec(void)
+  { return double(clock())/double(CLOCKS_PER_SEC); }
+# endif
+  
+  /* ******************************************************************** */
+  /*	Fixed size integer types.                     			  */
+  /* ******************************************************************** */
+  // Remark : the test program dynamic_array tests the lenght of
+  //          resulting integers
+
+  template <size_t s> struct fixed_size_integer_generator {
+    typedef void int_base_type;
+    typedef void uint_base_type;  
+  };
+
+  template <> struct fixed_size_integer_generator<sizeof(char)> {
+    typedef signed char int_base_type;
+    typedef unsigned char uint_base_type;
+  };
+
+  template <> struct fixed_size_integer_generator<sizeof(short int)
+    - ((sizeof(short int) == sizeof(char)) ? 78 : 0)> {
+    typedef signed short int int_base_type;
+    typedef unsigned short int uint_base_type;
+  };
+
+  template <> struct fixed_size_integer_generator<sizeof(int)
+    - ((sizeof(int) == sizeof(short int)) ? 59 : 0)> {
+    typedef signed int int_base_type;
+    typedef unsigned int uint_base_type;
+  };
+ 
+  template <> struct fixed_size_integer_generator<sizeof(long)
+    - ((sizeof(int) == sizeof(long)) ? 93 : 0)> {
+    typedef signed long int_base_type;
+    typedef unsigned long uint_base_type;
+  };
+
+  template <> struct fixed_size_integer_generator<sizeof(long long)
+    - ((sizeof(long long) == sizeof(long)) ? 99 : 0)> {
+    typedef signed long long int_base_type;
+    typedef unsigned long long uint_base_type;
+  };
+ 
+  typedef fixed_size_integer_generator<1>::int_base_type int8_type;
+  typedef fixed_size_integer_generator<1>::uint_base_type uint8_type;
+  typedef fixed_size_integer_generator<2>::int_base_type int16_type;
+  typedef fixed_size_integer_generator<2>::uint_base_type uint16_type;
+  typedef fixed_size_integer_generator<4>::int_base_type int32_type;
+  typedef fixed_size_integer_generator<4>::uint_base_type uint32_type;
+  typedef fixed_size_integer_generator<8>::int_base_type int64_type;
+  typedef fixed_size_integer_generator<8>::uint_base_type uint64_type;
+
+// #if INT_MAX == 32767
+//   typedef signed int    int16_type;
+//   typedef unsigned int uint16_type;
+// #elif  SHRT_MAX == 32767
+//   typedef signed short int    int16_type;
+//   typedef unsigned short int uint16_type;
+// #else
+// # error "impossible to build a 16 bits integer"
+// #endif
+
+// #if INT_MAX == 2147483647
+//   typedef signed int    int32_type;
+//   typedef unsigned int uint32_type;
+// #elif  SHRT_MAX == 2147483647
+//   typedef signed short int    int32_type;
+//   typedef unsigned short int uint32_type;
+// #elif LONG_MAX == 2147483647
+//   typedef signed long int    int32_type;
+//   typedef unsigned long int uint32_type;
+// #else
+// # error "impossible to build a 32 bits integer"
+// #endif
+
+// #if INT_MAX == 9223372036854775807L || INT_MAX == 9223372036854775807
+//   typedef signed int    int64_type;
+//   typedef unsigned int uint64_type;
+// #elif LONG_MAX == 9223372036854775807L || LONG_MAX == 9223372036854775807
+//   typedef signed long int    int64_type;
+//   typedef unsigned long int uint64_type;
+// #elif LLONG_MAX == 9223372036854775807LL || LLONG_MAX == 9223372036854775807L || LLONG_MAX == 9223372036854775807
+//   typedef signed long long int int64_type;
+//   typedef unsigned long long int uint64_type;
+// #else
+// # error "impossible to build a 64 bits integer"
+// #endif
+
+#if defined(__GNUC__) && !defined(__ICC)
+/* 
+   g++ can issue a warning at each usage of a function declared with this special attribute 
+   (also works with typedefs and variable declarations)
+*/
+# define IS_DEPRECATED __attribute__ ((__deprecated__))
+/*
+   the specified function is inlined at any optimization level 
+*/
+# define ALWAYS_INLINE __attribute__((always_inline))
+#else
+# define IS_DEPRECATED
+# define ALWAYS_INLINE
+#endif
+  
+}
+
+#endif /* GMM_STD_H__ */
+
diff --git a/Contrib/gmm/gmm_sub_index.h b/Contrib/gmm/gmm_sub_index.h
new file mode 100755
index 0000000..387c707
--- /dev/null
+++ b/Contrib/gmm/gmm_sub_index.h
@@ -0,0 +1,217 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_sub_index.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 13, 2002.
+   @brief sub-indices.
+*/
+
+#ifndef GMM_SUB_INDEX_H__
+#define GMM_SUB_INDEX_H__
+
+#include "gmm_def.h"
+
+namespace gmm {
+
+  /* ******************************************************************** */
+  /*		sub indices                               		  */
+  /* ******************************************************************** */
+
+  struct basic_index : public std::vector<size_t> {
+    
+    mutable size_type nb_ref;
+    // size_type key1; faire la somme des composantes
+    // const basic_index *rind; rindex s'il existe
+    
+
+    size_t operator[](size_type i) const {
+      return (i < size()) ? std::vector<size_t>::operator[](i) : size_type(-1);
+    }
+    
+    basic_index() : nb_ref(1) {}
+    basic_index(size_type j) : std::vector<size_t>(j), nb_ref(1) {}
+    template <typename IT> basic_index(IT b, IT e)
+      : std::vector<size_t>(e-b), nb_ref(1) { std::copy(b, e, begin()); }
+    basic_index(const basic_index *pbi) : nb_ref(1) {
+      const_iterator it = pbi->begin(), ite = pbi->end();
+      size_type i = 0;
+      for ( ; it != ite; ++it) i = std::max(i, *it);
+      resize(i+1); std::fill(begin(), end(), size_type(-1));
+      for (it = pbi->begin(), i = 0; it != ite; ++it, ++i)
+	std::vector<size_t>::operator[](*it) = i;
+    }
+    void swap(size_type i, size_type j) {
+      std::swap(std::vector<size_t>::operator[](i),
+		std::vector<size_t>::operator[](j));
+    }
+    
+  };
+
+  typedef basic_index *pbasic_index;
+
+  struct index_generator {
+
+    template <typename IT> static pbasic_index create_index(IT begin, IT end)
+    { return new basic_index(begin, end); }
+    static pbasic_index create_rindex(pbasic_index pbi)
+    { return new basic_index(pbi); }
+    static void attach(pbasic_index pbi) { if (pbi) pbi->nb_ref++; }
+    static void unattach(pbasic_index pbi)
+      { if (pbi && --(pbi->nb_ref) == 0) delete pbi; }
+
+  };
+
+  struct sub_index {
+
+    size_type first_, last_;
+    typedef basic_index base_type;
+    typedef base_type::const_iterator const_iterator;
+
+    mutable pbasic_index ind;
+    mutable pbasic_index rind;
+
+    void comp_extr(void) {
+      std::vector<size_t>::const_iterator it = ind->begin(), ite = ind->end();
+      if (it != ite) { first_=last_= *it; ++it; } else { first_=last_= 0; }
+      for (; it != ite; ++it) 
+	{ first_ = std::min(first_, *it); last_ = std::max(last_, *it); }
+    }
+
+    // inline void test_rind(void) const
+    //  { if (!rind) rind = index_generator::create_rindex(ind); }
+    size_type size(void) const { return ind->size(); }
+    size_type first(void) const { return first_; }
+    size_type last(void) const { return last_; }
+    size_type index(size_type i) const { return (*ind)[i]; }
+    size_type rindex(size_type i) const {
+      // test_rind();
+      if (i < rind->size()) return (*rind)[i]; else return size_type(-1);
+    }
+   
+    const_iterator  begin(void) const { return  ind->begin(); }
+    const_iterator    end(void) const { return  ind->end();   }
+    const_iterator rbegin(void) const {/*test_rind();*/ return rind->begin(); }
+    const_iterator   rend(void) const {/*test_rind();*/ return rind->end();   }
+
+    sub_index() : ind(0), rind(0) {}
+    template <typename IT> sub_index(IT it, IT ite)
+      : ind(index_generator::create_index(it, ite)),
+	rind(index_generator::create_rindex(ind)) { comp_extr(); }
+    template <typename CONT> sub_index(const CONT &c)
+      : ind(index_generator::create_index(c.begin(), c.end())),
+	rind(index_generator::create_rindex(ind))
+        { comp_extr(); }
+    ~sub_index()
+      { index_generator::unattach(rind); index_generator::unattach(ind); }
+    sub_index(const sub_index &si) : first_(si.first_), last_(si.last_),
+				     ind(si.ind), rind(si.rind)
+      { index_generator::attach(rind); index_generator::attach(ind); }
+    sub_index &operator =(const sub_index &si) {
+      index_generator::unattach(rind); index_generator::unattach(ind);
+      ind = si.ind; rind = si.rind; index_generator::attach(rind);
+      index_generator::attach(ind);
+      first_ = si.first_; last_ = si.last_;
+      return *this;
+    }
+  };
+
+  struct unsorted_sub_index : public sub_index {
+    template <typename IT> unsorted_sub_index(IT it, IT ite)
+      : sub_index(it, ite) {}
+    template <typename CONT> unsorted_sub_index(const CONT &c)
+      : sub_index(c) {}
+    unsorted_sub_index() {}
+    unsorted_sub_index(const unsorted_sub_index &si) : sub_index(si) {}
+    unsorted_sub_index &operator =(const unsorted_sub_index &si)
+    { sub_index::operator =(si); return *this; }
+    void swap(size_type i, size_type j) {
+      GMM_ASSERT2(ind->nb_ref <= 1, "Operation not allowed on this index");
+      if (rind) rind->swap((*ind)[i], (*ind)[j]);
+      ind->swap(i, j);
+    }
+  };
+
+  inline std::ostream &operator << (std::ostream &o, const sub_index &si) { 
+    o << "sub_index(";
+    if (si.size() != 0) o << si.index(0);
+    for (size_type i = 1; i < si.size(); ++i) o << ", " << si.index(i);
+    o << ")";
+    return o;
+  }
+
+  struct sub_interval {
+    size_type min, max; 
+
+    size_type size(void) const { return max - min; }
+    size_type first(void) const { return min; }
+    size_type last(void) const { return max; }
+    size_type index(size_type i) const { return min + i; }
+    size_type step(void) const { return 1; }
+    size_type rindex(size_type i) const
+    { if (i >= min && i < max) return i - min; return size_type(-1); }
+    sub_interval(size_type mi, size_type l) : min(mi), max(mi+l) {}
+    sub_interval() {}
+  };
+
+  inline std::ostream &operator << (std::ostream &o, const sub_interval &si)
+  { o << "sub_interval(" << si.min << ", " << si.size() << ")"; return o; }
+
+  struct sub_slice {
+    size_type min, max, N;
+
+    size_type size(void) const { return (max - min) / N; }
+    size_type first(void) const { return min; }
+    size_type last(void) const { return (min == max) ? max : max+1-N; }
+    size_type step(void) const { return N; }
+    size_type index(size_type i) const { return min + N * i; }
+    size_type rindex(size_type i) const { 
+      if (i >= min && i < max)
+	{ size_type j = (i - min); if (j % N == 0) return j / N; }
+      return size_type(-1);
+    }
+    sub_slice(size_type mi, size_type l, size_type n)
+      : min(mi), max(mi+l*n), N(n) {}
+    sub_slice(void) {}
+  };
+
+  inline std::ostream &operator << (std::ostream &o, const sub_slice &si) {
+    o << "sub_slice(" << si.min << ", " << si.size() << ", " << si.step() 
+      << ")"; return o;
+  }
+
+  template<class SUBI> struct index_is_sorted
+  {  typedef linalg_true bool_type; };
+  template<> struct index_is_sorted<unsorted_sub_index>
+  {  typedef linalg_false bool_type; };
+
+}
+
+#endif //  GMM_SUB_INDEX_H__
diff --git a/Contrib/gmm/gmm_sub_matrix.h b/Contrib/gmm/gmm_sub_matrix.h
new file mode 100755
index 0000000..efc36bc
--- /dev/null
+++ b/Contrib/gmm/gmm_sub_matrix.h
@@ -0,0 +1,409 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_sub_matrix.h
+   @author Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 13, 2002.
+   @brief Generic sub-matrices.
+*/
+
+#ifndef GMM_SUB_MATRIX_H__
+#define GMM_SUB_MATRIX_H__
+
+#include "gmm_sub_vector.h"
+
+namespace gmm {
+
+  /* ********************************************************************* */
+  /*		sub row matrices type                                      */
+  /* ********************************************************************* */
+
+  template <typename PT, typename SUBI1, typename SUBI2>
+  struct gen_sub_row_matrix {
+    typedef gen_sub_row_matrix<PT, SUBI1, SUBI2> this_type;
+    typedef typename std::iterator_traits<PT>::value_type M;
+    typedef M * CPT;
+    typedef typename std::iterator_traits<PT>::reference ref_M;
+    typedef typename select_ref<typename linalg_traits<M>
+            ::const_row_iterator, typename linalg_traits<M>::row_iterator,
+	    PT>::ref_type iterator;
+    typedef typename linalg_traits<this_type>::reference reference;
+    typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+    SUBI1 si1;
+    SUBI2 si2;
+    iterator begin_;
+    porigin_type origin;
+    
+    reference operator()(size_type i, size_type j) const 
+    { return linalg_traits<M>::access(begin_ + si1.index(i), si2.index(j)); }
+   
+    size_type nrows(void) const { return si1.size(); }
+    size_type ncols(void) const { return si2.size(); }
+    
+    gen_sub_row_matrix(ref_M m, const SUBI1 &s1, const SUBI2 &s2)
+      : si1(s1), si2(s2), begin_(mat_row_begin(m)),
+	origin(linalg_origin(m)) {}
+    gen_sub_row_matrix() {}
+    gen_sub_row_matrix(const gen_sub_row_matrix<CPT, SUBI1, SUBI2> &cr) :
+      si1(cr.si1), si2(cr.si2), begin_(cr.begin_),origin(cr.origin) {}
+  };
+
+  template <typename PT, typename SUBI1, typename SUBI2>
+  struct gen_sub_row_matrix_iterator {
+    typedef gen_sub_row_matrix<PT, SUBI1, SUBI2> this_type;
+    typedef typename modifiable_pointer<PT>::pointer MPT;
+    typedef typename std::iterator_traits<PT>::value_type M;
+    typedef typename select_ref<typename linalg_traits<M>
+            ::const_row_iterator, typename linalg_traits<M>::row_iterator,
+	    PT>::ref_type ITER;
+    typedef ITER value_type;
+    typedef ITER *pointer;
+    typedef ITER &reference;
+    typedef ptrdiff_t difference_type;
+    typedef size_t size_type;
+    typedef std::random_access_iterator_tag  iterator_category;
+    typedef gen_sub_row_matrix_iterator<PT, SUBI1, SUBI2> iterator;
+
+    ITER it;
+    SUBI1 si1;
+    SUBI2 si2;
+    size_type ii;
+    
+    iterator operator ++(int) { iterator tmp = *this; ii++; return tmp; }
+    iterator operator --(int) { iterator tmp = *this; ii--; return tmp; }
+    iterator &operator ++()   { ii++; return *this; }
+    iterator &operator --()   { ii--; return *this; }
+    iterator &operator +=(difference_type i) { ii += i; return *this; }
+    iterator &operator -=(difference_type i) { ii -= i; return *this; }
+    iterator operator +(difference_type i) const 
+    { iterator itt = *this; return (itt += i); }
+    iterator operator -(difference_type i) const
+    { iterator itt = *this; return (itt -= i); }
+    difference_type operator -(const iterator &i) const { return ii - i.ii; }
+
+    ITER operator *() const { return it + si1.index(ii); }
+    ITER operator [](int i) { return it + si1.index(ii+i); }
+
+    bool operator ==(const iterator &i) const { return (ii == i.ii); }
+    bool operator !=(const iterator &i) const { return !(i == *this); }
+    bool operator < (const iterator &i) const { return (ii < i.ii); }
+
+    gen_sub_row_matrix_iterator(void) {}
+    gen_sub_row_matrix_iterator(const 
+	     gen_sub_row_matrix_iterator<MPT, SUBI1, SUBI2> &itm)
+      : it(itm.it), si1(itm.si1), si2(itm.si2), ii(itm.ii) {}
+    gen_sub_row_matrix_iterator(const ITER &iter, const SUBI1 &s1,
+				const SUBI2 &s2, size_type i)
+      : it(iter), si1(s1), si2(s2), ii(i) { }
+    
+  };
+
+  template <typename PT, typename SUBI1, typename SUBI2>
+  struct linalg_traits<gen_sub_row_matrix<PT, SUBI1, SUBI2> > {
+    typedef gen_sub_row_matrix<PT, SUBI1, SUBI2> this_type;
+    typedef typename std::iterator_traits<PT>::value_type M;
+    typedef typename which_reference<PT>::is_reference is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef typename linalg_traits<M>::origin_type origin_type;
+    typedef typename select_ref<const origin_type *, origin_type *,
+				PT>::ref_type porigin_type;
+    typedef typename linalg_traits<M>::value_type value_type;
+    typedef typename select_ref<value_type,
+            typename linalg_traits<M>::reference, PT>::ref_type reference;
+    typedef abstract_null_type sub_col_type;
+    typedef abstract_null_type col_iterator;
+    typedef abstract_null_type const_sub_col_type;
+    typedef abstract_null_type const_col_iterator;
+    typedef typename sub_vector_type<const typename
+            linalg_traits<M>::const_sub_row_type *, SUBI2>::vector_type
+            const_sub_row_type;
+    typedef typename select_ref<abstract_null_type, 
+            typename sub_vector_type<typename linalg_traits<M>::sub_row_type *,
+	    SUBI2>::vector_type, PT>::ref_type sub_row_type;
+    typedef gen_sub_row_matrix_iterator<typename const_pointer<PT>::pointer,
+	    SUBI1, SUBI2> const_row_iterator;
+    typedef typename select_ref<abstract_null_type, 
+	    gen_sub_row_matrix_iterator<PT, SUBI1, SUBI2>, PT>::ref_type
+            row_iterator;
+    typedef typename linalg_traits<const_sub_row_type>::storage_type
+            storage_type;
+    typedef row_major sub_orientation;
+    typedef linalg_true index_sorted;
+    static size_type nrows(const this_type &m) { return m.nrows(); }
+    static size_type ncols(const this_type &m) { return m.ncols(); }
+    static const_sub_row_type row(const const_row_iterator &it)
+    { return const_sub_row_type(linalg_traits<M>::row(*it), it.si2); }
+    static sub_row_type row(const row_iterator &it)
+    { return sub_row_type(linalg_traits<M>::row(*it), it.si2); }
+    static const_row_iterator row_begin(const this_type &m)
+    { return const_row_iterator(m.begin_, m.si1, m.si2, 0); }
+    static row_iterator row_begin(this_type &m)
+    { return row_iterator(m.begin_, m.si1, m.si2, 0); }
+    static const_row_iterator row_end(const this_type &m)
+    { return const_row_iterator(m.begin_, m.si1, m.si2,  m.nrows()); }
+    static row_iterator row_end(this_type &m)
+    { return row_iterator(m.begin_, m.si1, m.si2, m.nrows()); }
+    static origin_type* origin(this_type &v) { return v.origin; }
+    static const origin_type* origin(const this_type &v) { return v.origin; }
+    static void do_clear(this_type &m) {
+      row_iterator it = mat_row_begin(m), ite = mat_row_end(m);
+      for (; it != ite; ++it) clear(row(it));
+    }
+    static value_type access(const const_row_iterator &itrow, size_type i)
+    { return linalg_traits<M>::access(*itrow, itrow.si2.index(i)); }
+    static reference access(const row_iterator &itrow, size_type i)
+    { return linalg_traits<M>::access(*itrow, itrow.si2.index(i)); }
+  };
+  
+  template <typename PT, typename SUBI1, typename SUBI2>
+  std::ostream &operator <<(std::ostream &o,
+			    const gen_sub_row_matrix<PT, SUBI1, SUBI2>& m)
+  { gmm::write(o,m); return o; }
+
+
+  /* ********************************************************************* */
+  /*		sub column matrices type                                   */
+  /* ********************************************************************* */
+
+  template <typename PT, typename SUBI1, typename SUBI2>
+  struct gen_sub_col_matrix {
+    typedef gen_sub_col_matrix<PT, SUBI1, SUBI2> this_type;
+    typedef typename std::iterator_traits<PT>::value_type M;
+    typedef M * CPT;
+    typedef typename std::iterator_traits<PT>::reference ref_M;
+    typedef typename select_ref<typename linalg_traits<M>
+            ::const_col_iterator, typename linalg_traits<M>::col_iterator,
+	    PT>::ref_type iterator;
+    typedef typename linalg_traits<this_type>::reference reference;
+    typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+    SUBI1 si1;
+    SUBI2 si2;
+    iterator begin_;
+    porigin_type origin;
+    
+    reference operator()(size_type i, size_type j) const
+    { return linalg_traits<M>::access(begin_ + si2.index(j), si1.index(i)); }
+
+    size_type nrows(void) const { return si1.size(); }
+    size_type ncols(void) const { return si2.size(); }
+    
+    gen_sub_col_matrix(ref_M m, const SUBI1 &s1, const SUBI2 &s2)
+      : si1(s1), si2(s2), begin_(mat_col_begin(m)),
+        origin(linalg_origin(m)) {}
+    gen_sub_col_matrix() {}
+    gen_sub_col_matrix(const gen_sub_col_matrix<CPT, SUBI1, SUBI2> &cr) :
+      si1(cr.si1), si2(cr.si2), begin_(cr.begin_),origin(cr.origin) {}
+  };
+
+  template <typename PT, typename SUBI1, typename SUBI2>
+  struct gen_sub_col_matrix_iterator {
+    typedef gen_sub_col_matrix<PT, SUBI1, SUBI2> this_type;
+    typedef typename modifiable_pointer<PT>::pointer MPT;
+    typedef typename std::iterator_traits<PT>::value_type M;
+    typedef typename select_ref<typename linalg_traits<M>::const_col_iterator,
+				typename linalg_traits<M>::col_iterator,
+				PT>::ref_type ITER;
+    typedef ITER value_type;
+    typedef ITER *pointer;
+    typedef ITER &reference;
+    typedef ptrdiff_t difference_type;
+    typedef size_t size_type;
+    typedef std::random_access_iterator_tag  iterator_category;
+    typedef gen_sub_col_matrix_iterator<PT, SUBI1, SUBI2> iterator;
+
+    ITER it;
+    SUBI1 si1;
+    SUBI2 si2;
+    size_type ii;
+    
+    iterator operator ++(int) { iterator tmp = *this; ii++; return tmp; }
+    iterator operator --(int) { iterator tmp = *this; ii--; return tmp; }
+    iterator &operator ++()   { ii++; return *this; }
+    iterator &operator --()   { ii--; return *this; }
+    iterator &operator +=(difference_type i) { ii += i; return *this; }
+    iterator &operator -=(difference_type i) { ii -= i; return *this; }
+    iterator operator +(difference_type i) const 
+    { iterator itt = *this; return (itt += i); }
+    iterator operator -(difference_type i) const
+    { iterator itt = *this; return (itt -= i); }
+    difference_type operator -(const iterator &i) const { return ii - i.ii; }
+
+    ITER operator *() const { return it + si2.index(ii); }
+    ITER operator [](int i) { return it + si2.index(ii+i); }
+
+    bool operator ==(const iterator &i) const { return (ii == i.ii); }
+    bool operator !=(const iterator &i) const { return !(i == *this); }
+    bool operator < (const iterator &i) const { return (ii < i.ii); }
+
+    gen_sub_col_matrix_iterator(void) {}
+    gen_sub_col_matrix_iterator(const 
+	gen_sub_col_matrix_iterator<MPT, SUBI1, SUBI2> &itm)
+      : it(itm.it), si1(itm.si1), si2(itm.si2), ii(itm.ii) {}
+    gen_sub_col_matrix_iterator(const ITER &iter, const SUBI1 &s1,
+				const SUBI2 &s2, size_type i)
+      : it(iter), si1(s1), si2(s2), ii(i) { }
+  };
+
+  template <typename PT, typename SUBI1, typename SUBI2>
+  struct linalg_traits<gen_sub_col_matrix<PT, SUBI1, SUBI2> > {
+    typedef gen_sub_col_matrix<PT, SUBI1, SUBI2> this_type;
+    typedef typename std::iterator_traits<PT>::value_type M;
+    typedef typename linalg_traits<M>::origin_type origin_type;
+    typedef typename select_ref<const origin_type *, origin_type *,
+			        PT>::ref_type porigin_type;
+    typedef typename which_reference<PT>::is_reference is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef typename linalg_traits<M>::value_type value_type;
+    typedef typename select_ref<value_type,
+            typename linalg_traits<M>::reference, PT>::ref_type reference;
+    typedef abstract_null_type sub_row_type;
+    typedef abstract_null_type row_iterator;
+    typedef abstract_null_type const_sub_row_type;
+    typedef abstract_null_type const_row_iterator;
+    typedef typename sub_vector_type<const typename
+            linalg_traits<M>::const_sub_col_type *, SUBI1>::vector_type
+            const_sub_col_type;
+    typedef typename select_ref<abstract_null_type, 
+            typename sub_vector_type<typename linalg_traits<M>::sub_col_type *,
+	    SUBI1>::vector_type, PT>::ref_type sub_col_type;
+    typedef gen_sub_col_matrix_iterator<typename const_pointer<PT>::pointer,
+	    SUBI1, SUBI2> const_col_iterator;
+    typedef typename select_ref<abstract_null_type, 
+	    gen_sub_col_matrix_iterator<PT, SUBI1, SUBI2>, PT>::ref_type
+            col_iterator;
+    typedef col_major sub_orientation;
+    typedef linalg_true index_sorted;
+    typedef typename linalg_traits<const_sub_col_type>::storage_type
+    storage_type;
+    static size_type nrows(const this_type &m) { return m.nrows(); }
+    static size_type ncols(const this_type &m) { return m.ncols(); }
+    static const_sub_col_type col(const const_col_iterator &it)
+    { return const_sub_col_type(linalg_traits<M>::col(*it), it.si1); }
+    static sub_col_type col(const col_iterator &it)
+    { return sub_col_type(linalg_traits<M>::col(*it), it.si1); }
+    static const_col_iterator col_begin(const this_type &m)
+    { return const_col_iterator(m.begin_, m.si1, m.si2, 0); }
+    static col_iterator col_begin(this_type &m)
+    { return col_iterator(m.begin_, m.si1, m.si2, 0); }
+    static const_col_iterator col_end(const this_type &m)
+    { return const_col_iterator(m.begin_, m.si1, m.si2,  m.ncols()); }
+    static col_iterator col_end(this_type &m)
+    { return col_iterator(m.begin_, m.si1, m.si2, m.ncols()); } 
+    static origin_type* origin(this_type &v) { return v.origin; }
+    static const origin_type* origin(const this_type &v) { return v.origin; }
+    static void do_clear(this_type &m) {
+      col_iterator it = mat_col_begin(m), ite = mat_col_end(m);
+      for (; it != ite; ++it) clear(col(it));
+    }
+    static value_type access(const const_col_iterator &itcol, size_type i)
+    { return linalg_traits<M>::access(*itcol, itcol.si1.index(i)); }
+    static reference access(const col_iterator &itcol, size_type i)
+    { return linalg_traits<M>::access(*itcol, itcol.si1.index(i)); }
+  };
+
+  template <typename PT, typename SUBI1, typename SUBI2> std::ostream &operator <<
+  (std::ostream &o, const gen_sub_col_matrix<PT, SUBI1, SUBI2>& m)
+  { gmm::write(o,m); return o; }
+
+  /* ******************************************************************** */
+  /*		sub matrices                                              */
+  /* ******************************************************************** */
+  
+  template <typename PT, typename SUBI1, typename SUBI2, typename ST>
+  struct sub_matrix_type_ {
+    typedef abstract_null_type return_type;
+  };
+  template <typename PT, typename SUBI1, typename SUBI2>
+  struct sub_matrix_type_<PT, SUBI1, SUBI2, col_major>
+  { typedef gen_sub_col_matrix<PT, SUBI1, SUBI2> matrix_type; };
+  template <typename PT, typename SUBI1, typename SUBI2>
+  struct sub_matrix_type_<PT, SUBI1, SUBI2, row_major>
+  { typedef gen_sub_row_matrix<PT, SUBI1, SUBI2> matrix_type; };
+  template <typename PT, typename SUBI1, typename SUBI2>
+  struct sub_matrix_type {
+    typedef typename std::iterator_traits<PT>::value_type M;
+    typedef typename sub_matrix_type_<PT, SUBI1, SUBI2,
+        typename principal_orientation_type<typename
+        linalg_traits<M>::sub_orientation>::potype>::matrix_type matrix_type;
+  };
+
+  template <typename M, typename SUBI1, typename SUBI2>  inline
+    typename select_return<typename sub_matrix_type<const M *, SUBI1, SUBI2>
+    ::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI2>::matrix_type,
+    M *>::return_type
+  sub_matrix(M &m, const SUBI1 &si1, const SUBI2 &si2) {
+    GMM_ASSERT2(si1.last() <= mat_nrows(m) && si2.last() <= mat_ncols(m),
+		"sub matrix too large");
+    return typename select_return<typename sub_matrix_type<const M *, SUBI1,
+      SUBI2>::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI2>
+      ::matrix_type, M *>::return_type(linalg_cast(m), si1, si2);
+  }
+
+  template <typename M, typename SUBI1, typename SUBI2>  inline
+    typename select_return<typename sub_matrix_type<const M *, SUBI1, SUBI2>
+    ::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI2>::matrix_type,
+    const M *>::return_type
+  sub_matrix(const M &m, const SUBI1 &si1, const SUBI2 &si2) {
+    GMM_ASSERT2(si1.last() <= mat_nrows(m) && si2.last() <= mat_ncols(m),
+		"sub matrix too large");
+    return typename select_return<typename sub_matrix_type<const M *, SUBI1,
+      SUBI2>::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI2>
+      ::matrix_type, const M *>::return_type(linalg_cast(m), si1, si2);
+  }
+
+  template <typename M, typename SUBI1>  inline
+    typename select_return<typename sub_matrix_type<const M *, SUBI1, SUBI1>
+    ::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI1>::matrix_type,
+    M *>::return_type
+  sub_matrix(M &m, const SUBI1 &si1) {
+    GMM_ASSERT2(si1.last() <= mat_nrows(m) && si1.last() <= mat_ncols(m),
+		"sub matrix too large");
+    return typename select_return<typename sub_matrix_type<const M *, SUBI1,
+      SUBI1>::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI1>
+      ::matrix_type, M *>::return_type(linalg_cast(m), si1, si1);
+  }
+
+  template <typename M, typename SUBI1>  inline
+    typename select_return<typename sub_matrix_type<const M *, SUBI1, SUBI1>
+    ::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI1>::matrix_type,
+    const M *>::return_type
+  sub_matrix(const M &m, const SUBI1 &si1) {
+    GMM_ASSERT2(si1.last() <= mat_nrows(m) && si1.last() <= mat_ncols(m),
+		"sub matrix too large");
+    return typename select_return<typename sub_matrix_type<const M *, SUBI1,
+      SUBI1>::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI1>
+      ::matrix_type, const M *>::return_type(linalg_cast(m), si1, si1);
+  }
+
+}
+
+#endif //  GMM_SUB_MATRIX_H__
diff --git a/Contrib/gmm/gmm_sub_vector.h b/Contrib/gmm/gmm_sub_vector.h
new file mode 100755
index 0000000..4f3292d
--- /dev/null
+++ b/Contrib/gmm/gmm_sub_vector.h
@@ -0,0 +1,557 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_sub_vector.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 13, 2002.
+   @brief Generic sub-vectors.
+*/
+
+#ifndef GMM_SUB_VECTOR_H__
+#define GMM_SUB_VECTOR_H__
+
+#include "gmm_interface.h"
+#include "gmm_sub_index.h"
+
+namespace gmm {
+
+  /* ********************************************************************* */
+  /*		sparse sub-vectors                                         */
+  /* ********************************************************************* */
+
+  template <typename IT, typename MIT, typename SUBI>
+  struct sparse_sub_vector_iterator {
+
+    IT itb, itbe;
+    SUBI si;
+
+    typedef std::iterator_traits<IT>                traits_type;
+    typedef typename traits_type::value_type        value_type;
+    typedef typename traits_type::pointer           pointer;
+    typedef typename traits_type::reference         reference;
+    typedef typename traits_type::difference_type   difference_type;
+    typedef std::bidirectional_iterator_tag         iterator_category;
+    typedef size_t                                  size_type;
+    typedef sparse_sub_vector_iterator<IT, MIT, SUBI>    iterator;
+
+    size_type index(void) const { return si.rindex(itb.index()); }
+    void forward(void);
+    void backward(void);
+    iterator &operator ++()
+    { ++itb; forward(); return *this; }
+    iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
+    iterator &operator --()
+    { --itb; backward(); return *this; }
+    iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
+    reference operator *() const { return *itb; }
+
+    bool operator ==(const iterator &i) const { return itb == i.itb; }
+    bool operator !=(const iterator &i) const { return !(i == *this); }
+
+    sparse_sub_vector_iterator(void) {}
+    sparse_sub_vector_iterator(const IT &it, const IT &ite, const SUBI &s)
+      : itb(it), itbe(ite), si(s) { forward(); }
+    sparse_sub_vector_iterator(const sparse_sub_vector_iterator<MIT, MIT,
+	 SUBI> &it) : itb(it.itb), itbe(it.itbe), si(it.si) {}
+  };
+
+  template <typename IT, typename MIT, typename SUBI>
+  void  sparse_sub_vector_iterator<IT, MIT, SUBI>::forward(void)
+  { while(itb!=itbe && index()==size_type(-1)) { ++itb; } }
+
+  template <typename IT, typename MIT, typename SUBI>
+  void  sparse_sub_vector_iterator<IT, MIT, SUBI>::backward(void)
+  { while(itb!=itbe && index()==size_type(-1)) --itb; }
+
+  template <typename PT, typename SUBI> struct sparse_sub_vector {
+    typedef sparse_sub_vector<PT, SUBI> this_type;
+    typedef typename std::iterator_traits<PT>::value_type V;
+    typedef V * CPT;
+    typedef typename select_ref<typename linalg_traits<V>::const_iterator,
+            typename linalg_traits<V>::iterator, PT>::ref_type iterator;
+    typedef typename linalg_traits<this_type>::reference reference;
+    typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+    iterator begin_, end_;
+    porigin_type origin;
+    SUBI si;
+
+    size_type size(void) const { return si.size(); }
+   
+    reference operator[](size_type i) const
+    { return linalg_traits<V>::access(origin, begin_, end_, si.index(i)); }
+
+    sparse_sub_vector(V &v, const SUBI &s) : begin_(vect_begin(v)),
+       end_(vect_end(v)), origin(linalg_origin(v)), si(s) {}
+    sparse_sub_vector(const V &v, const SUBI &s) 
+      : begin_(vect_begin(const_cast<V &>(v))),
+       end_(vect_end(const_cast<V &>(v))),
+	origin(linalg_origin(const_cast<V &>(v))), si(s) {}
+    sparse_sub_vector() {}
+    sparse_sub_vector(const sparse_sub_vector<CPT, SUBI> &cr)
+      : begin_(cr.begin_),end_(cr.end_),origin(cr.origin), si(cr.si) {} 
+  };
+
+  template <typename IT, typename MIT, typename SUBI, typename ORG,
+	    typename PT> inline
+  void set_to_begin(sparse_sub_vector_iterator<IT, MIT, SUBI> &it,
+		    ORG o, sparse_sub_vector<PT, SUBI> *,
+		    linalg_modifiable) {
+    typedef sparse_sub_vector<PT, SUBI> VECT;
+    typedef typename linalg_traits<VECT>::V_reference ref_t;
+    set_to_begin(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+    set_to_end(it.itbe, o, typename linalg_traits<VECT>::pV(), ref_t());
+    it.forward();
+  }
+  template <typename IT, typename MIT, typename SUBI, typename ORG,
+	    typename PT> inline
+  void set_to_begin(sparse_sub_vector_iterator<IT, MIT, SUBI> &it,
+		    ORG o, const sparse_sub_vector<PT, SUBI> *, 
+		    linalg_modifiable) {
+    typedef sparse_sub_vector<PT, SUBI> VECT;
+    typedef typename linalg_traits<VECT>::V_reference ref_t;
+    set_to_begin(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+    set_to_end(it.itbe, o, typename linalg_traits<VECT>::pV(), ref_t());
+    it.forward();
+  }
+  
+  template <typename IT, typename MIT, typename SUBI, typename ORG,
+	    typename PT> inline
+  void set_to_end(sparse_sub_vector_iterator<IT, MIT, SUBI> &it,
+		    ORG o, sparse_sub_vector<PT, SUBI> *, linalg_modifiable) {
+    typedef sparse_sub_vector<PT, SUBI> VECT;
+    typedef typename linalg_traits<VECT>::V_reference ref_t;
+    set_to_end(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+    set_to_end(it.itbe, o, typename linalg_traits<VECT>::pV(), ref_t());
+    it.forward();
+  }
+  template <typename IT, typename MIT, typename SUBI, typename ORG,
+	    typename PT> inline
+  void set_to_end(sparse_sub_vector_iterator<IT, MIT, SUBI> &it,
+		    ORG o, const sparse_sub_vector<PT, SUBI> *,
+		  linalg_modifiable) {
+    typedef sparse_sub_vector<PT, SUBI> VECT;
+    typedef typename linalg_traits<VECT>::V_reference ref_t;
+    set_to_end(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+    set_to_end(it.itbe, o, typename linalg_traits<VECT>::pV(), ref_t());
+    it.forward();
+  }
+
+  template <typename PT, typename SUBI>
+  struct linalg_traits<sparse_sub_vector<PT, SUBI> > {
+    typedef sparse_sub_vector<PT, SUBI> this_type;
+    typedef this_type * pthis_type;
+    typedef PT pV;
+    typedef typename std::iterator_traits<PT>::value_type V;
+    typedef typename linalg_and<typename index_is_sorted<SUBI>::bool_type,
+	    typename linalg_traits<V>::index_sorted>::bool_type index_sorted;
+    typedef typename linalg_traits<V>::is_reference V_reference;
+    typedef typename linalg_traits<V>::origin_type origin_type;
+    typedef typename select_ref<const origin_type *, origin_type *,
+			        PT>::ref_type porigin_type;
+    typedef typename which_reference<PT>::is_reference is_reference;
+    typedef abstract_vector linalg_type;
+    typedef typename linalg_traits<V>::value_type value_type;
+    typedef typename select_ref<value_type, typename
+            linalg_traits<V>::reference, PT>::ref_type reference;
+    typedef typename select_ref<typename linalg_traits<V>::const_iterator,
+	    typename linalg_traits<V>::iterator, PT>::ref_type pre_iterator;
+    typedef typename select_ref<abstract_null_type, 
+	    sparse_sub_vector_iterator<pre_iterator, pre_iterator, SUBI>,
+	    PT>::ref_type iterator;
+    typedef sparse_sub_vector_iterator<typename linalg_traits<V>
+            ::const_iterator, pre_iterator, SUBI> const_iterator;
+    typedef abstract_sparse storage_type;
+    static size_type size(const this_type &v) { return v.size(); }
+    static iterator begin(this_type &v) {
+      iterator it;
+      it.itb = v.begin_; it.itbe = v.end_; it.si = v.si;
+      if (!is_const_reference(is_reference()))
+	set_to_begin(it, v.origin, pthis_type(), is_reference());
+      else it.forward();
+      return it;
+    }
+    static const_iterator begin(const this_type &v) {
+      const_iterator it; it.itb = v.begin_; it.itbe = v.end_; it.si = v.si;
+      if (!is_const_reference(is_reference()))
+	{ set_to_begin(it, v.origin, pthis_type(), is_reference()); }
+      else it.forward();
+      return it;
+    }
+    static iterator end(this_type &v) {
+      iterator it;
+      it.itb = v.end_; it.itbe = v.end_; it.si = v.si;
+      if (!is_const_reference(is_reference()))
+	set_to_end(it, v.origin, pthis_type(), is_reference());
+      else it.forward();
+      return it;
+    }
+    static const_iterator end(const this_type &v) {
+      const_iterator it; it.itb = v.end_; it.itbe = v.end_; it.si = v.si;
+      if (!is_const_reference(is_reference()))
+	set_to_end(it, v.origin, pthis_type(), is_reference());
+      else it.forward();
+      return it;
+    }
+    static origin_type* origin(this_type &v) { return v.origin; }
+    static const origin_type* origin(const this_type &v) { return v.origin; }
+    static void clear(origin_type* o, const iterator &begin_,
+		      const iterator &end_) {
+      std::deque<size_type> ind;
+      iterator it = begin_;
+      for (; it != end_; ++it) ind.push_front(it.index());
+      for (; !(ind.empty()); ind.pop_back())
+	access(o, begin_, end_, ind.back()) = value_type(0);
+    }
+    static void do_clear(this_type &v) { clear(v.origin, begin(v), end(v)); }
+    static value_type access(const origin_type *o, const const_iterator &it,
+			     const const_iterator &ite, size_type i)
+    { return linalg_traits<V>::access(o, it.itb, ite.itb, it.si.index(i)); }
+    static reference access(origin_type *o, const iterator &it,
+			    const iterator &ite, size_type i)
+    { return linalg_traits<V>::access(o, it.itb, ite.itb, it.si.index(i)); }
+  };
+
+  template <typename PT, typename SUBI> std::ostream &operator <<
+  (std::ostream &o, const sparse_sub_vector<PT, SUBI>& m)
+  { gmm::write(o,m); return o; }
+
+  /* ********************************************************************* */
+  /*		skyline sub-vectors                                        */
+  /* ********************************************************************* */
+
+    template <typename IT, typename MIT, typename SUBI>
+  struct skyline_sub_vector_iterator {
+
+    IT itb;
+    SUBI si;
+
+    typedef std::iterator_traits<IT>                traits_type;
+    typedef typename traits_type::value_type        value_type;
+    typedef typename traits_type::pointer           pointer;
+    typedef typename traits_type::reference         reference;
+    typedef typename traits_type::difference_type   difference_type;
+    typedef std::bidirectional_iterator_tag         iterator_category;
+    typedef size_t                                  size_type;
+    typedef skyline_sub_vector_iterator<IT, MIT, SUBI>    iterator;
+
+    size_type index(void) const
+    { return (itb.index() - si.min + si.step() - 1) / si.step(); }
+    void backward(void);
+    iterator &operator ++()
+    { itb += si.step(); return *this; }
+    iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
+    iterator &operator --()
+    { itb -= si.step(); return *this; }
+    iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
+
+    iterator &operator +=(difference_type i)
+    { itb += si.step() * i; return *this; }
+    iterator &operator -=(difference_type i)
+    { itb -= si.step() * i; return *this; }
+    iterator operator +(difference_type i) const
+    { iterator ii = *this; return (ii += i); }
+    iterator operator -(difference_type i) const
+    { iterator ii = *this; return (ii -= i); }
+    difference_type operator -(const iterator &i) const
+    { return (itb - i.itb) / si.step(); }
+
+    reference operator *() const  { return *itb; }
+    reference operator [](int ii) { return *(itb + ii * si.step());  }
+
+    bool operator ==(const iterator &i) const { return index() == i.index();}
+    bool operator !=(const iterator &i) const { return !(i == *this); }
+    bool operator < (const iterator &i) const { return index()  < i.index();}
+
+    skyline_sub_vector_iterator(void) {}
+    skyline_sub_vector_iterator(const IT &it, const SUBI &s)
+      : itb(it), si(s) {}
+    skyline_sub_vector_iterator(const skyline_sub_vector_iterator<MIT, MIT,
+	 SUBI> &it) : itb(it.itb), si(it.si) {}
+  };
+
+  template <typename IT, typename SUBI>
+  void update_for_sub_skyline(IT &it, IT &ite, const SUBI &si) {
+    if (it.index() >= si.max || ite.index() <= si.min) { it = ite; return; }
+    ptrdiff_t dec1 = si.min - it.index(), dec2 = ite.index() - si.max;
+    it  += (dec1 < 0) ? ((si.step()-((-dec1) % si.step())) % si.step()) : dec1;
+    ite -= (dec2 < 0) ? -((-dec2) % si.step()) : dec2;
+  }
+
+  template <typename PT, typename SUBI> struct skyline_sub_vector {
+    typedef skyline_sub_vector<PT, SUBI> this_type;
+    typedef typename std::iterator_traits<PT>::value_type V;
+    typedef V * pV;
+    typedef typename select_ref<typename linalg_traits<V>::const_iterator,
+            typename linalg_traits<V>::iterator, PT>::ref_type iterator;
+    typedef typename linalg_traits<this_type>::reference reference;
+    typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+    iterator begin_, end_;
+    porigin_type origin;
+    SUBI si;
+
+    size_type size(void) const { return si.size(); }
+   
+    reference operator[](size_type i) const
+    { return linalg_traits<V>::access(origin, begin_, end_, si.index(i)); }
+
+    skyline_sub_vector(V &v, const SUBI &s) : begin_(vect_begin(v)),
+       end_(vect_end(v)), origin(linalg_origin(v)), si(s) {
+      update_for_sub_skyline(begin_, end_, si);
+    }
+    skyline_sub_vector(const V &v, const SUBI &s)
+      : begin_(vect_begin(const_cast<V &>(v))),
+	end_(vect_end(const_cast<V &>(v))),
+	origin(linalg_origin(const_cast<V &>(v))), si(s) {
+      update_for_sub_skyline(begin_, end_, si);
+    }
+    skyline_sub_vector() {}
+    skyline_sub_vector(const skyline_sub_vector<pV, SUBI> &cr)
+      : begin_(cr.begin_),end_(cr.end_),origin(cr.origin), si(cr.si) {}
+  };
+
+  template <typename IT, typename MIT, typename SUBI, typename ORG,
+	    typename PT> inline
+  void set_to_begin(skyline_sub_vector_iterator<IT, MIT, SUBI> &it,
+		    ORG o, skyline_sub_vector<PT, SUBI> *,
+		    linalg_modifiable) {
+    typedef skyline_sub_vector<PT, SUBI> VECT;
+    typedef typename linalg_traits<VECT>::V_reference ref_t;
+    IT itbe = it.itb;
+    set_to_begin(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+    set_to_end(itbe, o, typename linalg_traits<VECT>::pV(), ref_t());
+    update_for_sub_skyline(it.itb, itbe, it.si);
+  }
+  template <typename IT, typename MIT, typename SUBI, typename ORG,
+	    typename PT> inline
+  void set_to_begin(skyline_sub_vector_iterator<IT, MIT, SUBI> &it,
+		    ORG o, const skyline_sub_vector<PT, SUBI> *,
+		    linalg_modifiable) {
+    typedef skyline_sub_vector<PT, SUBI> VECT;
+    typedef typename linalg_traits<VECT>::V_reference ref_t;
+    IT itbe = it.itb;
+    set_to_begin(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+    set_to_end(itbe, o, typename linalg_traits<VECT>::pV(), ref_t());
+    update_for_sub_skyline(it.itb, itbe, it.si);
+  }
+  
+  template <typename IT, typename MIT, typename SUBI, typename ORG,
+	    typename PT> inline
+  void set_to_end(skyline_sub_vector_iterator<IT, MIT, SUBI> &it,
+		    ORG o, skyline_sub_vector<PT, SUBI> *,
+		  linalg_modifiable) {
+    typedef skyline_sub_vector<PT, SUBI> VECT;
+    typedef typename linalg_traits<VECT>::V_reference ref_t;
+    IT itb = it.itb;
+    set_to_begin(itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+    set_to_end(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+    update_for_sub_skyline(itb, it.itb, it.si);
+  }
+  template <typename IT, typename MIT, typename SUBI, typename ORG,
+	    typename PT> inline
+  void set_to_end(skyline_sub_vector_iterator<IT, MIT, SUBI> &it,
+		    ORG o, const skyline_sub_vector<PT, SUBI> *,
+		  linalg_modifiable) {
+    typedef skyline_sub_vector<PT, SUBI> VECT;
+    typedef typename linalg_traits<VECT>::V_reference ref_t;
+    IT itb = it.itb;
+    set_to_begin(itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+    set_to_end(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
+    update_for_sub_skyline(itb, it.itb, it.si);   
+  }
+
+
+  template <typename PT, typename SUBI>
+  struct linalg_traits<skyline_sub_vector<PT, SUBI> > {
+    typedef skyline_sub_vector<PT, SUBI> this_type;
+    typedef this_type *pthis_type;
+    typedef typename std::iterator_traits<PT>::value_type V;
+    typedef typename linalg_traits<V>::is_reference V_reference;
+    typedef typename linalg_traits<V>::origin_type origin_type;
+    typedef typename select_ref<const origin_type *, origin_type *,
+			        PT>::ref_type porigin_type;
+    typedef V * pV;
+    typedef typename which_reference<PT>::is_reference is_reference;
+    typedef abstract_vector linalg_type;
+    typedef typename linalg_traits<V>::value_type value_type;
+    typedef typename select_ref<value_type, typename
+            linalg_traits<V>::reference, PT>::ref_type reference;
+    typedef typename linalg_traits<V>::const_iterator const_V_iterator;
+    typedef typename linalg_traits<V>::iterator V_iterator;    
+    typedef typename select_ref<const_V_iterator, V_iterator, 
+				PT>::ref_type pre_iterator;
+    typedef typename select_ref<abstract_null_type, 
+	    skyline_sub_vector_iterator<pre_iterator, pre_iterator, SUBI>,
+	    PT>::ref_type iterator;
+    typedef skyline_sub_vector_iterator<const_V_iterator, pre_iterator, SUBI>
+            const_iterator;
+    typedef abstract_skyline storage_type;
+    typedef linalg_true index_sorted;
+    static size_type size(const this_type &v) { return v.size(); }
+    static iterator begin(this_type &v) {
+      iterator it;
+      it.itb = v.begin_; it.si = v.si;
+      if (!is_const_reference(is_reference()))
+	set_to_begin(it, v.origin, pthis_type(), is_reference());
+      return it;
+    }
+    static const_iterator begin(const this_type &v) {
+      const_iterator it; it.itb = v.begin_; it.si = v.si;
+      if (!is_const_reference(is_reference()))
+	{ set_to_begin(it, v.origin, pthis_type(), is_reference()); }
+      return it;
+    }
+    static iterator end(this_type &v) {
+      iterator it;
+      it.itb = v.end_; it.si = v.si;
+      if (!is_const_reference(is_reference()))
+	set_to_end(it, v.origin, pthis_type(), is_reference());
+      return it;
+    }
+    static const_iterator end(const this_type &v) {
+      const_iterator it; it.itb = v.end_; it.si = v.si;
+      if (!is_const_reference(is_reference()))
+	set_to_end(it, v.origin, pthis_type(), is_reference());
+      return it;
+    }
+    static origin_type* origin(this_type &v) { return v.origin; }
+    static const origin_type* origin(const this_type &v) { return v.origin; }
+    static void clear(origin_type*, const iterator &it, const iterator &ite)
+    { std::fill(it, ite, value_type(0)); }
+    static void do_clear(this_type &v) { clear(v.origin, begin(v), end(v)); }
+    static value_type access(const origin_type *o, const const_iterator &it,
+			     const const_iterator &ite, size_type i)
+    { return linalg_traits<V>::access(o, it.itb, ite.itb, it.si.index(i)); }
+    static reference access(origin_type *o, const iterator &it,
+			    const iterator &ite, size_type i)
+    { return linalg_traits<V>::access(o, it.itb, ite.itb, it.si.index(i)); }
+  };
+
+  template <typename PT, typename SUBI> std::ostream &operator <<
+  (std::ostream &o, const skyline_sub_vector<PT, SUBI>& m)
+  { gmm::write(o,m); return o; }
+
+  /* ******************************************************************** */
+  /*		sub vector.                                               */
+  /* ******************************************************************** */
+  /* sub_vector_type<PT, SUBI>::vector_type is the sub vector type        */
+  /* returned by sub_vector(v, sub_index)                                 */
+  /************************************************************************/
+
+  template <typename PT, typename SUBI, typename st_type> struct svrt_ir {
+    typedef abstract_null_type vector_type;
+  };
+
+  template <typename PT>
+  struct svrt_ir<PT, sub_index, abstract_dense> {
+    typedef typename std::iterator_traits<PT>::value_type V;
+    typedef typename vect_ref_type<PT,  V>::iterator iterator;
+    typedef tab_ref_index_ref_with_origin<iterator,
+      sub_index::const_iterator, V> vector_type;
+  }; 
+
+  template <typename PT>
+  struct svrt_ir<PT, unsorted_sub_index, abstract_dense> {
+    typedef typename std::iterator_traits<PT>::value_type V;
+    typedef typename vect_ref_type<PT,  V>::iterator iterator;
+    typedef tab_ref_index_ref_with_origin<iterator,
+      unsorted_sub_index::const_iterator, V> vector_type;
+  }; 
+
+  template <typename PT>
+  struct svrt_ir<PT, sub_interval, abstract_dense> {
+    typedef typename std::iterator_traits<PT>::value_type V;
+    typedef typename vect_ref_type<PT,  V>::iterator iterator;
+    typedef tab_ref_with_origin<iterator, V> vector_type;
+  }; 
+
+  template <typename PT>
+  struct svrt_ir<PT, sub_slice, abstract_dense> {
+    typedef typename std::iterator_traits<PT>::value_type V;
+    typedef typename vect_ref_type<PT,  V>::iterator iterator;
+    typedef tab_ref_reg_spaced_with_origin<iterator, V> vector_type;
+  };
+
+  template <typename PT, typename SUBI>
+  struct svrt_ir<PT, SUBI, abstract_skyline> {
+    typedef skyline_sub_vector<PT, SUBI> vector_type;
+  };
+
+  template <typename PT>
+  struct svrt_ir<PT, sub_index, abstract_skyline> {
+    typedef sparse_sub_vector<PT, sub_index> vector_type;
+  };
+
+  template <typename PT>
+  struct svrt_ir<PT, unsorted_sub_index, abstract_skyline> {
+    typedef sparse_sub_vector<PT, unsorted_sub_index> vector_type;
+  };
+
+
+  template <typename PT, typename SUBI>
+  struct svrt_ir<PT, SUBI, abstract_sparse> {
+    typedef sparse_sub_vector<PT, SUBI> vector_type;
+  };
+
+  template <typename PT, typename SUBI>
+  struct sub_vector_type {
+    typedef typename std::iterator_traits<PT>::value_type V;
+    typedef typename svrt_ir<PT, SUBI,
+      typename linalg_traits<V>::storage_type>::vector_type vector_type;
+  };
+
+  template <typename V, typename SUBI>
+  typename select_return<
+    typename sub_vector_type<const V *, SUBI>::vector_type,
+    typename sub_vector_type<V *, SUBI>::vector_type, const V *>::return_type
+  sub_vector(const V &v, const SUBI &si) {
+    GMM_ASSERT2(si.last() <= vect_size(v), "sub vector too large");
+    return typename select_return<
+      typename sub_vector_type<const V *, SUBI>::vector_type,
+      typename sub_vector_type<V *, SUBI>::vector_type, const V *>::return_type
+      (linalg_cast(v), si);
+  }
+
+  template <typename V, typename SUBI>
+  typename select_return<
+    typename sub_vector_type<const V *, SUBI>::vector_type,
+    typename sub_vector_type<V *, SUBI>::vector_type, V *>::return_type
+  sub_vector(V &v, const SUBI &si) {
+    GMM_ASSERT2(si.last() <= vect_size(v), "sub vector too large");
+    return  typename select_return<
+      typename sub_vector_type<const V *, SUBI>::vector_type,
+      typename sub_vector_type<V *, SUBI>::vector_type, V *>::return_type
+      (linalg_cast(v), si);
+  }
+
+}
+
+#endif //  GMM_SUB_VECTOR_H__
diff --git a/Contrib/gmm/gmm_superlu_interface.h b/Contrib/gmm/gmm_superlu_interface.h
new file mode 100755
index 0000000..eb32435
--- /dev/null
+++ b/Contrib/gmm/gmm_superlu_interface.h
@@ -0,0 +1,406 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_superlu_interface.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 17, 2003.
+   @brief Interface with SuperLU (LU direct solver for sparse matrices).
+*/
+#if defined(GMM_USES_SUPERLU) && !defined(GETFEM_VERSION)
+
+#ifndef GMM_SUPERLU_INTERFACE_H
+#define GMM_SUPERLU_INTERFACE_H
+
+#include "gmm_kernel.h"
+
+typedef int int_t;
+
+/* because SRC/util.h defines TRUE and FALSE ... */
+#ifdef TRUE
+# undef TRUE
+#endif
+#ifdef FALSE
+# undef FALSE
+#endif
+
+#include "SRC/slu_Cnames.h"
+#include "SRC/supermatrix.h"
+#include "SRC/slu_util.h"
+
+namespace SuperLU_S {
+#include "SRC/slu_sdefs.h"
+}
+namespace SuperLU_D {
+#include "SRC/slu_ddefs.h"
+}
+namespace SuperLU_C {
+#include "SRC/slu_cdefs.h"
+}
+namespace SuperLU_Z {
+#include "SRC/slu_zdefs.h" 
+}
+
+
+
+namespace gmm {
+
+  /*  interface for Create_CompCol_Matrix */
+
+  inline void Create_CompCol_Matrix(SuperMatrix *A, int m, int n, int nnz,
+			     float *a, int *ir, int *jc) {
+    SuperLU_S::sCreate_CompCol_Matrix(A, m, n, nnz, a, ir, jc,
+				      SLU_NC, SLU_S, SLU_GE);
+  }
+  
+  inline void Create_CompCol_Matrix(SuperMatrix *A, int m, int n, int nnz,
+			     double *a, int *ir, int *jc) {
+    SuperLU_D::dCreate_CompCol_Matrix(A, m, n, nnz, a, ir, jc,
+				      SLU_NC, SLU_D, SLU_GE);
+  }
+  
+  inline void Create_CompCol_Matrix(SuperMatrix *A, int m, int n, int nnz,
+			     std::complex<float> *a, int *ir, int *jc) {
+    SuperLU_C::cCreate_CompCol_Matrix(A, m, n, nnz, (SuperLU_C::complex *)(a),
+				      ir, jc, SLU_NC, SLU_C, SLU_GE);
+  }
+  
+  inline void Create_CompCol_Matrix(SuperMatrix *A, int m, int n, int nnz,
+			     std::complex<double> *a, int *ir, int *jc) {
+    SuperLU_Z::zCreate_CompCol_Matrix(A, m, n, nnz,
+				      (SuperLU_Z::doublecomplex *)(a), ir, jc,
+				      SLU_NC, SLU_Z, SLU_GE);
+  }
+
+  /*  interface for Create_Dense_Matrix */
+
+  inline void Create_Dense_Matrix(SuperMatrix *A, int m, int n, float *a, int k)
+  { SuperLU_S::sCreate_Dense_Matrix(A, m, n, a, k, SLU_DN, SLU_S, SLU_GE); }
+  inline void Create_Dense_Matrix(SuperMatrix *A, int m, int n, double *a, int k)
+  { SuperLU_D::dCreate_Dense_Matrix(A, m, n, a, k, SLU_DN, SLU_D, SLU_GE); }
+  inline void Create_Dense_Matrix(SuperMatrix *A, int m, int n,
+			   std::complex<float> *a, int k) {
+    SuperLU_C::cCreate_Dense_Matrix(A, m, n, (SuperLU_C::complex *)(a),
+				    k, SLU_DN, SLU_C, SLU_GE);
+  }
+  inline void Create_Dense_Matrix(SuperMatrix *A, int m, int n, 
+			   std::complex<double> *a, int k) {
+    SuperLU_Z::zCreate_Dense_Matrix(A, m, n, (SuperLU_Z::doublecomplex *)(a),
+				    k, SLU_DN, SLU_Z, SLU_GE);
+  }
+
+  /*  interface for gssv */
+
+#define DECL_GSSV(NAMESPACE,FNAME,FLOATTYPE,KEYTYPE) \
+  inline void SuperLU_gssv(superlu_options_t *options, SuperMatrix *A, int *p, \
+  int *q, SuperMatrix *L, SuperMatrix *U, SuperMatrix *B,               \
+  SuperLUStat_t *stats, int *info, KEYTYPE) {                           \
+  NAMESPACE::FNAME(options, A, p, q, L, U, B, stats, info);             \
+  }
+
+  DECL_GSSV(SuperLU_S,sgssv,float,float)
+  DECL_GSSV(SuperLU_C,cgssv,float,std::complex<float>)
+  DECL_GSSV(SuperLU_D,dgssv,double,double)
+  DECL_GSSV(SuperLU_Z,zgssv,double,std::complex<double>)
+
+  /*  interface for gssvx */
+
+#define DECL_GSSVX(NAMESPACE,FNAME,FLOATTYPE,KEYTYPE) \
+    inline float SuperLU_gssvx(superlu_options_t *options, SuperMatrix *A,	\
+		     int *perm_c, int *perm_r, int *etree, char *equed,  \
+		     FLOATTYPE *R, FLOATTYPE *C, SuperMatrix *L,         \
+		     SuperMatrix *U, void *work, int lwork,              \
+		     SuperMatrix *B, SuperMatrix *X,                     \
+		     FLOATTYPE *recip_pivot_growth,                      \
+		     FLOATTYPE *rcond, FLOATTYPE *ferr, FLOATTYPE *berr, \
+		     SuperLUStat_t *stats, int *info, KEYTYPE) {         \
+    NAMESPACE::mem_usage_t mem_usage;                                    \
+    NAMESPACE::FNAME(options, A, perm_c, perm_r, etree, equed, R, C, L,  \
+		     U, work, lwork, B, X, recip_pivot_growth, rcond,    \
+		     ferr, berr, &mem_usage, stats, info);               \
+    return mem_usage.for_lu; /* bytes used by the factor storage */     \
+  }
+
+  DECL_GSSVX(SuperLU_S,sgssvx,float,float)
+  DECL_GSSVX(SuperLU_C,cgssvx,float,std::complex<float>)
+  DECL_GSSVX(SuperLU_D,dgssvx,double,double)
+  DECL_GSSVX(SuperLU_Z,zgssvx,double,std::complex<double>)
+
+  /* ********************************************************************* */
+  /*   SuperLU solve interface                                             */
+  /* ********************************************************************* */
+
+  template <typename MAT, typename VECTX, typename VECTB>
+  void SuperLU_solve(const MAT &A, const VECTX &X_, const VECTB &B,
+		     double& rcond_, int permc_spec = 3) {
+    VECTX &X = const_cast<VECTX &>(X_);
+    /*
+     * Get column permutation vector perm_c[], according to permc_spec:
+     *   permc_spec = 0: use the natural ordering 
+     *   permc_spec = 1: use minimum degree ordering on structure of A'*A
+     *   permc_spec = 2: use minimum degree ordering on structure of A'+A
+     *   permc_spec = 3: use approximate minimum degree column ordering
+     */
+    typedef typename linalg_traits<MAT>::value_type T;
+    typedef typename number_traits<T>::magnitude_type R;
+
+    int m = mat_nrows(A), n = mat_ncols(A), nrhs = 1, info = 0;
+
+    csc_matrix<T> csc_A(m, n); gmm::copy(A, csc_A);
+    std::vector<T> rhs(m), sol(m);
+    gmm::copy(B, rhs);
+
+    int nz = nnz(csc_A);
+    if ((2 * nz / n) >= m)
+      GMM_WARNING2("CAUTION : it seems that SuperLU has a problem"
+		  " for nearly dense sparse matrices");
+
+    superlu_options_t options;
+    set_default_options(&options);
+    options.ColPerm = NATURAL;
+    options.PrintStat = NO;
+    options.ConditionNumber = YES;
+    switch (permc_spec) {
+    case 1 : options.ColPerm = MMD_ATA; break;
+    case 2 : options.ColPerm = MMD_AT_PLUS_A; break;
+    case 3 : options.ColPerm = COLAMD; break;
+    }
+    SuperLUStat_t stat;
+    StatInit(&stat);
+
+    SuperMatrix SA, SL, SU, SB, SX; // SuperLU format.
+    Create_CompCol_Matrix(&SA, m, n, nz, csc_A.pr,
+			  (int *)(csc_A.ir), (int *)(csc_A.jc));
+    Create_Dense_Matrix(&SB, m, nrhs, &rhs[0], m);
+    Create_Dense_Matrix(&SX, m, nrhs, &sol[0], m);
+    memset(&SL,0,sizeof SL);
+    memset(&SU,0,sizeof SU);
+
+    std::vector<int> etree(n);
+    char equed[] = "B";
+    std::vector<R> Rscale(m),Cscale(n); // row scale factors
+    std::vector<R> ferr(nrhs), berr(nrhs);
+    R recip_pivot_gross, rcond;
+    std::vector<int> perm_r(m), perm_c(n);
+
+    SuperLU_gssvx(&options, &SA, &perm_c[0], &perm_r[0], 
+		  &etree[0] /* output */, equed /* output         */, 
+		  &Rscale[0] /* row scale factors (output)        */, 
+		  &Cscale[0] /* col scale factors (output)        */,
+		  &SL /* fact L (output)*/, &SU /* fact U (output)*/, 
+		  NULL /* work                                    */, 
+		  0 /* lwork: superlu auto allocates (input)      */, 
+		  &SB /* rhs */, &SX /* solution                  */,
+		  &recip_pivot_gross /* reciprocal pivot growth   */
+		  /* factor max_j( norm(A_j)/norm(U_j) ).         */,  
+		  &rcond /*estimate of the reciprocal condition   */
+		  /* number of the matrix A after equilibration   */,
+		  &ferr[0] /* estimated forward error             */,
+		  &berr[0] /* relative backward error             */,
+		  &stat, &info, T());
+    rcond_ = rcond;
+    Destroy_SuperMatrix_Store(&SB);
+    Destroy_SuperMatrix_Store(&SX);
+    Destroy_SuperMatrix_Store(&SA);
+    Destroy_SuperNode_Matrix(&SL);
+    Destroy_CompCol_Matrix(&SU);
+    StatFree(&stat);
+    GMM_ASSERT1(info == 0, "SuperLU solve failed: info=" << info);
+    gmm::copy(sol, X);
+  }
+
+  template <class T> class SuperLU_factor {
+    typedef typename number_traits<T>::magnitude_type R;
+
+    csc_matrix<T> csc_A;
+    mutable SuperMatrix SA, SL, SB, SU, SX;
+    mutable SuperLUStat_t stat;
+    mutable superlu_options_t options;
+    float memory_used;
+    mutable std::vector<int> etree, perm_r, perm_c;
+    mutable std::vector<R> Rscale, Cscale;
+    mutable std::vector<R> ferr, berr;
+    mutable std::vector<T> rhs;
+    mutable std::vector<T> sol;
+    mutable bool is_init;
+    mutable char equed;
+
+  public :
+    enum { LU_NOTRANSP, LU_TRANSP, LU_CONJUGATED };
+    void free_supermatrix(void);
+    template <class MAT> void build_with(const MAT &A,  int permc_spec = 3);
+    template <typename VECTX, typename VECTB> 
+    /* transp = LU_NOTRANSP   -> solves Ax = B
+       transp = LU_TRANSP     -> solves A'x = B
+       transp = LU_CONJUGATED -> solves conj(A)X = B */
+    void solve(const VECTX &X_, const VECTB &B, int transp=LU_NOTRANSP) const;
+    SuperLU_factor(void) { is_init = false; }
+    SuperLU_factor(const SuperLU_factor& other) {
+      GMM_ASSERT2(!(other.is_init),
+		 "copy of initialized SuperLU_factor is forbidden");
+      is_init = false;
+    }
+    SuperLU_factor& operator=(const SuperLU_factor& other) {
+      GMM_ASSERT2(!(other.is_init) && !is_init,
+		  "assignment of initialized SuperLU_factor is forbidden");
+      return *this;
+    }
+    ~SuperLU_factor() { free_supermatrix(); }
+    float memsize() { return memory_used; }
+  };
+
+
+  template <class T> void SuperLU_factor<T>::free_supermatrix(void) {
+      if (is_init) {
+	if (SB.Store) Destroy_SuperMatrix_Store(&SB);
+	if (SX.Store) Destroy_SuperMatrix_Store(&SX);
+	if (SA.Store) Destroy_SuperMatrix_Store(&SA);
+	if (SL.Store) Destroy_SuperNode_Matrix(&SL);
+	if (SU.Store) Destroy_CompCol_Matrix(&SU);
+      }
+    }
+
+    
+    template <class T> template <class MAT>
+    void SuperLU_factor<T>::build_with(const MAT &A,  int permc_spec) {
+    /*
+     * Get column permutation vector perm_c[], according to permc_spec:
+     *   permc_spec = 0: use the natural ordering 
+     *   permc_spec = 1: use minimum degree ordering on structure of A'*A
+     *   permc_spec = 2: use minimum degree ordering on structure of A'+A
+     *   permc_spec = 3: use approximate minimum degree column ordering
+     */
+      free_supermatrix();
+      int n = mat_nrows(A), m = mat_ncols(A), info = 0;
+      csc_A.init_with(A);
+
+      rhs.resize(m); sol.resize(m);
+      gmm::clear(rhs);
+      int nz = nnz(csc_A);
+
+      set_default_options(&options);
+      options.ColPerm = NATURAL;
+      options.PrintStat = NO;
+      options.ConditionNumber = NO;
+      switch (permc_spec) {
+      case 1 : options.ColPerm = MMD_ATA; break;
+      case 2 : options.ColPerm = MMD_AT_PLUS_A; break;
+      case 3 : options.ColPerm = COLAMD; break;
+      }
+      StatInit(&stat);
+      
+      Create_CompCol_Matrix(&SA, m, n, nz, csc_A.pr,
+			    (int *)(csc_A.ir), (int *)(csc_A.jc));
+      Create_Dense_Matrix(&SB, m, 0, &rhs[0], m);
+      Create_Dense_Matrix(&SX, m, 0, &sol[0], m);
+      memset(&SL,0,sizeof SL);
+      memset(&SU,0,sizeof SU);
+      equed = 'B';
+      Rscale.resize(m); Cscale.resize(n); etree.resize(n);
+      ferr.resize(1); berr.resize(1);
+      R recip_pivot_gross, rcond;
+      perm_r.resize(m); perm_c.resize(n);
+      memory_used = SuperLU_gssvx(&options, &SA, &perm_c[0], &perm_r[0], 
+		    &etree[0] /* output */, &equed /* output        */, 
+		    &Rscale[0] /* row scale factors (output)        */, 
+		    &Cscale[0] /* col scale factors (output)        */,
+		    &SL /* fact L (output)*/, &SU /* fact U (output)*/, 
+		    NULL /* work                                    */, 
+		    0 /* lwork: superlu auto allocates (input)      */, 
+		    &SB /* rhs */, &SX /* solution                  */,
+		    &recip_pivot_gross /* reciprocal pivot growth   */
+		    /* factor max_j( norm(A_j)/norm(U_j) ).         */,  
+		    &rcond /*estimate of the reciprocal condition   */
+		    /* number of the matrix A after equilibration   */,
+		    &ferr[0] /* estimated forward error             */,
+		    &berr[0] /* relative backward error             */,
+		    &stat, &info, T());
+      
+      Destroy_SuperMatrix_Store(&SB);
+      Destroy_SuperMatrix_Store(&SX);
+      Create_Dense_Matrix(&SB, m, 1, &rhs[0], m);
+      Create_Dense_Matrix(&SX, m, 1, &sol[0], m);
+      StatFree(&stat);
+
+      GMM_ASSERT1(info == 0, "SuperLU solve failed: info=" << info);
+      is_init = true;
+    }
+    
+    template <class T> template <typename VECTX, typename VECTB> 
+    void SuperLU_factor<T>::solve(const VECTX &X_, const VECTB &B,
+				  int transp) const {
+      VECTX &X = const_cast<VECTX &>(X_);
+      gmm::copy(B, rhs);
+      options.Fact = FACTORED;
+      options.IterRefine = NOREFINE;
+      switch (transp) {
+      case LU_NOTRANSP: options.Trans = NOTRANS; break;
+      case LU_TRANSP: options.Trans = TRANS; break;
+      case LU_CONJUGATED: options.Trans = CONJ; break;
+      default: GMM_ASSERT1(false, "invalid value for transposition option");
+      }
+      StatInit(&stat);
+      int info = 0;
+      R recip_pivot_gross, rcond;
+      SuperLU_gssvx(&options, &SA, &perm_c[0], &perm_r[0], 
+		    &etree[0] /* output */, &equed /* output        */, 
+		    &Rscale[0] /* row scale factors (output)        */, 
+		    &Cscale[0] /* col scale factors (output)        */,
+		    &SL /* fact L (output)*/, &SU /* fact U (output)*/, 
+		    NULL /* work                                    */, 
+		    0 /* lwork: superlu auto allocates (input)      */, 
+		    &SB /* rhs */, &SX /* solution                  */,
+		    &recip_pivot_gross /* reciprocal pivot growth   */
+		    /* factor max_j( norm(A_j)/norm(U_j) ).         */,  
+		    &rcond /*estimate of the reciprocal condition   */
+		    /* number of the matrix A after equilibration   */,
+		    &ferr[0] /* estimated forward error             */,
+		    &berr[0] /* relative backward error             */,
+		    &stat, &info, T());
+     StatFree(&stat);
+     GMM_ASSERT1(info == 0, "SuperLU solve failed: info=" << info);
+     gmm::copy(sol, X);
+    }
+
+  template <typename T, typename V1, typename V2> inline
+  void mult(const SuperLU_factor<T>& P, const V1 &v1, const V2 &v2) {
+    P.solve(v2,v1);
+  }
+
+  template <typename T, typename V1, typename V2> inline
+  void transposed_mult(const SuperLU_factor<T>& P,const V1 &v1,const V2 &v2) {
+    P.solve(v2, v1, SuperLU_factor<T>::LU_TRANSP);
+  }
+
+}
+
+  
+#endif // GMM_SUPERLU_INTERFACE_H
+
+#endif // GMM_USES_SUPERLU
diff --git a/Contrib/gmm/gmm_transposed.h b/Contrib/gmm/gmm_transposed.h
new file mode 100755
index 0000000..b5da665
--- /dev/null
+++ b/Contrib/gmm/gmm_transposed.h
@@ -0,0 +1,243 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_transposed.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date November 10, 2002.
+   @brief Generic transposed matrices
+*/
+#ifndef GMM_TRANSPOSED_H__
+#define GMM_TRANSPOSED_H__
+
+#include "gmm_def.h"
+
+namespace gmm {
+
+  /* ********************************************************************* */
+  /*		transposed reference                    		   */
+  /* ********************************************************************* */
+  
+  template <typename PT> struct  transposed_row_ref {
+    
+    typedef transposed_row_ref<PT> this_type;
+    typedef typename std::iterator_traits<PT>::value_type M;
+    typedef M * CPT;
+    typedef typename std::iterator_traits<PT>::reference ref_M;
+    typedef typename select_ref<typename linalg_traits<this_type>
+            ::const_col_iterator, typename linalg_traits<this_type>
+            ::col_iterator, PT>::ref_type iterator;
+    typedef typename linalg_traits<this_type>::reference reference;
+    typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+
+    iterator begin_, end_;
+    porigin_type origin;
+    size_type nr, nc;
+
+    transposed_row_ref(ref_M m)
+      : begin_(mat_row_begin(m)), end_(mat_row_end(m)),
+	origin(linalg_origin(m)), nr(mat_ncols(m)), nc(mat_nrows(m)) {}
+
+    transposed_row_ref(const transposed_row_ref<CPT> &cr) :
+      begin_(cr.begin_),end_(cr.end_), origin(cr.origin),nr(cr.nr),nc(cr.nc) {}
+
+    reference operator()(size_type i, size_type j) const
+    { return linalg_traits<M>::access(begin_+j, i); }
+  };
+
+  template <typename PT> struct linalg_traits<transposed_row_ref<PT> > {
+    typedef transposed_row_ref<PT> this_type;
+    typedef typename std::iterator_traits<PT>::value_type M;
+    typedef typename linalg_traits<M>::origin_type origin_type;
+    typedef typename select_ref<const origin_type *, origin_type *,
+			        PT>::ref_type porigin_type;
+    typedef typename which_reference<PT>::is_reference is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef typename linalg_traits<M>::value_type value_type;
+    typedef typename select_ref<value_type,
+            typename linalg_traits<M>::reference, PT>::ref_type reference;
+    typedef typename linalg_traits<M>::storage_type storage_type;
+    typedef abstract_null_type sub_row_type;
+    typedef abstract_null_type const_sub_row_type;
+    typedef abstract_null_type row_iterator;
+    typedef abstract_null_type const_row_iterator;
+    typedef typename linalg_traits<M>::const_sub_row_type const_sub_col_type;
+    typedef typename select_ref<abstract_null_type, typename
+            linalg_traits<M>::sub_row_type, PT>::ref_type sub_col_type;
+    typedef typename linalg_traits<M>::const_row_iterator const_col_iterator;
+    typedef typename select_ref<abstract_null_type, typename
+            linalg_traits<M>::row_iterator, PT>::ref_type col_iterator;
+    typedef col_major sub_orientation;
+    typedef typename linalg_traits<M>::index_sorted index_sorted;
+    static size_type ncols(const this_type &v) { return v.nc; }
+    static size_type nrows(const this_type &v) { return v.nr; }
+    static const_sub_col_type col(const const_col_iterator &it)
+    { return linalg_traits<M>::row(it); }
+    static sub_col_type col(const col_iterator &it)
+    { return linalg_traits<M>::row(it); }
+    static col_iterator col_begin(this_type &m) { return m.begin_; }
+    static col_iterator col_end(this_type &m) { return m.end_; }
+    static const_col_iterator col_begin(const this_type &m)
+    { return m.begin_; }
+    static const_col_iterator col_end(const this_type &m) { return m.end_; }
+    static origin_type* origin(this_type &v) { return v.origin; }
+    static const origin_type* origin(const this_type &v) { return v.origin; }
+    static void do_clear(this_type &v);
+    static value_type access(const const_col_iterator &itcol, size_type i)
+    { return linalg_traits<M>::access(itcol, i); }
+    static reference access(const col_iterator &itcol, size_type i)
+    { return linalg_traits<M>::access(itcol, i); }
+  };
+  
+  template <typename PT> 
+  void linalg_traits<transposed_row_ref<PT> >::do_clear(this_type &v) { 
+    col_iterator it = mat_col_begin(v), ite = mat_col_end(v);
+    for (; it != ite; ++it) clear(col(it));
+  }
+  
+  template<typename PT> std::ostream &operator <<
+  (std::ostream &o, const transposed_row_ref<PT>& m)
+  { gmm::write(o,m); return o; }
+
+  template <typename PT> struct  transposed_col_ref {
+    
+    typedef transposed_col_ref<PT> this_type;
+    typedef typename std::iterator_traits<PT>::value_type M;
+    typedef M * CPT;
+    typedef typename std::iterator_traits<PT>::reference ref_M;
+    typedef typename select_ref<typename linalg_traits<this_type>
+            ::const_row_iterator, typename linalg_traits<this_type>
+            ::row_iterator, PT>::ref_type iterator;
+    typedef typename linalg_traits<this_type>::reference reference;
+    typedef typename linalg_traits<this_type>::porigin_type porigin_type;
+    
+    iterator begin_, end_;
+    porigin_type origin;
+    size_type nr, nc;
+
+    transposed_col_ref(ref_M m)
+      : begin_(mat_col_begin(m)), end_(mat_col_end(m)),
+	origin(linalg_origin(m)), nr(mat_ncols(m)), nc(mat_nrows(m)) {}
+
+    transposed_col_ref(const transposed_col_ref<CPT> &cr) :
+      begin_(cr.begin_),end_(cr.end_), origin(cr.origin),nr(cr.nr),nc(cr.nc) {}
+
+    reference operator()(size_type i, size_type j) const
+    { return linalg_traits<M>::access(begin_+i, j); }
+  };
+
+  template <typename PT> struct linalg_traits<transposed_col_ref<PT> > {
+    typedef transposed_col_ref<PT> this_type;
+    typedef typename std::iterator_traits<PT>::value_type M;
+    typedef typename linalg_traits<M>::origin_type origin_type;
+    typedef typename select_ref<const origin_type *, origin_type *,
+			        PT>::ref_type porigin_type;
+    typedef typename which_reference<PT>::is_reference is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef typename linalg_traits<M>::value_type value_type;
+    typedef typename select_ref<value_type,
+            typename linalg_traits<M>::reference, PT>::ref_type reference;
+    typedef typename linalg_traits<M>::storage_type storage_type;
+    typedef abstract_null_type sub_col_type;
+    typedef abstract_null_type const_sub_col_type;
+    typedef abstract_null_type col_iterator;
+    typedef abstract_null_type const_col_iterator;
+    typedef typename linalg_traits<M>::const_sub_col_type const_sub_row_type;
+    typedef typename select_ref<abstract_null_type, typename
+            linalg_traits<M>::sub_col_type, PT>::ref_type sub_row_type;
+    typedef typename linalg_traits<M>::const_col_iterator const_row_iterator;
+    typedef typename select_ref<abstract_null_type, typename
+            linalg_traits<M>::col_iterator, PT>::ref_type row_iterator;
+    typedef row_major sub_orientation;
+    typedef typename linalg_traits<M>::index_sorted index_sorted;
+    static size_type nrows(const this_type &v)
+    { return v.nr; }
+    static size_type ncols(const this_type &v)
+    { return v.nc; }
+    static const_sub_row_type row(const const_row_iterator &it)
+    { return linalg_traits<M>::col(it); }
+    static sub_row_type row(const row_iterator &it)
+    { return linalg_traits<M>::col(it); }
+    static row_iterator row_begin(this_type &m) { return m.begin_; }
+    static row_iterator row_end(this_type &m) { return m.end_; }
+    static const_row_iterator row_begin(const this_type &m)
+    { return m.begin_; }
+    static const_row_iterator row_end(const this_type &m) { return m.end_; }
+    static origin_type* origin(this_type &v) { return v.origin; }
+    static const origin_type* origin(const this_type &v) { return v.origin; }
+    static void do_clear(this_type &m);
+    static value_type access(const const_row_iterator &itrow, size_type i)
+    { return linalg_traits<M>::access(itrow, i); }
+    static reference access(const row_iterator &itrow, size_type i)
+    { return linalg_traits<M>::access(itrow, i); }
+  };
+
+  template <typename PT> 
+  void linalg_traits<transposed_col_ref<PT> >::do_clear(this_type &v) { 
+    row_iterator it = mat_row_begin(v), ite = mat_row_end(v);
+    for (; it != ite; ++it) clear(row(it));
+  }
+
+  template<typename PT> std::ostream &operator <<
+  (std::ostream &o, const transposed_col_ref<PT>& m)
+  { gmm::write(o,m); return o; }
+
+  template <typename TYPE, typename PT> struct transposed_return_ {
+    typedef abstract_null_type return_type;
+  };
+  template <typename PT> struct transposed_return_<row_major, PT> {
+    typedef typename std::iterator_traits<PT>::value_type L;
+    typedef typename select_return<transposed_row_ref<const L *>,
+            transposed_row_ref< L *>, PT>::return_type return_type;
+  };
+  template <typename PT> struct transposed_return_<col_major, PT> {
+    typedef typename std::iterator_traits<PT>::value_type L;
+    typedef typename select_return<transposed_col_ref<const L *>,
+            transposed_col_ref< L *>, PT>::return_type return_type;
+  };
+  template <typename PT> struct transposed_return {
+    typedef typename std::iterator_traits<PT>::value_type L;
+    typedef typename transposed_return_<typename principal_orientation_type<
+            typename linalg_traits<L>::sub_orientation>::potype,
+	    PT>::return_type return_type;
+  };
+
+  template <typename L> inline 
+  typename transposed_return<const L *>::return_type transposed(const L &l) {
+    return typename transposed_return<const L *>::return_type
+      (linalg_cast(const_cast<L &>(l)));
+  }
+
+  template <typename L> inline 
+  typename transposed_return<L *>::return_type transposed(L &l)
+  { return typename transposed_return<L *>::return_type(linalg_cast(l)); }
+
+}
+
+#endif //  GMM_TRANSPOSED_H__
diff --git a/Contrib/gmm/gmm_tri_solve.h b/Contrib/gmm/gmm_tri_solve.h
new file mode 100755
index 0000000..2f7acf2
--- /dev/null
+++ b/Contrib/gmm/gmm_tri_solve.h
@@ -0,0 +1,221 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_tri_solve.h
+   @author Yves Renard
+   @date October 13, 2002.
+   @brief Solve triangular linear system for dense matrices.
+*/
+
+#ifndef GMM_TRI_SOLVE_H__
+#define GMM_TRI_SOLVE_H__
+
+#include "gmm_interface.h"
+
+namespace gmm {
+
+  template <typename TriMatrix, typename VecX>
+  void upper_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
+				col_major, abstract_sparse, bool is_unit) {
+    typename linalg_traits<TriMatrix>::value_type x_j;
+    for (int j = int(k) - 1; j >= 0; --j) {
+      typedef typename linalg_traits<TriMatrix>::const_sub_col_type COL;
+      COL c = mat_const_col(T, j);
+      typename linalg_traits<COL>::const_iterator 
+	it = vect_const_begin(c), ite = vect_const_end(c);
+      if (!is_unit) x[j] /= c[j];
+      for (x_j = x[j]; it != ite ; ++it)
+	if (int(it.index()) < j) x[it.index()] -= x_j * (*it);
+    }    
+  }
+
+  template <typename TriMatrix, typename VecX>
+  void upper_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
+				col_major, abstract_dense, bool is_unit) {
+    typename linalg_traits<TriMatrix>::value_type x_j;
+    for (int j = int(k) - 1; j >= 0; --j) {
+      typedef typename linalg_traits<TriMatrix>::const_sub_col_type COL;
+      COL c = mat_const_col(T, j);
+      typename linalg_traits<COL>::const_iterator
+	it = vect_const_begin(c), ite = it + j;
+      typename linalg_traits<VecX>::iterator itx = vect_begin(x);
+      if (!is_unit) x[j] /= c[j];
+      for (x_j = x[j]; it != ite ; ++it, ++itx) *itx -= x_j * (*it);
+    }
+  }
+
+  template <typename TriMatrix, typename VecX>
+  void lower_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
+				col_major, abstract_sparse, bool is_unit) {
+    typename linalg_traits<TriMatrix>::value_type x_j;
+    // cout << "(lower col)The Tri Matrix = " << T << endl;
+    // cout << "k = " << endl;
+    for (int j = 0; j < int(k); ++j) {
+      typedef typename linalg_traits<TriMatrix>::const_sub_col_type COL;
+      COL c = mat_const_col(T, j);
+      typename linalg_traits<COL>::const_iterator 
+	it = vect_const_begin(c), ite = vect_const_end(c);
+      if (!is_unit) x[j] /= c[j];
+      for (x_j = x[j]; it != ite ; ++it)
+	if (int(it.index()) > j && it.index() < k) x[it.index()] -= x_j*(*it);
+    }    
+  }
+  
+  template <typename TriMatrix, typename VecX>
+  void lower_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
+				col_major, abstract_dense, bool is_unit) {
+    typename linalg_traits<TriMatrix>::value_type x_j;
+    for (int j = 0; j < int(k); ++j) {
+      typedef typename linalg_traits<TriMatrix>::const_sub_col_type COL;
+      COL c = mat_const_col(T, j);
+      typename linalg_traits<COL>::const_iterator 
+	it = vect_const_begin(c) + (j+1), ite = vect_const_begin(c) + k;
+      typename linalg_traits<VecX>::iterator itx = vect_begin(x) + (j+1);
+      if (!is_unit) x[j] /= c[j];
+      for (x_j = x[j]; it != ite ; ++it, ++itx) *itx -= x_j * (*it);
+    }    
+  }
+  
+
+  template <typename TriMatrix, typename VecX>
+  void upper_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
+				row_major, abstract_sparse, bool is_unit) {
+    typedef typename linalg_traits<TriMatrix>::const_sub_row_type ROW;
+    typename linalg_traits<TriMatrix>::value_type t;
+    typename linalg_traits<TriMatrix>::const_row_iterator
+      itr = mat_row_const_end(T);
+    for (int i = int(k) - 1; i >= 0; --i) {
+      --itr;
+      ROW c = linalg_traits<TriMatrix>::row(itr);
+      typename linalg_traits<ROW>::const_iterator 
+	it = vect_const_begin(c), ite = vect_const_end(c);
+      for (t = x[i]; it != ite; ++it)
+	if (int(it.index()) > i && it.index() < k) t -= (*it) * x[it.index()];
+      if (!is_unit) x[i] = t / c[i]; else x[i] = t;    
+    }    
+  }
+
+  template <typename TriMatrix, typename VecX>
+  void upper_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
+				row_major, abstract_dense, bool is_unit) {
+    typename linalg_traits<TriMatrix>::value_type t;
+   
+    for (int i = int(k) - 1; i >= 0; --i) {
+      typedef typename linalg_traits<TriMatrix>::const_sub_row_type ROW;
+      ROW c = mat_const_row(T, i);
+      typename linalg_traits<ROW>::const_iterator 
+	it = vect_const_begin(c) + (i + 1), ite = vect_const_begin(c) + k;
+      typename linalg_traits<VecX>::iterator itx = vect_begin(x) + (i+1);
+      
+      for (t = x[i]; it != ite; ++it, ++itx) t -= (*it) * (*itx);
+      if (!is_unit) x[i] = t / c[i]; else x[i] = t;   
+    }    
+  }
+
+  template <typename TriMatrix, typename VecX>
+  void lower_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
+				row_major, abstract_sparse, bool is_unit) {
+    typename linalg_traits<TriMatrix>::value_type t;
+   
+    for (int i = 0; i < int(k); ++i) {
+      typedef typename linalg_traits<TriMatrix>::const_sub_row_type ROW;
+      ROW c = mat_const_row(T, i);
+      typename linalg_traits<ROW>::const_iterator 
+	it = vect_const_begin(c), ite = vect_const_end(c);
+
+      for (t = x[i]; it != ite; ++it)
+	if (int(it.index()) < i) t -= (*it) * x[it.index()];
+      if (!is_unit) x[i] = t / c[i]; else x[i] = t; 
+    }    
+  }
+
+  template <typename TriMatrix, typename VecX>
+  void lower_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
+				row_major, abstract_dense, bool is_unit) {
+    typename linalg_traits<TriMatrix>::value_type t;
+   
+    for (int i = 0; i < int(k); ++i) {
+      typedef typename linalg_traits<TriMatrix>::const_sub_row_type ROW;
+      ROW c = mat_const_row(T, i);
+      typename linalg_traits<ROW>::const_iterator 
+	it = vect_const_begin(c), ite = it + i;
+      typename linalg_traits<VecX>::iterator itx = vect_begin(x);
+
+      for (t = x[i]; it != ite; ++it, ++itx) t -= (*it) * (*itx);
+      if (!is_unit) x[i] = t / c[i]; else x[i] = t;
+    }
+  }
+
+
+// Triangular Solve:  x <-- T^{-1} * x
+
+  template <typename TriMatrix, typename VecX> inline
+  void upper_tri_solve(const TriMatrix& T, VecX &x_, bool is_unit = false)
+  { upper_tri_solve(T, x_, mat_nrows(T), is_unit); }
+  
+  template <typename TriMatrix, typename VecX> inline
+  void lower_tri_solve(const TriMatrix& T, VecX &x_, bool is_unit = false)
+  { lower_tri_solve(T, x_, mat_nrows(T), is_unit); }
+
+  template <typename TriMatrix, typename VecX> inline
+  void upper_tri_solve(const TriMatrix& T, VecX &x_, size_t k,
+		       bool is_unit) {
+    VecX& x = const_cast<VecX&>(x_);
+    GMM_ASSERT2(mat_nrows(T) >= k && vect_size(x) >= k
+		&& mat_ncols(T) >= k && !is_sparse(x_), "dimensions mismatch");
+    upper_tri_solve__(T, x, k, 
+		      typename principal_orientation_type<typename
+		      linalg_traits<TriMatrix>::sub_orientation>::potype(),
+		      typename linalg_traits<TriMatrix>::storage_type(),
+		      is_unit);
+  }
+  
+  template <typename TriMatrix, typename VecX> inline
+  void lower_tri_solve(const TriMatrix& T, VecX &x_, size_t k,
+		       bool is_unit) {
+    VecX& x = const_cast<VecX&>(x_);
+    GMM_ASSERT2(mat_nrows(T) >= k && vect_size(x) >= k
+		&& mat_ncols(T) >= k && !is_sparse(x_), "dimensions mismatch");
+    lower_tri_solve__(T, x, k, 
+		      typename principal_orientation_type<typename
+		      linalg_traits<TriMatrix>::sub_orientation>::potype(),
+		      typename linalg_traits<TriMatrix>::storage_type(),
+		      is_unit);
+  }
+
+
+ 
+
+
+
+}
+
+
+#endif //  GMM_TRI_SOLVE_H__
diff --git a/Contrib/gmm/gmm_vector.h b/Contrib/gmm/gmm_vector.h
new file mode 100755
index 0000000..f114a32
--- /dev/null
+++ b/Contrib/gmm/gmm_vector.h
@@ -0,0 +1,968 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2002-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+/**@file gmm_vector.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date October 13, 2002.
+   @brief Declaration of the vector types (gmm::rsvector, gmm::wsvector,
+     gmm::slvector ,..)
+*/
+#ifndef GMM_VECTOR_H__
+#define GMM_VECTOR_H__
+
+#include <map>
+#include "gmm_interface.h"
+
+namespace gmm {
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Class ref_elt_vector: reference on a vector component.                */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  template<typename T, typename V> class ref_elt_vector {
+
+    V *pm;
+    size_type l;
+    
+    public :
+
+    operator T() const { return pm->r(l); }
+    ref_elt_vector(V *p, size_type ll) : pm(p), l(ll) {}
+    inline ref_elt_vector &operator =(T v)
+      { (*pm).w(l,v); return *this; }
+    inline bool operator ==(T v) const { return ((*pm).r(l) == v); }
+    inline bool operator !=(T v) const { return ((*pm).r(l) != v); }
+    inline ref_elt_vector &operator +=(T v)
+      { (*pm).w(l,(*pm).r(l) + v); return *this; }
+    inline ref_elt_vector &operator -=(T v)
+      { (*pm).w(l,(*pm).r(l) - v); return *this; }
+    inline ref_elt_vector &operator /=(T v)
+      { (*pm).w(l,(*pm).r(l) / v); return *this; }
+    inline ref_elt_vector &operator *=(T v)
+      { (*pm).w(l,(*pm).r(l) * v); return *this; }
+    inline ref_elt_vector &operator =(const ref_elt_vector &re)
+      { *this = T(re); return *this; }
+    T operator +()    { return  T(*this);   } // necessary for unknow reason
+    T operator -()    { return -T(*this);   } // necessary for unknow reason
+    T operator +(T v) { return T(*this)+ v; } // necessary for unknow reason
+    T operator -(T v) { return T(*this)- v; } // necessary for unknow reason
+    T operator *(T v) { return T(*this)* v; } // necessary for unknow reason
+    T operator /(T v) { return T(*this)/ v; } // necessary for unknow reason
+  };  
+  
+  
+  template<typename T, typename V> inline
+  bool operator ==(T v, const ref_elt_vector<T, V> &re) { return (v==T(re)); }
+  template<typename T, typename V> inline
+  bool operator !=(T v, const ref_elt_vector<T, V> &re) { return (v!=T(re)); }
+  template<typename T, typename V> inline
+  T &operator +=(T &v, const ref_elt_vector<T, V> &re) 
+  { v += T(re); return v; }
+  template<typename T, typename V> inline
+  T &operator -=(T &v, const ref_elt_vector<T, V> &re)
+  { v -= T(re); return v; }
+  template<typename T, typename V> inline
+  T &operator *=(T &v, const ref_elt_vector<T, V> &re) 
+  { v *= T(re); return v; }
+  template<typename T, typename V> inline
+  T &operator /=(T &v, const ref_elt_vector<T, V> &re)
+  { v /= T(re); return v; }
+  template<typename T, typename V> inline
+  T operator +(const ref_elt_vector<T, V> &re) { return T(re); }
+  template<typename T, typename V> inline
+  T operator -(const ref_elt_vector<T, V> &re) { return -T(re); }
+  template<typename T, typename V> inline
+  T operator +(const ref_elt_vector<T, V> &re, T v) { return T(re)+ v; }
+  template<typename T, typename V> inline
+  T operator +(T v, const ref_elt_vector<T, V> &re) { return v+ T(re); }
+  template<typename T, typename V> inline
+  T operator -(const ref_elt_vector<T, V> &re, T v) { return T(re)- v; }
+  template<typename T, typename V> inline
+  T operator -(T v, const ref_elt_vector<T, V> &re) { return v- T(re); }
+  template<typename T, typename V>  inline
+  T operator *(const ref_elt_vector<T, V> &re, T v) { return T(re)* v; }
+  template<typename T, typename V> inline
+  T operator *(T v, const ref_elt_vector<T, V> &re) { return v* T(re); }
+  template<typename T, typename V> inline
+  T operator /(const ref_elt_vector<T, V> &re, T v) { return T(re)/ v; }
+  template<typename T, typename V> inline
+  T operator /(T v, const ref_elt_vector<T, V> &re) { return v/ T(re); }
+  template<typename T, typename V> inline
+  typename number_traits<T>::magnitude_type
+  abs(const ref_elt_vector<T, V> &re) { return gmm::abs(T(re)); }
+  template<typename T, typename V> inline
+  T sqr(const ref_elt_vector<T, V> &re) { return gmm::sqr(T(re)); }
+  template<typename T, typename V> inline
+  typename number_traits<T>::magnitude_type
+  abs_sqr(const ref_elt_vector<T, V> &re) { return gmm::abs_sqr(T(re)); }
+  template<typename T, typename V> inline
+  T conj(const ref_elt_vector<T, V> &re) { return gmm::conj(T(re)); }
+  template<typename T, typename V> std::ostream &operator <<
+  (std::ostream &o, const ref_elt_vector<T, V> &re) { o << T(re); return o; }
+  template<typename T, typename V> inline
+  typename number_traits<T>::magnitude_type
+  real(const ref_elt_vector<T, V> &re) { return gmm::real(T(re)); }
+  template<typename T, typename V> inline
+  typename number_traits<T>::magnitude_type
+  imag(const ref_elt_vector<T, V> &re) { return gmm::imag(T(re)); }
+
+  
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Class wsvector: sparse vector optimized for random write operations.  */
+  /*                                                                       */
+  /*************************************************************************/
+  
+  template<typename T> struct wsvector_iterator
+    : public std::map<size_type, T>::iterator {
+    typedef typename std::map<size_type, T>::iterator base_it_type;
+    typedef T                   value_type;
+    typedef value_type*         pointer;
+    typedef value_type&         reference;
+    // typedef size_t              size_type;
+    typedef ptrdiff_t           difference_type;
+    typedef std::bidirectional_iterator_tag iterator_category;
+    
+    reference operator *() const { return (base_it_type::operator*()).second; }
+    pointer operator->() const { return &(operator*()); }
+    size_type index(void) const { return (base_it_type::operator*()).first; }
+
+    wsvector_iterator(void) {}
+    wsvector_iterator(const base_it_type &it) : base_it_type(it) {}
+  };
+
+  template<typename T> struct wsvector_const_iterator
+    : public std::map<size_type, T>::const_iterator {
+    typedef typename std::map<size_type, T>::const_iterator base_it_type;
+    typedef T                   value_type;
+    typedef const value_type*   pointer;
+    typedef const value_type&   reference;
+    // typedef size_t              size_type;
+    typedef ptrdiff_t           difference_type;
+    typedef std::bidirectional_iterator_tag iterator_category;
+    
+    reference operator *() const { return (base_it_type::operator*()).second; }
+    pointer operator->() const { return &(operator*()); }
+    size_type index(void) const { return (base_it_type::operator*()).first; }
+
+    wsvector_const_iterator(void) {}
+    wsvector_const_iterator(const wsvector_iterator<T> &it)
+      : base_it_type(it) {}
+    wsvector_const_iterator(const base_it_type &it) : base_it_type(it) {}
+  };
+
+
+  /**
+     sparse vector built upon std::map.
+     Read and write access are quite fast (log n)
+  */
+  template<typename T> class wsvector : public std::map<size_type, T> {
+  public:
+    
+    typedef typename std::map<int, T>::size_type size_type;
+    typedef std::map<size_type, T> base_type;
+    typedef typename base_type::iterator iterator;
+    typedef typename base_type::const_iterator const_iterator;
+
+  protected:
+    size_type nbl;
+    
+  public:
+    void clean(double eps);
+    void resize(size_type);
+    
+    inline ref_elt_vector<T, wsvector<T> > operator [](size_type c)
+    { return ref_elt_vector<T, wsvector<T> >(this, c); }
+
+    inline void w(size_type c, const T &e) {
+      GMM_ASSERT2(c < nbl, "out of range");
+      if (e == T(0)) { base_type::erase(c); }
+      else base_type::operator [](c) = e;
+    }
+
+    inline T r(size_type c) const {
+      GMM_ASSERT2(c < nbl, "out of range");
+      const_iterator it = this->lower_bound(c);
+      if (it != this->end() && c == it->first) return it->second;
+      else return T(0);
+    }
+
+    inline T operator [](size_type c) const { return r(c); }
+    
+    size_type nb_stored(void) const { return base_type::size(); }
+    size_type size(void) const { return nbl; }
+
+    void swap(wsvector<T> &v)
+    { std::swap(nbl, v.nbl); std::map<size_type, T>::swap(v); }
+				       
+
+    /* Constructeurs */
+    void init(size_type l) { nbl = l; this->clear(); }
+    explicit wsvector(size_type l){ init(l); }
+    wsvector(void) { init(0); }
+  };
+
+  template<typename T>  void wsvector<T>::clean(double eps) {
+    iterator it = this->begin(), itf = it, ite = this->end();
+    while (it != ite) {
+      ++itf; if (gmm::abs(it->second) <= eps) erase(it); it = itf;
+    }
+  }
+
+  template<typename T>  void wsvector<T>::resize(size_type n) {
+    if (n < nbl) {
+      iterator it = this->begin(), itf = it, ite = this->end();
+      while (it != ite) { ++itf; if (it->first >= n) erase(it); it = itf; }
+    }
+    nbl = n;
+  }
+
+  template <typename T> struct linalg_traits<wsvector<T> > {
+    typedef wsvector<T> this_type;
+    typedef this_type origin_type;
+    typedef linalg_false is_reference;
+    typedef abstract_vector linalg_type;
+    typedef T value_type;
+    typedef ref_elt_vector<T, wsvector<T> > reference;
+    typedef wsvector_iterator<T>  iterator;
+    typedef wsvector_const_iterator<T> const_iterator;
+    typedef abstract_sparse storage_type;
+    typedef linalg_true index_sorted;
+    static size_type size(const this_type &v) { return v.size(); }
+    static iterator begin(this_type &v) { return v.begin(); }
+    static const_iterator begin(const this_type &v) { return v.begin(); }
+    static iterator end(this_type &v) { return v.end(); }
+    static const_iterator end(const this_type &v) { return v.end(); }
+    static origin_type* origin(this_type &v) { return &v; }
+    static const origin_type* origin(const this_type &v) { return &v; }
+    static void clear(origin_type* o, const iterator &, const iterator &)
+    { o->clear(); }
+    static void do_clear(this_type &v) { v.clear(); }
+    static value_type access(const origin_type *o, const const_iterator &,
+			     const const_iterator &, size_type i)
+    { return (*o)[i]; }
+    static reference access(origin_type *o, const iterator &, const iterator &,
+			    size_type i)
+    { return (*o)[i]; }
+    static void resize(this_type &v, size_type n) { v.resize(n); }
+  };
+
+  template<typename T> std::ostream &operator <<
+  (std::ostream &o, const wsvector<T>& v) { gmm::write(o,v); return o; }
+
+  /******* Optimized BLAS for wsvector<T> **********************************/
+
+  template <typename T> inline void copy(const wsvector<T> &v1,
+					 wsvector<T> &v2) {
+    GMM_ASSERT2(vect_size(v1) == vect_size(v2), "dimensions mismatch");
+    v2 = v1;
+  }
+  template <typename T> inline
+  void copy(const wsvector<T> &v1, const simple_vector_ref<wsvector<T> *> &v2){
+    simple_vector_ref<wsvector<T> *>
+      *svr = const_cast<simple_vector_ref<wsvector<T> *> *>(&v2);
+    wsvector<T>
+      *pv = const_cast<wsvector<T> *>(v2.origin);
+    GMM_ASSERT2(vect_size(v1) == vect_size(v2), "dimensions mismatch");
+    *pv = v1; svr->begin_ = vect_begin(*pv); svr->end_ = vect_end(*pv);
+  }
+  template <typename T> inline
+  void copy(const simple_vector_ref<const wsvector<T> *> &v1,
+	    wsvector<T> &v2)
+  { copy(*(v1.origin), v2); }
+  template <typename T> inline
+  void copy(const simple_vector_ref<wsvector<T> *> &v1, wsvector<T> &v2)
+  { copy(*(v1.origin), v2); }
+
+  template <typename T> inline void clean(wsvector<T> &v, double eps) {
+    typedef typename number_traits<T>::magnitude_type R;
+    typename wsvector<T>::iterator it = v.begin(), ite = v.end(), itc;
+    while (it != ite) 
+      if (gmm::abs((*it).second) <= R(eps))
+	{ itc=it; ++it; v.erase(itc); } else ++it; 
+  }
+
+  template <typename T>
+  inline void clean(const simple_vector_ref<wsvector<T> *> &l, double eps) {
+    simple_vector_ref<wsvector<T> *>
+      *svr = const_cast<simple_vector_ref<wsvector<T> *> *>(&l);
+    wsvector<T>
+      *pv = const_cast<wsvector<T> *>((l.origin));
+    clean(*pv, eps);
+    svr->begin_ = vect_begin(*pv); svr->end_ = vect_end(*pv);
+  }
+
+  template <typename T>
+  inline size_type nnz(const wsvector<T>& l) { return l.nb_stored(); }
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*    rsvector: sparse vector optimized for linear algebra operations.   */
+  /*                                                                       */
+  /*************************************************************************/
+
+  template<typename T> struct elt_rsvector_ {
+    size_type c; T e;
+    /* e is initialized by default to avoid some false warnings of valgrind..
+       (from http://valgrind.org/docs/manual/mc-manual.html:
+      
+       When memory is read into the CPU's floating point registers, the
+       relevant V bits are read from memory and they are immediately
+       checked. If any are invalid, an uninitialised value error is
+       emitted. This precludes using the floating-point registers to copy
+       possibly-uninitialised memory, but simplifies Valgrind in that it
+       does not have to track the validity status of the floating-point
+       registers.
+    */
+    elt_rsvector_(void) : e(0) {}
+    elt_rsvector_(size_type cc) : c(cc), e(0) {}
+    elt_rsvector_(size_type cc, const T &ee) : c(cc), e(ee) {}
+    bool operator < (const elt_rsvector_ &a) const { return c < a.c; }
+    bool operator == (const elt_rsvector_ &a) const { return c == a.c; }
+    bool operator != (const elt_rsvector_ &a) const { return c != a.c; }
+  };
+
+  template<typename T> struct rsvector_iterator {
+    typedef typename std::vector<elt_rsvector_<T> >::iterator IT;
+    typedef T                   value_type;
+    typedef value_type*         pointer;
+    typedef value_type&         reference;
+    typedef size_t              size_type;
+    typedef ptrdiff_t           difference_type;
+    typedef std::bidirectional_iterator_tag iterator_category;
+    typedef rsvector_iterator<T> iterator;
+
+    IT it;
+
+    reference operator *() const { return it->e; }
+    pointer operator->() const { return &(operator*()); }
+
+    iterator &operator ++() { ++it; return *this; }
+    iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
+    iterator &operator --() { --it; return *this; }
+    iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
+
+    bool operator ==(const iterator &i) const { return it == i.it; }
+    bool operator !=(const iterator &i) const { return !(i == *this); }
+
+    size_type index(void) const { return it->c; }
+    rsvector_iterator(void) {}
+    rsvector_iterator(const IT &i) : it(i) {}
+  };
+
+  template<typename T> struct rsvector_const_iterator {
+    typedef typename std::vector<elt_rsvector_<T> >::const_iterator IT;
+    typedef T                   value_type;
+    typedef const value_type*   pointer;
+    typedef const value_type&   reference;
+    typedef size_t              size_type;
+    typedef ptrdiff_t           difference_type;
+    typedef std::forward_iterator_tag iterator_category;
+    typedef rsvector_const_iterator<T> iterator;
+
+    IT it;
+
+    reference operator *() const { return it->e; }
+    pointer operator->() const { return &(operator*()); }
+    size_type index(void) const { return it->c; }
+
+    iterator &operator ++() { ++it; return *this; }
+    iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
+    iterator &operator --() { --it; return *this; }
+    iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
+
+    bool operator ==(const iterator &i) const { return it == i.it; }
+    bool operator !=(const iterator &i) const { return !(i == *this); }
+
+    rsvector_const_iterator(void) {}
+    rsvector_const_iterator(const rsvector_iterator<T> &i) : it(i.it) {}
+    rsvector_const_iterator(const IT &i) : it(i) {}
+  };
+
+  /**
+     sparse vector built upon std::vector. Read access is fast,
+     but insertion is O(n) 
+  */
+  template<typename T> class rsvector : public std::vector<elt_rsvector_<T> > {
+  public:
+    
+    typedef std::vector<elt_rsvector_<T> > base_type_;
+    typedef typename base_type_::iterator iterator;
+    typedef typename base_type_::const_iterator const_iterator;
+    typedef typename base_type_::size_type size_type;
+    typedef T value_type;
+
+  protected:
+    size_type nbl;    	/* size of the vector.	          	  */
+    
+  public:
+
+    void sup(size_type j);
+    void base_resize(size_type n) { base_type_::resize(n); }
+    void resize(size_type);
+    
+    ref_elt_vector<T, rsvector<T> > operator [](size_type c)
+    { return ref_elt_vector<T, rsvector<T> >(this, c); }
+
+    void w(size_type c, const T &e);
+    T r(size_type c) const;
+    void swap_indices(size_type i, size_type j);
+
+    inline T operator [](size_type c) const { return r(c); }
+    
+    size_type nb_stored(void) const { return base_type_::size(); }
+    size_type size(void) const { return nbl; }
+    void clear(void) { base_type_::resize(0); }
+    void swap(rsvector<T> &v)
+    { std::swap(nbl, v.nbl); std::vector<elt_rsvector_<T> >::swap(v); }
+
+    /* Constructeurs */
+    explicit rsvector(size_type l) : nbl(l) { }
+    rsvector(void) : nbl(0) { }
+  };
+
+  template <typename T>
+  void rsvector<T>::swap_indices(size_type i, size_type j) {
+    if (i > j) std::swap(i, j);
+    if (i != j) {
+      int situation = 0;
+      elt_rsvector_<T> ei(i), ej(j), a;
+      iterator it, ite, iti, itj;
+      iti = std::lower_bound(this->begin(), this->end(), ei);
+      if (iti != this->end() && iti->c == i) situation += 1;
+      itj = std::lower_bound(this->begin(), this->end(), ej);
+      if (itj != this->end() && itj->c == j) situation += 2;
+
+      switch (situation) {
+      case 1 : a = *iti; a.c = j; it = iti; ++it; ite = this->end();
+	       for (; it != ite && it->c <= j; ++it, ++iti) *iti = *it;
+	       *iti = a;
+	       break;
+      case 2 : a = *itj; a.c = i; it = itj; ite = this->begin();
+	if (it != ite) {
+	  --it;
+	  while (it->c >= i) { *itj = *it;  --itj; if (it==ite) break; --it; }
+	}
+	*itj = a;
+	break;
+      case 3 : std::swap(iti->e, itj->e);
+	       break;
+      }
+    }
+  }
+
+  template <typename T> void rsvector<T>::sup(size_type j) {
+    if (nb_stored() != 0) {
+      elt_rsvector_<T> ev(j);
+      iterator it = std::lower_bound(this->begin(), this->end(), ev);
+      if (it != this->end() && it->c == j) {
+	for (iterator ite = this->end() - 1; it != ite; ++it) *it = *(it+1);
+	base_type_::resize(nb_stored()-1);
+      }
+    }
+  }
+
+  template<typename T>  void rsvector<T>::resize(size_type n) {
+    if (n < nbl) {
+      for (size_type i = 0; i < nb_stored(); ++i)
+	if (base_type_::operator[](i).c >= n) { base_resize(i); break; }
+    }
+    nbl = n;
+  }
+
+  template <typename T> void rsvector<T>::w(size_type c, const T &e) {
+    GMM_ASSERT2(c < nbl, "out of range");
+    if (e == T(0)) sup(c);
+    else {
+      elt_rsvector_<T> ev(c, e);
+      if (nb_stored() == 0) {
+	base_type_::resize(1,ev);
+      }
+      else {
+	iterator it = std::lower_bound(this->begin(), this->end(), ev);
+	if (it != this->end() && it->c == c) it->e = e;
+	else {
+	  size_type ind = it - this->begin();
+	  base_type_::resize(nb_stored()+1, ev);
+	  if (ind != nb_stored() - 1) {
+	    it = this->begin() + ind;
+	    for (iterator ite = this->end() - 1; ite != it; --ite)
+	      *ite = *(ite-1);
+	    *it = ev;
+	  }
+	}
+      }
+    }
+  }
+  
+  template <typename T> T rsvector<T>::r(size_type c) const {
+    GMM_ASSERT2(c < nbl, "out of range");
+    if (nb_stored() != 0) {
+      elt_rsvector_<T> ev(c);
+      const_iterator it = std::lower_bound(this->begin(), this->end(), ev);
+      if (it != this->end() && it->c == c) return it->e;
+    }
+    return T(0);
+  }
+
+  template <typename T> struct linalg_traits<rsvector<T> > {
+    typedef rsvector<T> this_type;
+    typedef this_type origin_type;
+    typedef linalg_false is_reference;
+    typedef abstract_vector linalg_type;
+    typedef T value_type;
+    typedef ref_elt_vector<T, rsvector<T> > reference;
+    typedef rsvector_iterator<T>  iterator;
+    typedef rsvector_const_iterator<T> const_iterator;
+    typedef abstract_sparse storage_type;
+    typedef linalg_true index_sorted;
+    static size_type size(const this_type &v) { return v.size(); }
+    static iterator begin(this_type &v) { return iterator(v.begin()); }
+    static const_iterator begin(const this_type &v)
+    { return const_iterator(v.begin()); }
+    static iterator end(this_type &v) { return iterator(v.end()); }
+    static const_iterator end(const this_type &v)
+      { return const_iterator(v.end()); }
+    static origin_type* origin(this_type &v) { return &v; }
+    static const origin_type* origin(const this_type &v) { return &v; }
+    static void clear(origin_type* o, const iterator &, const iterator &)
+    { o->clear(); }
+    static void do_clear(this_type &v) { v.clear(); }
+    static value_type access(const origin_type *o, const const_iterator &,
+			     const const_iterator &, size_type i)
+    { return (*o)[i]; }
+    static reference access(origin_type *o, const iterator &, const iterator &,
+			    size_type i)
+    { return (*o)[i]; }
+    static void resize(this_type &v, size_type n) { v.resize(n); }
+  };
+
+  template<typename T> std::ostream &operator <<
+  (std::ostream &o, const rsvector<T>& v) { gmm::write(o,v); return o; }
+
+  /******* Optimized operations for rsvector<T> ****************************/
+
+  template <typename T> inline void copy(const rsvector<T> &v1,
+ 					 rsvector<T> &v2) {
+    GMM_ASSERT2(vect_size(v1) == vect_size(v2), "dimensions mismatch");
+    v2 = v1;
+  }
+  template <typename T> inline
+  void copy(const rsvector<T> &v1, const simple_vector_ref<rsvector<T> *> &v2){
+    simple_vector_ref<rsvector<T> *>
+      *svr = const_cast<simple_vector_ref<rsvector<T> *> *>(&v2);
+    rsvector<T>
+      *pv = const_cast<rsvector<T> *>((v2.origin));
+    GMM_ASSERT2(vect_size(v1) == vect_size(v2), "dimensions mismatch");
+    *pv = v1; svr->begin_ = vect_begin(*pv); svr->end_ = vect_end(*pv);
+  }
+  template <typename T> inline
+  void copy(const simple_vector_ref<const rsvector<T> *> &v1,
+	    rsvector<T> &v2)
+  { copy(*(v1.origin), v2); }
+  template <typename T> inline
+  void copy(const simple_vector_ref<rsvector<T> *> &v1, rsvector<T> &v2)
+  { copy(*(v1.origin), v2); }
+
+  template <typename V, typename T> inline void add(const V &v1,
+						    rsvector<T> &v2) {
+    if ((const void *)(&v1) != (const void *)(&v2)) {
+      GMM_ASSERT2(vect_size(v1) == vect_size(v2), "dimensions mismatch");
+	add_rsvector(v1, v2, typename linalg_traits<V>::storage_type());
+    }
+  }
+
+  template <typename V, typename T> 
+  inline void add_rsvector(const V &v1, rsvector<T> &v2, abstract_dense)
+  { add(v1, v2, abstract_dense(), abstract_sparse()); }
+
+  template <typename V, typename T> 
+  inline void add_rsvector(const V &v1, rsvector<T> &v2, abstract_skyline)
+  { add(v1, v2, abstract_skyline(), abstract_sparse()); }
+
+  template <typename V, typename T> 
+  void add_rsvector(const V &v1, rsvector<T> &v2, abstract_sparse) {
+    add_rsvector(v1, v2, typename linalg_traits<V>::index_sorted());
+  }
+
+  template <typename V, typename T> 
+  void add_rsvector(const V &v1, rsvector<T> &v2, linalg_false) {
+    add(v1, v2, abstract_sparse(), abstract_sparse());
+  }
+
+  template <typename V, typename T> 
+  void add_rsvector(const V &v1, rsvector<T> &v2, linalg_true) {
+    typename linalg_traits<V>::const_iterator it1 = vect_const_begin(v1),
+      ite1 = vect_const_end(v1);
+    typename rsvector<T>::iterator it2 = v2.begin(), ite2 = v2.end(), it3;
+    size_type nbc = 0, old_nbc = v2.nb_stored();
+    for (; it1 != ite1 && it2 != ite2 ; ++nbc)
+      if (it1.index() == it2->c) { ++it1; ++it2; }
+      else if (it1.index() < it2->c) ++it1; else ++it2;
+    for (; it1 != ite1; ++it1) ++nbc;
+    for (; it2 != ite2; ++it2) ++nbc;
+
+    v2.base_resize(nbc);
+    it3 = v2.begin() + old_nbc;
+    it2 = v2.end(); ite2 = v2.begin();
+    it1 = vect_end(v1); ite1 = vect_const_begin(v1);
+    while (it1 != ite1 && it3 != ite2) {
+      --it3; --it1; --it2;
+      if (it3->c > it1.index()) { *it2 = *it3; ++it1; }
+      else if (it3->c == it1.index()) { *it2=*it3; it2->e+=*it1; }
+      else { it2->c = it1.index(); it2->e = *it1; ++it3; }
+    }
+    while (it1 != ite1) { --it1; --it2; it2->c = it1.index(); it2->e = *it1; }
+  }
+
+  template <typename V, typename T> void copy(const V &v1, rsvector<T> &v2) {
+    if ((const void *)(&v1) != (const void *)(&v2)) {
+      GMM_ASSERT2(vect_size(v1) == vect_size(v2), "dimensions mismatch");
+      if (same_origin(v1, v2))
+	GMM_WARNING2("a conflict is possible in vector copy\n");
+      copy_rsvector(v1, v2, typename linalg_traits<V>::storage_type());
+    }
+  }
+
+  template <typename V, typename T> 
+  void copy_rsvector(const V &v1, rsvector<T> &v2, abstract_dense)
+  { copy_vect(v1, v2, abstract_dense(), abstract_sparse()); }
+
+  template <typename V, typename T> 
+  void copy_rsvector(const V &v1, rsvector<T> &v2, abstract_skyline)
+  { copy_vect(v1, v2, abstract_skyline(), abstract_sparse()); }
+
+  template <typename V, typename T>
+  void copy_rsvector(const V &v1, rsvector<T> &v2, abstract_sparse) {
+    copy_rsvector(v1, v2, typename linalg_traits<V>::index_sorted());
+  }
+  
+  template <typename V, typename T2>
+  void copy_rsvector(const V &v1, rsvector<T2> &v2, linalg_true) {
+    typedef typename linalg_traits<V>::value_type T1;
+    typename linalg_traits<V>::const_iterator it = vect_const_begin(v1),
+      ite = vect_const_end(v1);
+    v2.base_resize(nnz(v1));
+    typename rsvector<T2>::iterator it2 = v2.begin();
+    size_type nn = 0;
+    for (; it != ite; ++it)
+      if ((*it) != T1(0)) { it2->c = it.index(); it2->e = *it; ++it2; ++nn; }
+    v2.base_resize(nn);
+  }
+
+  template <typename V, typename T2>
+  void copy_rsvector(const V &v1, rsvector<T2> &v2, linalg_false) {
+    typedef typename linalg_traits<V>::value_type T1;
+    typename linalg_traits<V>::const_iterator it = vect_const_begin(v1),
+      ite = vect_const_end(v1);
+    v2.base_resize(nnz(v1));
+    typename rsvector<T2>::iterator it2 = v2.begin();
+    size_type nn = 0;
+    for (; it != ite; ++it)
+      if ((*it) != T1(0)) { it2->c = it.index(); it2->e = *it; ++it2; ++nn; }
+    v2.base_resize(nn);
+    std::sort(v2.begin(), v2.end());
+  }
+  
+  template <typename T> inline void clean(rsvector<T> &v, double eps) {
+    typedef typename number_traits<T>::magnitude_type R;
+    typename rsvector<T>::iterator it = v.begin(), ite = v.end();
+    for (; it != ite; ++it) if (gmm::abs((*it).e) <= eps) break;
+    if (it != ite) {
+      typename rsvector<T>::iterator itc = it;
+      size_type erased = 1;
+      for (++it; it != ite; ++it)
+	{ *itc = *it; if (gmm::abs((*it).e) <= R(eps)) ++erased; else ++itc; }
+      v.base_resize(v.nb_stored() - erased);
+    }
+  }
+
+  template <typename T>
+  inline void clean(const simple_vector_ref<rsvector<T> *> &l, double eps) {
+    simple_vector_ref<rsvector<T> *>
+      *svr = const_cast<simple_vector_ref<rsvector<T> *> *>(&l);
+    rsvector<T>
+      *pv = const_cast<rsvector<T> *>((l.origin));
+    clean(*pv, eps);
+    svr->begin_ = vect_begin(*pv); svr->end_ = vect_end(*pv);
+  }
+  
+  template <typename T>
+  inline size_type nnz(const rsvector<T>& l) { return l.nb_stored(); }
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Class slvector: 'sky-line' vector.                                    */
+  /*                                                                       */
+  /*************************************************************************/
+
+  template<typename T> struct slvector_iterator {
+    typedef T value_type;
+    typedef T *pointer;
+    typedef T &reference;
+    typedef ptrdiff_t difference_type;
+    typedef std::random_access_iterator_tag iterator_category;
+    typedef size_t size_type;
+    typedef slvector_iterator<T> iterator;
+    typedef typename std::vector<T>::iterator base_iterator;
+
+    base_iterator it;
+    size_type shift;
+    
+   
+    iterator &operator ++()
+    { ++it; ++shift; return *this; }
+    iterator &operator --()
+    { --it; --shift; return *this; }
+    iterator operator ++(int)
+    { iterator tmp = *this; ++(*(this)); return tmp; }
+    iterator operator --(int)
+    { iterator tmp = *this; --(*(this)); return tmp; }
+    iterator &operator +=(difference_type i)
+    { it += i; shift += i; return *this; }
+    iterator &operator -=(difference_type i)
+    { it -= i; shift -= i; return *this; }
+    iterator operator +(difference_type i) const
+    { iterator tmp = *this; return (tmp += i); }
+    iterator operator -(difference_type i) const
+    { iterator tmp = *this; return (tmp -= i); }
+    difference_type operator -(const iterator &i) const
+    { return it - i.it; }
+	
+    reference operator *() const
+    { return *it; }
+    reference operator [](int ii)
+    { return *(it + ii); }
+    
+    bool operator ==(const iterator &i) const
+    { return it == i.it; }
+    bool operator !=(const iterator &i) const
+    { return !(i == *this); }
+    bool operator < (const iterator &i) const
+    { return it < i.it; }
+    size_type index(void) const { return shift; }
+
+    slvector_iterator(void) {}
+    slvector_iterator(const base_iterator &iter, size_type s)
+      : it(iter), shift(s) {}
+  };
+
+  template<typename T> struct slvector_const_iterator {
+    typedef T value_type;
+    typedef const T *pointer;
+    typedef value_type reference;
+    typedef ptrdiff_t difference_type;
+    typedef std::random_access_iterator_tag iterator_category;
+    typedef size_t size_type;
+    typedef slvector_const_iterator<T> iterator;
+    typedef typename std::vector<T>::const_iterator base_iterator;
+
+    base_iterator it;
+    size_type shift;
+    
+   
+    iterator &operator ++()
+    { ++it; ++shift; return *this; }
+    iterator &operator --()
+    { --it; --shift; return *this; }
+    iterator operator ++(int)
+    { iterator tmp = *this; ++(*(this)); return tmp; }
+    iterator operator --(int)
+    { iterator tmp = *this; --(*(this)); return tmp; }
+    iterator &operator +=(difference_type i)
+    { it += i; shift += i; return *this; }
+    iterator &operator -=(difference_type i)
+    { it -= i; shift -= i; return *this; }
+    iterator operator +(difference_type i) const
+    { iterator tmp = *this; return (tmp += i); }
+    iterator operator -(difference_type i) const
+    { iterator tmp = *this; return (tmp -= i); }
+    difference_type operator -(const iterator &i) const
+    { return it - i.it; }
+	
+    value_type operator *() const
+    { return *it; }
+    value_type operator [](int ii)
+    { return *(it + ii); }
+    
+    bool operator ==(const iterator &i) const
+    { return it == i.it; }
+    bool operator !=(const iterator &i) const
+    { return !(i == *this); }
+    bool operator < (const iterator &i) const
+    { return it < i.it; }
+    size_type index(void) const { return shift; }
+
+    slvector_const_iterator(void) {}
+    slvector_const_iterator(const slvector_iterator<T>& iter)
+      : it(iter.it), shift(iter.shift) {}
+    slvector_const_iterator(const base_iterator &iter, size_type s)
+      : it(iter), shift(s) {}
+  };
+
+
+  /** skyline vector.
+   */
+  template <typename T> class slvector {
+    
+  public :
+    typedef slvector_iterator<T> iterators;
+    typedef slvector_const_iterator<T> const_iterators;
+    typedef typename std::vector<T>::size_type size_type;
+    typedef T value_type;
+
+  protected :
+    std::vector<T> data;
+    size_type shift;
+    size_type size_;
+
+
+  public :
+
+    size_type size(void) const { return size_; }
+    size_type first(void) const { return shift; }
+    size_type last(void) const { return shift + data.size(); }
+    ref_elt_vector<T, slvector<T> > operator [](size_type c)
+    { return ref_elt_vector<T, slvector<T> >(this, c); }
+
+    typename std::vector<T>::iterator data_begin(void) { return data.begin(); }
+    typename std::vector<T>::iterator data_end(void) { return data.end(); }
+    typename std::vector<T>::const_iterator data_begin(void) const
+      { return data.begin(); }
+    typename std::vector<T>::const_iterator data_end(void) const
+      { return data.end(); }
+
+    void w(size_type c, const T &e);
+    T r(size_type c) const {
+      GMM_ASSERT2(c < size_, "out of range");
+      if (c < shift || c >= shift + data.size()) return T(0);
+      return data[c - shift];
+    }
+
+    inline T operator [](size_type c) const { return r(c); }
+    void resize(size_type);
+    void clear(void) { data.resize(0); shift = 0; }
+    void swap(slvector<T> &v) {
+      std::swap(data, v.data);
+      std::swap(shift, v.shift);
+      std::swap(size_, v.size_);
+    }
+
+
+    slvector(void) : data(0), shift(0), size_(0) {}
+    explicit slvector(size_type l) : data(0), shift(0), size_(l) {}
+    slvector(size_type l, size_type d, size_type s)
+      : data(d), shift(s), size_(l) {}
+
+  };
+
+  template<typename T>  void slvector<T>::resize(size_type n) {
+    if (n < last()) {
+      if (shift >= n) clear(); else { data.resize(n-shift); }
+    }
+    size_ = n;
+  }
+
+  template<typename T>  void slvector<T>::w(size_type c, const T &e) {
+    GMM_ASSERT2(c < size_, "out of range");
+    size_type s = data.size();
+    if (!s) { data.resize(1); shift = c; }
+    else if (c < shift) {
+      data.resize(s + shift - c); 
+      typename std::vector<T>::iterator it = data.begin(),it2=data.end()-1;
+      typename std::vector<T>::iterator it3 = it2 - shift + c;
+      for (; it3 >= it; --it3, --it2) *it2 = *it3;
+      std::fill(it, it + shift - c, T(0));
+      shift = c;
+    }
+    else if (c >= shift + s) {
+      data.resize(c - shift + 1);
+      std::fill(data.begin() + s, data.end(), T(0));
+    }
+    data[c - shift] = e;
+  }
+  
+  template <typename T> struct linalg_traits<slvector<T> > {
+    typedef slvector<T> this_type;
+    typedef this_type origin_type;
+    typedef linalg_false is_reference;
+    typedef abstract_vector linalg_type;
+    typedef T value_type;
+    typedef ref_elt_vector<T, slvector<T> > reference;
+    typedef slvector_iterator<T>  iterator;
+    typedef slvector_const_iterator<T> const_iterator;
+    typedef abstract_skyline storage_type;
+    typedef linalg_true index_sorted;
+    static size_type size(const this_type &v) { return v.size(); }
+    static iterator begin(this_type &v)
+      { return iterator(v.data_begin(), v.first()); }
+    static const_iterator begin(const this_type &v)
+      { return const_iterator(v.data_begin(), v.first()); }
+    static iterator end(this_type &v)
+      { return iterator(v.data_end(), v.last()); }
+    static const_iterator end(const this_type &v)
+      { return const_iterator(v.data_end(), v.last()); }
+    static origin_type* origin(this_type &v) { return &v; }
+    static const origin_type* origin(const this_type &v) { return &v; }
+    static void clear(origin_type* o, const iterator &, const iterator &)
+    { o->clear(); }
+    static void do_clear(this_type &v) { v.clear(); }
+    static value_type access(const origin_type *o, const const_iterator &,
+			     const const_iterator &, size_type i)
+    { return (*o)[i]; }
+    static reference access(origin_type *o, const iterator &, const iterator &,
+			    size_type i)
+    { return (*o)[i]; }
+    static void resize(this_type &v, size_type n) { v.resize(n); }
+  };
+
+  template<typename T> std::ostream &operator <<
+  (std::ostream &o, const slvector<T>& v) { gmm::write(o,v); return o; }
+
+  template <typename T>
+  inline size_type nnz(const slvector<T>& l) { return l.last() - l.first(); }
+
+}
+
+namespace std {
+  template <typename T> void swap(gmm::wsvector<T> &v, gmm::wsvector<T> &w)
+  { v.swap(w);}
+  template <typename T> void swap(gmm::rsvector<T> &v, gmm::rsvector<T> &w)
+  { v.swap(w);}
+  template <typename T> void swap(gmm::slvector<T> &v, gmm::slvector<T> &w)
+  { v.swap(w);}
+}
+
+
+
+#endif /* GMM_VECTOR_H__ */
diff --git a/Contrib/gmm/gmm_vector_to_matrix.h b/Contrib/gmm/gmm_vector_to_matrix.h
new file mode 100755
index 0000000..50036fc
--- /dev/null
+++ b/Contrib/gmm/gmm_vector_to_matrix.h
@@ -0,0 +1,339 @@
+// -*- c++ -*- (enables emacs c++ mode)
+//===========================================================================
+//
+// Copyright (C) 2003-2008 Yves Renard
+//
+// This file is a part of GETFEM++
+//
+// Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
+// under  the  terms  of the  GNU  Lesser General Public License as published
+// by  the  Free Software Foundation;  either version 2.1 of the License,  or
+// (at your option) any later version.
+// This program  is  distributed  in  the  hope  that it will be useful,  but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+// License for more details.
+// You  should  have received a copy of the GNU Lesser General Public License
+// along  with  this program;  if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+//===========================================================================
+
+/**@file gmm_vector_to_matrix.h
+   @author  Yves Renard <Yves.Renard at insa-lyon.fr>
+   @date December 6, 2003.
+   @brief View vectors as row or column matrices. */
+#ifndef GMM_VECTOR_TO_MATRIX_H__
+#define GMM_VECTOR_TO_MATRIX_H__
+
+#include "gmm_interface.h"
+
+namespace gmm {
+
+  /* ********************************************************************* */
+  /*	     row vector -> transform a vector in a (1, n) matrix.          */
+  /* ********************************************************************* */
+
+  template <typename PT> struct gen_row_vector {
+    typedef gen_row_vector<PT> this_type;
+    typedef typename std::iterator_traits<PT>::value_type V;
+    typedef V * CPT;
+    typedef typename std::iterator_traits<PT>::reference ref_V;
+    typedef typename linalg_traits<this_type>::reference reference;
+
+    simple_vector_ref<PT> vec;
+    
+    reference operator()(size_type, size_type j) const { return vec[j]; }
+   
+    size_type nrows(void) const { return 1; }
+    size_type ncols(void) const { return vect_size(vec); }
+    
+    gen_row_vector(ref_V v) : vec(v) {}
+    gen_row_vector() {}
+    gen_row_vector(const gen_row_vector<CPT> &cr) : vec(cr.vec) {}
+  };
+
+  template <typename PT>
+  struct gen_row_vector_iterator {
+    typedef gen_row_vector<PT> this_type;
+    typedef typename modifiable_pointer<PT>::pointer MPT;
+    typedef typename std::iterator_traits<PT>::value_type V;
+    typedef simple_vector_ref<PT> value_type;
+    typedef const simple_vector_ref<PT> *pointer;
+    typedef const simple_vector_ref<PT> &reference;
+    typedef ptrdiff_t difference_type;
+    typedef size_t size_type;
+    typedef std::random_access_iterator_tag  iterator_category;
+    typedef gen_row_vector_iterator<PT> iterator;
+
+    simple_vector_ref<PT> vec;
+    bool isend;
+    
+    iterator &operator ++()   { isend = true; return *this; }
+    iterator &operator --()   { isend = false; return *this; }
+    iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
+    iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
+    iterator &operator +=(difference_type i)
+    { if (i) isend = false; return *this; }
+    iterator &operator -=(difference_type i)
+    { if (i) isend = true; return *this;  }
+    iterator operator +(difference_type i) const 
+    { iterator itt = *this; return (itt += i); }
+    iterator operator -(difference_type i) const
+    { iterator itt = *this; return (itt -= i); }
+    difference_type operator -(const iterator &i) const { 
+      return (isend == true) ? ((i.isend == true) ? 0 : 1)
+	                     : ((i.isend == true) ? -1 : 0);
+    }
+
+    const simple_vector_ref<PT>& operator *() const { return vec; }
+    const simple_vector_ref<PT>& operator [](int i) { return vec; }
+
+    bool operator ==(const iterator &i) const { return (isend == i.isend); }
+    bool operator !=(const iterator &i) const { return !(i == *this); }
+    bool operator < (const iterator &i) const { return (*this - i < 0); }
+
+    gen_row_vector_iterator(void) {}
+    gen_row_vector_iterator(const gen_row_vector_iterator<MPT> &itm)
+      : vec(itm.vec), isend(itm.isend) {}
+    gen_row_vector_iterator(const gen_row_vector<PT> &m, bool iis_end)
+      : vec(m.vec), isend(iis_end) { }
+    
+  };
+
+  template <typename PT>
+  struct linalg_traits<gen_row_vector<PT> > {
+    typedef gen_row_vector<PT> this_type;
+    typedef typename std::iterator_traits<PT>::value_type V;
+    typedef typename which_reference<PT>::is_reference is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef typename linalg_traits<V>::origin_type origin_type;
+    typedef typename select_ref<const origin_type *, origin_type *,
+				PT>::ref_type porigin_type;
+    typedef typename linalg_traits<V>::value_type value_type;
+    typedef typename select_ref<value_type,
+            typename linalg_traits<V>::reference, PT>::ref_type reference;
+    typedef abstract_null_type sub_col_type;
+    typedef abstract_null_type col_iterator;
+    typedef abstract_null_type const_sub_col_type;
+    typedef abstract_null_type const_col_iterator;
+    typedef simple_vector_ref<const V *> const_sub_row_type;
+    typedef typename select_ref<abstract_null_type, 
+            simple_vector_ref<V *>, PT>::ref_type sub_row_type;
+    typedef gen_row_vector_iterator<typename const_pointer<PT>::pointer>
+            const_row_iterator;
+    typedef typename select_ref<abstract_null_type, 
+	    gen_row_vector_iterator<PT>, PT>::ref_type row_iterator;
+    typedef typename linalg_traits<V>::storage_type storage_type;
+    typedef row_major sub_orientation;
+    typedef typename linalg_traits<V>::index_sorted index_sorted;
+    static size_type nrows(const this_type &) { return 1; }
+    static size_type ncols(const this_type &m) { return m.ncols(); }
+    static const_sub_row_type row(const const_row_iterator &it) { return *it; }
+    static sub_row_type row(const row_iterator &it) { return *it; }
+    static const_row_iterator row_begin(const this_type &m)
+    { return const_row_iterator(m, false); }
+    static row_iterator row_begin(this_type &m)
+    { return row_iterator(m, false); }
+    static const_row_iterator row_end(const this_type &m)
+    { return const_row_iterator(m, true); }
+    static row_iterator row_end(this_type &m)
+    { return row_iterator(m, true); }
+    static origin_type* origin(this_type &m) { return m.vec.origin; }
+    static const origin_type* origin(const this_type &m)
+    { return m.vec.origin; }
+    static void do_clear(this_type &m)
+    { clear(row(mat_row_begin(m))); }
+    static value_type access(const const_row_iterator &itrow, size_type i)
+    { return itrow.vec[i]; }
+    static reference access(const row_iterator &itrow, size_type i)
+    { return itrow.vec[i]; }
+  };
+  
+  template <typename PT>
+  std::ostream &operator <<(std::ostream &o, const gen_row_vector<PT>& m)
+  { gmm::write(o,m); return o; }
+
+  /* ********************************************************************* */
+  /*	     col vector -> transform a vector in a (n, 1) matrix.          */
+  /* ********************************************************************* */
+
+  template <typename PT> struct gen_col_vector {
+    typedef gen_col_vector<PT> this_type;
+    typedef typename std::iterator_traits<PT>::value_type V;
+    typedef V * CPT;
+    typedef typename std::iterator_traits<PT>::reference ref_V;
+    typedef typename linalg_traits<this_type>::reference reference;
+
+    simple_vector_ref<PT> vec;
+    
+    reference operator()(size_type i, size_type) const { return vec[i]; }
+   
+    size_type ncols(void) const { return 1; }
+    size_type nrows(void) const { return vect_size(vec); }
+    
+    gen_col_vector(ref_V v) : vec(v) {}
+    gen_col_vector() {}
+    gen_col_vector(const gen_col_vector<CPT> &cr) : vec(cr.vec) {}
+  };
+
+  template <typename PT>
+  struct gen_col_vector_iterator {
+    typedef gen_col_vector<PT> this_type;
+    typedef typename modifiable_pointer<PT>::pointer MPT;
+    typedef typename std::iterator_traits<PT>::value_type V;
+    typedef simple_vector_ref<PT> value_type;
+    typedef const simple_vector_ref<PT> *pointer;
+    typedef const simple_vector_ref<PT> &reference;
+    typedef ptrdiff_t difference_type;
+    typedef size_t size_type;
+    typedef std::random_access_iterator_tag  iterator_category;
+    typedef gen_col_vector_iterator<PT> iterator;
+
+    simple_vector_ref<PT> vec;
+    bool isend;
+    
+    iterator &operator ++()   { isend = true; return *this; }
+    iterator &operator --()   { isend = false; return *this; }
+    iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
+    iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
+    iterator &operator +=(difference_type i)
+    { if (i) isend = false; return *this; }
+    iterator &operator -=(difference_type i)
+    { if (i) isend = true; return *this;  }
+    iterator operator +(difference_type i) const 
+    { iterator itt = *this; return (itt += i); }
+    iterator operator -(difference_type i) const
+    { iterator itt = *this; return (itt -= i); }
+    difference_type operator -(const iterator &i) const { 
+      return (isend == true) ? ((i.isend == true) ? 0 : 1)
+	                     : ((i.isend == true) ? -1 : 0);
+    }
+
+    const simple_vector_ref<PT>& operator *() const { return vec; }
+    const simple_vector_ref<PT>& operator [](int i) { return vec; }
+
+    bool operator ==(const iterator &i) const { return (isend == i.isend); }
+    bool operator !=(const iterator &i) const { return !(i == *this); }
+    bool operator < (const iterator &i) const { return (*this - i < 0); }
+
+    gen_col_vector_iterator(void) {}
+    gen_col_vector_iterator(const gen_col_vector_iterator<MPT> &itm)
+      : vec(itm.vec), isend(itm.isend) {}
+    gen_col_vector_iterator(const gen_col_vector<PT> &m, bool iis_end)
+      : vec(m.vec), isend(iis_end) { }
+    
+  };
+
+  template <typename PT>
+  struct linalg_traits<gen_col_vector<PT> > {
+    typedef gen_col_vector<PT> this_type;
+    typedef typename std::iterator_traits<PT>::value_type V;
+    typedef typename which_reference<PT>::is_reference is_reference;
+    typedef abstract_matrix linalg_type;
+    typedef typename linalg_traits<V>::origin_type origin_type;
+    typedef typename select_ref<const origin_type *, origin_type *,
+				PT>::ref_type porigin_type;
+    typedef typename linalg_traits<V>::value_type value_type;
+    typedef typename select_ref<value_type,
+            typename linalg_traits<V>::reference, PT>::ref_type reference;
+    typedef abstract_null_type sub_row_type;
+    typedef abstract_null_type row_iterator;
+    typedef abstract_null_type const_sub_row_type;
+    typedef abstract_null_type const_row_iterator;
+    typedef simple_vector_ref<const V *> const_sub_col_type;
+    typedef typename select_ref<abstract_null_type, 
+            simple_vector_ref<V *>, PT>::ref_type sub_col_type;
+    typedef gen_col_vector_iterator<typename const_pointer<PT>::pointer>
+            const_col_iterator;
+    typedef typename select_ref<abstract_null_type, 
+	    gen_col_vector_iterator<PT>, PT>::ref_type col_iterator;
+    typedef typename linalg_traits<V>::storage_type storage_type;
+    typedef col_major sub_orientation;
+    typedef typename linalg_traits<V>::index_sorted index_sorted;
+    static size_type ncols(const this_type &) { return 1; }
+    static size_type nrows(const this_type &m) { return m.nrows(); }
+    static const_sub_col_type col(const const_col_iterator &it) { return *it; }
+    static sub_col_type col(const col_iterator &it) { return *it; }
+    static const_col_iterator col_begin(const this_type &m)
+    { return const_col_iterator(m, false); }
+    static col_iterator col_begin(this_type &m)
+    { return col_iterator(m, false); }
+    static const_col_iterator col_end(const this_type &m)
+    { return const_col_iterator(m, true); }
+    static col_iterator col_end(this_type &m)
+    { return col_iterator(m, true); }
+    static origin_type* origin(this_type &m) { return m.vec.origin; }
+    static const origin_type* origin(const this_type &m)
+    { return m.vec.origin; }
+    static void do_clear(this_type &m)
+    { clear(col(mat_col_begin(m))); }
+    static value_type access(const const_col_iterator &itcol, size_type i)
+    { return itcol.vec[i]; }
+    static reference access(const col_iterator &itcol, size_type i)
+    { return itcol.vec[i]; }
+  };
+  
+  template <typename PT>
+  std::ostream &operator <<(std::ostream &o, const gen_col_vector<PT>& m)
+  { gmm::write(o,m); return o; }
+
+  /* ******************************************************************** */
+  /*		col and row vectors                                       */
+  /* ******************************************************************** */
+
+  
+  template <class V> inline
+  typename select_return< gen_row_vector<const V *>, gen_row_vector<V *>,
+			  const V *>::return_type
+  row_vector(const V& v) {
+    return typename select_return< gen_row_vector<const V *>,
+      gen_row_vector<V *>, const V *>::return_type(linalg_cast(v));
+  }
+
+  template <class V> inline
+  typename select_return< gen_row_vector<const V *>, gen_row_vector<V *>,
+			  V *>::return_type
+  row_vector(V& v) {
+    return typename select_return< gen_row_vector<const V *>,
+      gen_row_vector<V *>, V *>::return_type(linalg_cast(v));
+  }
+ 
+  template <class V> inline gen_row_vector<const V *>
+  const_row_vector(V& v)
+  { return gen_row_vector<const V *>(v); }
+ 
+
+  template <class V> inline
+  typename select_return< gen_col_vector<const V *>, gen_col_vector<V *>,
+			  const V *>::return_type
+  col_vector(const V& v) {
+    return typename select_return< gen_col_vector<const V *>,
+      gen_col_vector<V *>, const V *>::return_type(linalg_cast(v));
+  }
+
+  template <class V> inline
+  typename select_return< gen_col_vector<const V *>, gen_col_vector<V *>,
+			  V *>::return_type
+  col_vector(V& v) {
+    return typename select_return< gen_col_vector<const V *>,
+      gen_col_vector<V *>, V *>::return_type(linalg_cast(v));
+  }
+ 
+  template <class V> inline gen_col_vector<const V *>
+  const_col_vector(V& v)
+  { return gen_col_vector<const V *>(v); }
+ 
+
+}
+
+#endif //  GMM_VECTOR_TO_MATRIX_H__
diff --git a/Contrib/mathex/lesser.txt b/Contrib/mathex/lesser.txt
new file mode 100644
index 0000000..3f50d04
--- /dev/null
+++ b/Contrib/mathex/lesser.txt
@@ -0,0 +1,506 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
+
+
diff --git a/Contrib/mathex/license.txt b/Contrib/mathex/license.txt
new file mode 100644
index 0000000..1bc4194
--- /dev/null
+++ b/Contrib/mathex/license.txt
@@ -0,0 +1,35 @@
+BMP libray License
+------------------
+
+The MathEx library and included programs are part of SSCILIB and provided under
+the terms of the GNU Library/Lesser General Public License (LGPL) 2.1 or latter,
+with following static linking exceptions:
+
+   1. The combined work statically linked with unmodified MathEx library will
+distributed under your own license.
+
+   2. The application or libraries statically linked with MathEx library must identify 
+their use of SSCILIB library. For example, text like
+"[application/library] is based in part on the work of the SSCILIB Library
+ (http://sscilib.sourceforge.net/)" 
+will included in document or help to satisfy this requirement.
+
+   3. The folowing five modifications on MathEx library in way to fit your 
+requirement does not implies in modification of source code:
+    i. Modification of the MathEx config script, makefiles or instalation tools.
+   ii. change of name space definition
+using namespace smlib
+to other one (need if it conflict with other library)
+
+   4. The modifications of source code implies in the GNU Library/Lesser General Public License 2.1 or latter, without this static linking exceptions.
+
+End of license term
+-------------------
+
+For GNU Library/lesser General Public License, see the lesser.txt or visit
+http://www.gnu.org/
+
+June of 2003.
+
+Sadao Massago
+http://www2.dm.ufscar.br/~sadao
diff --git a/Contrib/mathex/mathex.cpp b/Contrib/mathex/mathex.cpp
new file mode 100644
index 0000000..3231891
--- /dev/null
+++ b/Contrib/mathex/mathex.cpp
@@ -0,0 +1,1019 @@
+///////////////////////////////////////////////////////////////////////////
+// mathex 0.2.3 (beta) - Copyright (C) 2000-2003, by Sadao Massago       //
+// file: mathex.h (math expression evaluator header file)                //
+// requires: none                                                        //
+// project web page: http://sscilib.sourceforge.net/                     //
+// ----------------------------------------------------------------------//
+// The mathex library and related files is licenced under the term of    //
+// GNU LGPL (Lesser General Public License) version 2.1 or latter        //
+// with exceptions that allow for static linking.                        //
+// See license.txt for detail.                                           //
+// For GNU LGPL, see lesser.txt.                                         //
+// For information over GNU or GNU compatible license, visit the site    //
+// http://www.gnu.org.                                                   //
+///////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////
+// references:
+//-------------------------------------------------------------------------
+// title: Algoritms and Data Structures
+// author: Niklaus Wirth
+// publisher: Prentice-Hall
+// year: 1989
+//-------------------------------------------------------------------------
+// title: The C++ Programming Language
+// edition: thrird
+// author: Bjarne Stroustrup
+// publisher: Addilson-Wesley
+// year: 1997
+//-------------------------------------------------------------------------
+// title: building your own C interpreter
+// author: Schildt, Helbert
+// journal: Dr. Dobb's Jornal (http://www.ddj.com)
+// number: August/1989
+// pages: 38-49, 110-122
+///////////////////////////////////////////////////////////////////////////
+
+// #define _DEBUG_
+
+#include "mathex.h"
+
+#include <string.h>
+#include <string>
+#include <vector>
+#include <cmath>
+#include <cctype>
+#include <math.h>
+#include <cstdlib>
+
+// debug purpose
+#ifdef _DEBUG_
+  #include <iostream>
+#endif
+
+   namespace smlib {
+      using namespace std;
+   
+   
+   ////////////////////////////////////
+   // local variables, functions, etc
+   ////////////////////////////////////
+      namespace {
+      
+      //////////////////////////////////
+      // C function with one parameter
+      //--------------------------------
+      
+          double fac(double x)
+         // Function return the factorial of integer belong to range 0..170.
+         // in future, will implement aproximation for gamma function to evaluate for x > 170
+         {
+            double p;
+            unsigned n;
+         
+            if((x <0) || (x>170)) // maximum admited where
+               throw mathex::error("Error [fac()]: range error");
+            else {
+               n = static_cast<unsigned>(x+0.5);
+               if(x < 2)
+                  return 1;
+               else if(n == 2)
+                  return(2);
+               for(p=1;1<n;n--)
+                  p *= n;
+               return p;
+            }
+         } // fac()
+      
+      // convert radian to degree
+          double deg(double x)
+         {
+            return( x * 180.0 / M_PI);
+         } // deg()
+      
+      // convert degree to radian
+          double rad(double x)
+         {
+            return(x * M_PI / 180.0);
+         } // rad()
+      
+      // return square
+      /*    double sqr(double x)
+      {
+         return (x*x);
+      } */
+      // sqr()
+      
+      // return real part
+          double trunc(double x)
+         {
+            return static_cast<long>(x);
+         } // trunc()
+      
+      // return rounded value to int
+          double round(double x)
+         {
+            return static_cast<long>(x+0.5);
+         } // round
+      
+      // return 0 if x negative, 1 otherwise
+          double step(double x)
+         {
+           if ( x < 0 ) return static_cast<long>(0.);
+           return static_cast<long>(1.);
+         } // step
+      
+      // return -1 if x negative, 1 otherwise
+          double sign(double x)
+         {
+           if ( x < 0 ) return static_cast<long>(-1.);
+           return static_cast<long>(1.);
+         } // sign
+      
+      //////////////////////////////////////////////////////////
+      // arithmetic operators
+      //////////////////////////////////////////////////////////
+      // operators was treated in Parsingr time, to check the
+      //   operator level.
+      //   unary operator is the function double op(double) and
+      //   binary operator is function double op(double,double)
+      //--------------------------------------------------------
+      //   unary:
+      //   "+" -> none
+      //   "-" -> unary_minus
+      //   binary:
+      //   "+" -> binary_plus
+      //   "-" -> binary_minus
+      //   "*" -> binary_times
+      //   "/" -> binary_divide
+      //   "^" -> binary_power
+      //   "%" -> fmod (defined in math.h)
+      ///////////////////////////////////////////////////////////
+      
+      //////////////////////
+      // C unary operator
+      
+          double unary_minus(double x)
+         {
+            return -x;
+         } // unary_minus()
+      
+      //////////////////////////////////////////
+      // C binary operators
+      //----------------------------------------
+      
+          double binary_plus(double x, double y)
+         {
+            return x + y;
+         } // binary_plus() 
+      
+          double binary_minus(double x, double y)
+         {
+            return x - y;
+         } // binary_minus()
+      
+          double binary_times(double x, double y)
+         {
+            return x * y;
+         } // binary_timess()
+      
+          double binary_divide(double x, double y)
+         // in future, put more precisery checking, for overflow ?
+         {
+            if (y == 0)
+               throw mathex::error("Error [binary_divide()]: divisin by zero");
+            else
+               return (x/y);
+         } // binary_divide()
+      
+          double binary_power(double x, double y)
+         {
+            return pow(x,y);
+         } // binary_power()
+      
+      /////////////////////////////////////////
+      // pre-defined user defined functions
+      //---------------------------------------
+      
+          double p_rand(vector <double> const &x)
+         // rand() return value between [0,1)
+         {
+            if(x.size() != 0)
+               throw mathex::error("Error [p_rand()]: can not use argument");
+            return rand()/(RAND_MAX+1.0);
+         } // p_rand()
+      
+      // maximum
+          double p_max(vector <double> const & x)
+         {
+         
+            double maxval=0;
+         
+            if(x.size() == 0)
+               throw mathex::error("Error [p_max()]: No arguments");
+            maxval = x[0];
+            for(unsigned i=0; i<x.size(); i++)
+               if(x[i] > maxval)
+                  maxval = x[i];
+         
+            return maxval;
+         } // p_max
+      
+      // minimum
+          double p_min(vector <double> const & x)
+         {
+         
+            double minval=0;
+         
+            if(x.size() == 0)
+               throw mathex::error("Error [p_min()]: No arguments");
+            minval = x[0];
+            for(unsigned i=0; i<x.size(); i++)
+               if(x[i] < minval)
+                  minval = x[i];
+         
+            return minval;
+         } // p_min
+      
+      // sum
+          double p_sum(vector <double> const & x)
+         {
+         
+            double sumval=0;
+         
+            if(x.size() == 0)
+               throw mathex::error("Error [p_sum()]: No arguments");
+            for(unsigned i=0; i<x.size(); i++)
+               sumval += x[i];
+         
+            return sumval;
+         } // p_sum
+      
+      // average
+          double p_med(vector <double> const & x)
+         {
+            if(x.size() == 0)
+               throw mathex::error("Error [p_med()]: No arguments");
+            return p_sum(x)/x.size();
+         } // p_med()
+      
+      ////////////////////////////////
+      // function/constant tables
+      ////////////////////////////////
+      
+      //////////////////////////////////
+      // One parameter C function table
+      
+      // Record for one parameter C functions
+         typedef 
+             struct
+            {
+               const char *name;
+               double  (*f)(double x); // one parameter function
+            } CFUNCREC;
+      	
+      ///////////////////////////////////////////////////////////   
+      // One parameter internal C defined functions
+      // the unary operator are stored on first part of table
+      //---------------------------------------------------------
+      // CAUTION:
+      // if add unary operator, adjust the definiftion of NUM_UNARY_OP 
+      #define NUM_UNARY_OP 1
+         CFUNCREC cfunctable[] =
+         {
+         // name and funtion pointer
+         // first part of table is unary operators
+         {"-", unary_minus}, // unary operator
+         // seccond part of table is functions
+         { "abs",     fabs },
+         { "Abs",     fabs },
+         { "acos",    acos },
+         { "Acos",    acos },
+         { "asin",    asin },
+         { "Asin",    asin },
+         { "atan",    atan },
+         { "Atan",    atan },
+         { "cos",     cos },
+         { "Cos",     cos },
+         { "cosh",    cosh },
+         { "Cosh",    cosh },
+         { "deg",     deg },   // added
+         { "Deg",     deg },   // added
+         { "exp",     exp },
+         { "Exp",     exp },
+         { "fac",     fac },   // added
+         { "Fac",     fac },   // added
+         { "log",     log },
+         { "Log",     log },
+         { "log10",   log10 },
+         { "Log10",   log10 },
+         // { "pow10",   pow10 } // in future, add it?
+         { "rad",     rad },   // added 
+         { "Rad",     rad },   // added 
+         { "round",   round }, // added
+         { "Round",   round }, // added
+         { "sign",    sign },
+         { "Sign",    sign },
+         { "sin",     sin },
+         { "Sin",     sin },
+         { "sinh",    sinh },
+         { "Sinh",    sinh },
+         // { "sqr",     sqr }, // added
+         { "sqrt",    sqrt },
+         { "Sqrt",    sqrt },
+         { "step",    step },
+         { "Step",    step },
+         { "tan",     tan },
+         { "Tan",     tan },
+         { "tanh",    tanh },
+         { "Tanh",    tanh },
+         { "trunc",   trunc }, // added
+         { "Trunc",   trunc }, // added
+         { "floor",   floor }, // largest integer not grather than x
+         { "Floor",   floor }, // largest integer not grather than x
+         { "ceil",    ceil }, // smallest integer not less than x
+         { "Ceil",    ceil }, // smallest integer not less than x
+         
+         { 0, 0 } // 0 mark the end of table
+         };
+      
+      /////////////////////
+      // binary operators
+      
+      // binary operator's record
+          class BINOPREC {
+         public:
+            char name;
+            double (*f)(double, double);
+         };
+      
+      ////////////////////
+      // binary operators
+         BINOPREC binoptable[] =
+         {
+         // name, value
+         { '+',  binary_plus},
+         { '-',  binary_minus},
+         { '*',  binary_times},
+         { '/',  binary_divide},
+         { '^',  binary_power},
+         { '%',  fmod},
+         
+         { '\0' , 0 } // '\0' mark the end of table
+         };
+      
+      //////////////
+      // constants
+      
+      // constants record
+          class CONSTREC {
+         public:
+            const char *name;
+            double value;
+         };
+      
+      /////////////
+      // constants
+         CONSTREC consttable[] =
+         {
+         // name, value
+         { "pi",  M_PI },
+         { "e",   M_E },
+         
+         { NULL, 0 } // NULL mark the end of table
+         };
+      
+      } // namespace {
+   
+   
+   ////////////////////////////
+   // implementations
+   ///////////////////////////
+   
+   ///////////////
+   // constatnts
+   /// undefined number of arguments (for user defined functions
+      const int mathex::UNDEFARGS = -1; // for user function arguments   
+   
+   ////////////////
+   // methods
+       void mathex::addstdfunc()
+      {
+         addfunc("rand", p_rand, 0);
+         addfunc("sum", p_sum, UNDEFARGS);
+         addfunc("max", p_max, UNDEFARGS);
+         addfunc("min", p_min, UNDEFARGS);
+         addfunc("med", p_med, UNDEFARGS);
+      } // addstdfunc()
+   
+       void mathex::reset()
+      {
+         delvar();
+         delfunc();
+         status = notparsed;
+         expr = "";
+         bytecode.clear();
+         pos = 0;
+         addstdfunc();  
+      } // reset
+   
+   /////////////////////////////////
+   // varibles table manipulations
+   
+       bool mathex::addvar(string const &name, double *var)
+      // register the program internal variable
+      {
+         unsigned i;
+      
+         for(i=0; (i<vartable.size()) && (vartable[i].name != name);i++);
+         if(i<vartable.size()) { // found! overwrite
+            vartable[i].var = var;
+            return true;
+         }
+         else if(!isnewvalidname(name))
+            return false;
+         vartable.push_back(VARREC(name, var));
+         return true;
+      } // addvar()
+   
+       bool mathex::delvar(string const &name)
+      // delete one variable
+      {
+         unsigned i;
+      
+         for(i=0; (i<vartable.size()) && (vartable[i].name != name);i++);
+         if(i < vartable.size())  {
+         // how to use erase?
+         // vartable.erase(&vartable[i],&vartable[i+1]);
+            for(unsigned j=0; j<vartable.size()-1; j++)
+               vartable[j] = vartable[j+1];
+            vartable.pop_back(); // delete last
+            status = notparsed;
+            return true;
+         }
+         else
+            return false;
+      } // delvar()
+   
+   //////////////////////////////////////////////
+   // user defined function table manipulation
+   //////////////////////////////////////////////
+   
+       bool mathex::addfunc(string const &name, double (*f)(vector<double> const &), int NumArgs)
+      // register the user defined function
+      {
+         unsigned i;
+      
+         for(i=0; (i<functable.size()) && (functable[i].name != name);i++);
+         if(i<functable.size()) { // found! overwrite
+            functable[i].f = f;
+            functable[i].numargs = NumArgs;
+            return true;
+         }
+         else if(!isnewvalidname(name))
+            return false;
+         functable.push_back(FUNCREC(name, f, NumArgs));
+         return true;
+      } // addfunc()
+   
+       bool mathex::delfunc(string const &name)
+      // delete the user defined function
+      {
+         unsigned i;
+      
+         for(i=0; (i<functable.size()) && (functable[i].name != name);i++);
+         if(i < functable.size())  {
+         // how to use erase?
+         // functable.erase(&vartable[i],&vartable[i+1]);
+            for(unsigned j=0; j<vartable.size()-1; j++)
+               functable[j] = functable[j+1];
+            functable.pop_back(); // delete last
+            return true;
+         }
+         else
+            return false;
+      } // delfunc()
+   
+   ////////////////////////////////////////////////////
+   // get the index of variables/constants/functions/
+   //     binary operator/user defined functions
+   //--------------------------------------------------
+   // return -1 if not found
+   ////////////////////////////////////////////////////
+   
+       int mathex::getconst(string const &name)
+      // get index of const
+      // return -1 if not found
+      {
+         unsigned i;
+      // look up the constants
+         for(i=0;consttable[i].name && strcmp(name.c_str(), consttable[i].name);i++);
+         if(consttable[i].name != NULL) // if found
+            return i;
+         else
+            return -1;
+      } // getconst
+   
+   
+       int mathex::getvar(string const &name)
+      // get index of variable
+      // return -1 if not found
+      {
+         unsigned i;
+      
+      // look up the table
+         for(i=0;(i<vartable.size()) && strcmp(name.c_str(), vartable[i].name.c_str());i++);
+         if(i<vartable.size()) // if found
+            return i;
+         else
+            return -1;
+      } // getvar
+   
+   
+       int mathex::getcfunc(string const &name)
+      // get index of one parameter function
+      // return -1 if not found
+      {
+         unsigned i;
+      // look up the constants
+         for(i=NUM_UNARY_OP;cfunctable[i].name && strcmp(name.c_str(), cfunctable[i].name);i++);
+         if(cfunctable[i].name != NULL) // if found
+            return i;
+         else
+            return -1;
+      } // getcfunc
+   
+       int mathex::getunaryop(string const &name)
+      // get index of unary operator
+      // return -1 if not found
+      {
+         unsigned i;
+      // look up the constants
+         for(i=0; cfunctable[i].name && strcmp(name.c_str(), cfunctable[i].name);i++);
+         if(cfunctable[i].name != NULL) // if found
+            return i;
+         else
+            return -1;
+      } // getunaryop
+   
+       int mathex::getbinop(char name)
+      // get index of one parameter function
+      // return -1 if not found
+      {
+         unsigned i;
+      // look up the constants
+         for(i=0;binoptable[i].name && (name != binoptable[i].name);i++);
+         if(binoptable[i].name != '\0') // if found
+            return i;
+         else
+            return -1;
+      } // getbinop
+   
+   
+       int mathex::getuserfunc(string const &name)
+      // get index of variable
+      // return -1 if not found
+      {
+         unsigned i;
+      // look up the constants
+         for(i=0;(i<functable.size()) && strcmp(name.c_str(), functable[i].name.c_str());i++);
+         if(i<functable.size()) // if found
+            return i;
+         else
+            return -1;
+      } // getuserfunc
+   
+   
+       bool mathex::isnewvalidname(string const &name)
+      // Name validation.
+      {
+         if(name.empty() || (!isalpha(name[0]) && (name[0] != '_')))
+            return false;
+      // check for rest of characters
+         for(unsigned j=0; j<name.size(); j++)
+            if(!isalnum(name[j]) && (name[j] != '-'))
+               return false;
+         return (getcfunc(name) < 0) && (getconst(name) < 0) 
+            && (getuserfunc(name) < 0) && (getvar(name) < 0);
+      } // isnewvalidname
+   
+   
+   //////////////////
+   //  Evaluation 
+   
+   // main evaluator: internal use only
+   
+   // main evaluation function
+       double mathex::eval()
+      //  Eval the parsed stack and return
+      {
+         static vector <double> x; // suppose that eval does not eval
+         evalstack.clear();
+      
+         if(status == notparsed) parse();
+         if(status == invalid) throw error("eval()", "invalid expression");
+      
+         for(unsigned i=0; i<bytecode.size(); i++)
+         {
+            switch(bytecode[i].state) {
+               case CODETOKEN::VALUE: evalstack.push_back(bytecode[i].value);
+                  break;
+               case CODETOKEN::VARIABLE:
+               // get value of variable as value
+                  evalstack.push_back(*vartable[bytecode[i].idx].var);
+                  break;
+               case CODETOKEN::FUNCTION: // Call the C internal functions with one parameter
+               #ifdef _DEBUG_
+               if(evalstack.size()<1) // error: It does not to occur if currect parsed.
+                  throw error("eval()", "stack error");
+               #endif
+                  evalstack.back() = cfunctable[bytecode[i].idx].f(evalstack.back());
+                  break;
+               case CODETOKEN::BINOP: // Call the intern C function with two parameters
+               #ifdef _DEBUG_
+               if(evalstack.size() < 2) // error: It does not to occur if currect parsed.
+                  throw error("eval()", "stack error");
+               #endif
+                  evalstack[evalstack.size()-2] = binoptable[bytecode[i].idx].f
+                     (evalstack[evalstack.size()-2], evalstack.back());
+                  evalstack.pop_back(); // delete last
+                  break;				
+               case CODETOKEN::USERFUNC: // Call the user defined functions
+               #ifdef _DEBUG_
+               if(bytecode[i].numargs > evalstack.size())
+                  throw error("eval()", "stack error");
+               #endif
+                  if(bytecode[i].numargs > 0) {
+                     x.resize(bytecode[i].numargs);
+                     for(unsigned j=0; j<static_cast<unsigned>(bytecode[i].numargs); j++)
+                        x[bytecode[i].numargs-1-j] = evalstack[evalstack.size()-1-j];
+                     evalstack.resize(evalstack.size()-bytecode[i].numargs+1);
+							
+                     evalstack.back() = functable[bytecode[i].idx].f(x);
+                  }
+						else // Fixing bug pointed by  Hugh Denman <denmanh at tcd.ie> November 06, 2003
+						   evalstack.push_back(functable[bytecode[i].idx].f(x));
+                  break;         
+               default: // invarid stack. It does not occur if currect parsed
+                  throw  error("eval()", "invalid code token");
+            }
+         } // for(i=0; ByteCode[i].state != EMPTY;i++);
+      
+      #ifdef _DEBUG_
+      if(evalstack.size() != 1)
+         throw error("eval()", "stack error");  
+      #endif
+         return evalstack[0];
+      } // eval()
+   
+   /////////////////
+   // parser
+   //---------------
+   
+   /////////////////
+   // get the token
+   
+   // get the number token
+       bool mathex::getnumber(double &x)
+      {
+         unsigned long i = pos;
+         bool decimal;
+      
+      // is a number?
+         if((i >= expr.size()) || !strchr("0123456789.", expr[i])) // not a number
+            return false;
+      
+      // getting the number
+         for(decimal=false; i<expr.size(); i++) {
+            if(!isdigit(expr[i]) && ((expr[i] != '.') || decimal) )
+               break;
+            if(expr[i] == '.') decimal = true;
+         }
+      
+         if((i==(pos+1)) && (expr[i]=='.')) // is not a number
+            return false;
+      
+      // if scientific notation
+         if((toupper(expr[i])=='E') && (i<expr.size())) { // cientific notation 
+         // decimal = true; // turn on to detect that are double
+            i++; // skip this
+            if((i<expr.size()) && ((expr[i]=='+') || (expr[i]=='-')) ) { // if sign
+               i++;
+            }
+         // get the expoent
+            while((i<expr.size()) && isdigit(expr[i]))
+               i++;
+         }
+      // now, copy the token and conter to number
+      // if decimal is true, the number is double. otherwise, number is integer
+      // for this detection, cientific notation need to enable decimal too.
+      // The integer value are not used for this package
+      
+         x = strtod(expr.substr(pos, i-pos).c_str(), 0);
+         pos = i;
+         return true;
+      } // getnumber()
+   
+       bool mathex::getidentifier(string &name)
+      {
+         unsigned i = pos;
+      
+         name.erase();
+         if((i>=expr.size()) || (!isalpha(expr[i]) && (expr[i] != '_'))) // not a identifier
+            return false;
+      
+      // identifier
+         for(;(i<expr.size()) &&(isalnum(expr[i]) || (expr[i] == '_')); i++);
+      
+         name = expr.substr(pos, i-pos);
+         pos = i; // advance the input
+      
+         return true;
+      } // getidentifier()
+   
+   
+       mathex::PARSERTOKEN::type mathex::nexttoken()
+      // Gets the next token from the expr
+      {
+         string identifier;
+      
+         while((pos<expr.size()) && isspace(expr[pos]) )
+            pos++;
+      
+         if(pos == expr.size()) {
+            curtok.state = PARSERTOKEN::END;
+            return curtok.state;
+         }
+      
+         if(getnumber(curtok.value)) {
+            curtok.state = PARSERTOKEN::VALUE;
+            return curtok.state;
+         }
+         else if(getidentifier(identifier)) { // if identifier
+         // checking the identifier type
+            if((curtok.idx = getcfunc(identifier))>=0) // internal C functions
+               curtok.state = PARSERTOKEN::FUNCTION;
+            else if((curtok.idx=getuserfunc(identifier))>=0) { // user defined functions
+               curtok.numargs = functable[curtok.idx].numargs;
+               curtok.state = PARSERTOKEN::USERFUNC;
+            }
+            else if((curtok.idx=getvar(identifier))>=0) // variable
+               curtok.state = PARSERTOKEN::VARIABLE;
+            else if((curtok.idx=getconst(identifier))>=0) {  // constant are treated as NUMBER
+               curtok.state = PARSERTOKEN::VALUE;
+               curtok.value = consttable[curtok.idx].value;
+            }
+            else { // new identifier: not supported
+               curtok.state = PARSERTOKEN::INVALID;
+            }
+         }
+         else { // will be operators or delimiters
+            switch(expr[pos]) {
+               case '+' : curtok.state = PARSERTOKEN::PLUS;
+                  break;
+               case '-' : curtok.state = PARSERTOKEN::MINUS;
+                  break;
+               case '*' : curtok.state = PARSERTOKEN::TIMES;
+                  break;
+               case '/' : curtok.state = PARSERTOKEN::DIVIDE;
+                  break;
+               case '%' : curtok.state = PARSERTOKEN::MODULE;
+                  break;
+               case '^' : curtok.state = PARSERTOKEN::POWER;
+                  break;
+               case ',' : curtok.state = PARSERTOKEN::COMMA;
+                  break;
+               case '(' : curtok.state = PARSERTOKEN::OPAREN;
+                  break;
+               case ')' : curtok.state = PARSERTOKEN::CPAREN;
+                  break;
+               default  : curtok.state = PARSERTOKEN::INVALID;
+            } // switch 
+            if(curtok.state != PARSERTOKEN::INVALID) {
+               curtok.idx = getbinop(expr[pos]);
+               pos++;
+            }
+         } // else
+      
+         return curtok.state;
+      } // nexttoken()
+   
+   ////////////////////////////
+   // CodeStack operations 
+   ////////////////////////////
+   #ifdef _DEBUG_
+    void mathex::printcoderec(CODETOKEN const &token)
+   // print the Code Stack status
+   {
+      switch(token.state) {
+      // case CODETOKEN::EMPTY: cout << "EMPTY\n";
+      //  break;
+         case CODETOKEN::VALUE:
+            cout << "VALUE: " << token.value << endl;
+            break;
+         case CODETOKEN::VARIABLE:
+            cout << "VARIABLE: " << vartable[token.idx].name << endl;
+            break;
+         case CODETOKEN::FUNCTION:
+            if(token.idx <NUM_UNARY_OP) 
+               cout << "unary operator: " << cfunctable[token.idx].name << endl;
+            else
+               cout << "FUNCTION: " << cfunctable[token.idx].name << endl;
+            break;
+         case CODETOKEN::BINOP:
+            cout << "binary operator: " << binoptable[token.idx].name << endl;
+            break;
+         case CODETOKEN::USERFUNC:
+            cout << "USERFUNC: " << functable[token.idx].name << endl;
+            break;
+         default: printf("INVALID\n");
+      }
+   
+   } // printcoderec()
+   
+    void mathex::printbytecode()
+   {
+      cout << "codesize = "<< bytecode.size() << endl;
+      for(unsigned i=0; i<bytecode.size(); i++)
+         printcoderec(bytecode[i]);
+   }
+   #endif
+   
+       void mathex::parse()
+      // Parse the expression
+      {
+      // parserstatus = true;
+         bytecode.clear();
+         status = invalid;
+         pos=0;
+         nexttoken();
+         parsearithmetic1();
+      #ifdef _DEBUG_
+        printbytecode();
+      #endif
+         if(curtok.state != PARSERTOKEN::END) // if remain token
+            throw error("parse()", "End of expression expected");
+         status = parsed;
+      } // parse()
+   
+       void mathex::parsearithmetic1(void)
+      // level 1 arithmetic operator: binary plus/minus
+      {
+         unsigned savedidx; 
+         parsearithmetic2();
+         while((curtok.state == PARSERTOKEN::PLUS) || (curtok.state == PARSERTOKEN::MINUS)) {
+            savedidx = curtok.idx;
+            nexttoken();
+            if((curtok.state == PARSERTOKEN::PLUS) || (curtok.state == PARSERTOKEN::MINUS)) 
+               throw error("parse()", "Invalid expression");
+            parsearithmetic2();      
+            bytecode.push_back(CODETOKEN(CODETOKEN::BINOP, savedidx));
+         } // while
+      } // parsearithmetic1
+   
+   
+       void mathex::parsearithmetic2(void)
+      // level 2 arithmetic operator: multiplication, division, module
+      {
+         unsigned savedidx;
+         parsearithmetic3();   
+         while( (curtok.state == PARSERTOKEN::TIMES) || (curtok.state == PARSERTOKEN::DIVIDE)
+           || (curtok.state == PARSERTOKEN::MODULE) ) {
+            savedidx = curtok.idx;
+            nexttoken();
+            if((curtok.state == PARSERTOKEN::PLUS) || (curtok.state == PARSERTOKEN::MINUS)) 
+               throw error("parse()", "Invalid expression");
+            parsearithmetic3();
+            bytecode.push_back(CODETOKEN(CODETOKEN::BINOP, savedidx));
+         }
+      } // parsearithmetic3
+   
+       void mathex::parsearithmetic3(void)
+      // level 3 arithmetic operator: power
+      {
+         unsigned savedidx;
+         parsearithmetic4();
+         if(curtok.state == PARSERTOKEN::POWER) {
+            savedidx = curtok.idx;
+            nexttoken();
+            if((curtok.state == PARSERTOKEN::PLUS) || (curtok.state == PARSERTOKEN::MINUS)) 
+               throw error("parse()", "Invalid expression");
+            parsearithmetic4();
+            bytecode.push_back(CODETOKEN(CODETOKEN::BINOP, savedidx));
+         }
+      } // parsearithmetic3()
+   
+       void mathex::parsearithmetic4(void)
+      // level 4 arithmetic operator: unary plus/minus
+      {
+         PARSERTOKEN::type state;
+         if(((state=curtok.state) == PARSERTOKEN::PLUS) || (state == PARSERTOKEN::MINUS))
+            nexttoken();
+         if((curtok.state == PARSERTOKEN::PLUS) || (curtok.state == PARSERTOKEN::MINUS)) 
+            throw error("parse()", "Invalid expression");
+         parseatom();
+      
+         if(state == PARSERTOKEN::MINUS) // stored index are for binary operator. Get correct index
+            bytecode.push_back(CODETOKEN(CODETOKEN::FUNCTION, getunaryop("-"))); 
+      	// unary minus are on function table
+      } // parsearithmetic5()
+   
+       void mathex::parseatom(void)
+      // level 6: literal numbers, variables and functions
+      {
+         unsigned i;
+      
+      // parentesis expression
+         if(curtok.state == PARSERTOKEN::OPAREN) {
+            nexttoken();
+            if(curtok.state == PARSERTOKEN::CPAREN)
+               throw error("parseatom()", "No expression inside parentesis");
+            parsearithmetic1();
+         
+            if(curtok.state != PARSERTOKEN::CPAREN)
+               throw error("parseatom()", "\")\" expected");
+            nexttoken();  // Added by Hugh Denman (<denmanh at tcd.ie> or hdenman at cantab.net) Oct/03/2003     
+         }
+         // Number
+         else if(curtok.state == PARSERTOKEN::VALUE) { // numbers
+            bytecode.push_back(CODETOKEN(curtok.value));
+            nexttoken();
+         }
+         // variables
+         else if(curtok.state == PARSERTOKEN::VARIABLE) { // variables
+            bytecode.push_back(CODETOKEN(CODETOKEN::VARIABLE, curtok.idx));
+            nexttoken();
+         }
+         // internal C function with one parameters
+         else if(curtok.state == PARSERTOKEN::FUNCTION) { // one parameter C functions
+            parserstack.push_back(curtok);
+            nexttoken();
+            if(curtok.state != PARSERTOKEN::OPAREN)
+               throw error("parseatom()", "\"(\" expected");
+            nexttoken();
+            if(curtok.state == PARSERTOKEN::CPAREN) 
+               throw error("parseatom()", "invalid number of arguments");
+            parsearithmetic1();
+            if(curtok.state != PARSERTOKEN::CPAREN)
+               throw error("parseatom()", "\")\" expected");
+            curtok = parserstack.back();
+            parserstack.pop_back();
+            bytecode.push_back(CODETOKEN(CODETOKEN::FUNCTION, curtok.idx));
+            nexttoken();
+         }
+         // user defined functions
+         else if(curtok.state == PARSERTOKEN::USERFUNC) { // user defined function
+            parserstack.push_back(curtok);
+            nexttoken();
+            if(curtok.state != PARSERTOKEN::OPAREN)
+               throw error("parseatom()", "\"(\" expected");
+            nexttoken();
+            if(curtok.state == PARSERTOKEN::CPAREN)
+               i = 0;
+            else { // arguments exist
+               parsearithmetic1();
+               i = 1;
+            // while(parserstatus && (curtok.state != PARSERTOKEN::END)
+            //        &&(curtok.state != PARSERTOKEN::CPAREN)) {
+               while((curtok.state != PARSERTOKEN::END) && (curtok.state != PARSERTOKEN::CPAREN)) {
+                  if(curtok.state == PARSERTOKEN::COMMA) {
+                     nexttoken();
+                     i++;
+                  }
+                  else 
+                     throw error("parseatom()", "unknow error");
+                  parsearithmetic1();
+               } // while
+               if(curtok.state != PARSERTOKEN::CPAREN)
+                  throw error("parseatom()", "\")\" expected");
+            } // else
+            curtok = parserstack.back();
+            parserstack.pop_back();
+         
+            if ((curtok.numargs != UNDEFARGS) && (i != static_cast<unsigned>(curtok.numargs)))
+            // i is current number of parameters
+               throw error("parseatom()", "invalid number of arguments");
+         
+         // number of parameters is correct. Now, put the function
+         // i is number of arguments    
+            bytecode.push_back(CODETOKEN(CODETOKEN::USERFUNC, curtok.idx, i));
+         
+            nexttoken();
+         } // user defined functions
+         // End of buffer
+         else if (curtok.state == PARSERTOKEN::END)
+            throw error("parseatom()", "unexpected end of expression");
+         // invalid
+         else if (curtok.state == PARSERTOKEN::INVALID)
+            throw error("parseatom()", "invalid token on expression");
+         // unknow error
+         else // it not occur
+            throw error("parseatom()", "unknow error");  
+      } // parseatom()
+   
+   
+   
+   } // namespace smlib {
+
+
+// end of mathex.c
diff --git a/Contrib/mathex/mathex.h b/Contrib/mathex/mathex.h
new file mode 100644
index 0000000..56e9029
--- /dev/null
+++ b/Contrib/mathex/mathex.h
@@ -0,0 +1,270 @@
+///////////////////////////////////////////////////////////////////////////
+// mathex 0.2.3 (beta) - Copyright (C) 2000-2003, by Sadao Massago       //
+// file: mathex.h (math expression evaluator header file)                //
+// requires: none                                                        //
+// project web page: http://sscilib.sourceforge.net/                     //
+//-----------------------------------------------------------------------//
+// The mathex library and related files is licensed under the term of    //
+// GNU LGPL (Lesser General Public License) version 2.1 or latter        //
+// with exceptions that allow for static linking.                        //
+// See license.txt for detail.                                           //
+// For GNU LGPL, see lesser.txt.                                         //
+// For information over GNU or GNU compatible license, visit the site    //
+// http://www.gnu.org.                                                   //
+////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////
+// references:
+//-------------------------------------------------------------------------
+// title: Algoritms and Data Structures
+// author: Niklaus Wirth
+// publisher: Prentice-Hall
+// year: 1989
+//-------------------------------------------------------------------------
+// title: The C++ programming language
+// edition: thrird
+// author: Bjarne Stroustrup
+// publisher: Addilson-Wesley
+// year: 1997
+//-------------------------------------------------------------------------
+// title: building your own C interpreter
+// author: Schildt, Helbert
+// journal: Dr. Dobb's Jornal (http://www.ddj.com)
+// number: August/1989
+// pages: 38-49, 110-122
+///////////////////////////////////////////////////////////////////////////
+
+// example file listing for doxygen
+
+/// \example inttest.cpp
+/// integration test using Trapezoidal rule
+
+/// \example userfunctest.cpp
+/// user defined function testing
+
+/// \example tabletest.cpp
+/// making table of function
+ 
+/// \example curvetest.cpp
+/// making table of parametric curve
+
+// #define _DEBUG_
+
+#ifndef _MATHEX_H
+ #define _MATHEX_H
+
+#include <string>
+#include <vector>
+#include <cmath>
+// #include <cctype>
+// debug purpose
+#ifdef _DEBUG_
+  #include <iostream>
+#endif
+
+namespace smlib {
+
+using namespace std;
+
+/////////////////////////////////////
+// mathex main class
+// it contain several sub classes
+// to handle expressions
+/////////////////////////////////////
+
+    class mathex {
+   /////////////////////////
+   // private sub calsses
+   ////////////////////////
+   
+     // code token used by evaluator
+       class CODETOKEN {
+      public:
+         // token type (code token type)
+         enum type {
+         VALUE=0, // numerical value stack
+         VARIABLE, // variable stack
+         FUNCTION, // internal C function with one parameters (include unary operators)
+         BINOP, // internal C binary opeartors (function with two parameters)
+         USERFUNC, // user defined functions
+         LASTTYPE=USERFUNC};
+      
+         type state;  // state of Token
+         unsigned numargs;
+         // The user defined function use it to pop values from stack
+			// In the undefined number of arguments case, it will not eliminated
+			double value; // numerical value
+         unsigned idx; // index of variable, function or user defined function on table
+          CODETOKEN(double x=0.0) // construct VALUE token
+         {
+            state = VALUE;
+            value = x;
+         }
+          CODETOKEN(type toktype, unsigned index, unsigned NumArgs=1) // construct token except VALUE
+          // in the used defined function case, num args need to set
+         {
+            state = toktype;
+            idx = index;
+				numargs = NumArgs;
+         }
+      }; // CODETOKEN
+   
+      // parse token used by parser
+       class PARSERTOKEN {
+      public:
+         enum type {
+         VALUE, VARIABLE, FUNCTION, USERFUNC,
+         PLUS, MINUS, TIMES, DIVIDE, MODULE, POWER, 
+         OPAREN, CPAREN, COMMA, END, INVALID, // invalid character on token
+         LASTTYPE=INVALID
+         };
+      
+         type state;
+         int numargs; // number of parameters of functions
+         double value;
+         int idx; // it are signed because receive func/var search index that will be -1
+      	         // atom parsing cede optimization
+      };  // parsetoken
+   
+   
+   // function record
+   
+   //  Record for user defined functions
+       class FUNCREC {
+      public:
+         string name;
+         double  (*f)(vector<double> const &x); // generic number of parameters
+         int numargs; // number of arguments
+          FUNCREC() // only for table (vector) operation
+         {name = ""; f = 0;}
+          FUNCREC(string const &funcname, double (*func)(vector<double> const &), int NumArgs)
+         {name = funcname; f = func; numargs = NumArgs; }
+      }; // FUNCREC
+   
+   
+   // variable record
+       class VARREC {
+      public:
+         string name;
+         double *var;
+          VARREC()
+         {name = ""; var = 0;}
+          VARREC(string const &varname, double *x)
+         {
+            if(x == NULL) throw error("Error [VARREC()]: variable without reference");
+            name = varname; var = x; }
+      }; // VARREC
+   
+   /////////////////////
+   // evalmath start here
+   /////////////////////
+      
+      vector<FUNCREC> functable; // used defined function table
+      vector<VARREC> vartable; // used defined variable table
+      vector<CODETOKEN> bytecode; // parsed code
+      vector<double> evalstack; // stack memory used by evaluator
+      string expr; // expression string
+      enum {invalid, notparsed, parsed} status; // prse status
+   
+      // used by addvar/addfunc to validate new variable/functions name
+      bool isnewvalidname(string const &name); // check if new valid name
+   
+      // table look up
+      int getconst(string const &name); // get index of constant
+      int getvar(string const &name); // get index of variable
+      int getcfunc(string const &name); // get index of one parameter internal C function
+      int getunaryop(string const &name); // get index of unary operator
+      int getbinop(char name); // get index of binary operator
+      int getuserfunc(string const &name); // get index of user defined functions
+      void addstdfunc(); // add standard user defined functions to table
+   
+      // token operators
+      bool getnumber(double &x); // get number from input string
+      bool getidentifier(string &name); // get identifier from input string
+      PARSERTOKEN::type nexttoken(); // get next token from input string
+      vector<PARSERTOKEN> parserstack; // stack used by parser
+      PARSERTOKEN curtok; // current token. Used by parser
+      unsigned long pos; // expression parsing position
+   
+      #ifdef _DEBUG_
+      void printcoderec(CODETOKEN const &token); // used by printbytecode()
+      #endif
+      // parser methods
+      // aritmethic operators
+      void parsearithmetic1(void);  // binary plus/minus 
+      void parsearithmetic2(void);  // timed, divide, modulo
+      void parsearithmetic3(void);  // power
+      void parsearithmetic4(void);  // unary minus 
+      void parseatom(void);  // atom: functions, variables, numbers...
+      
+   public:
+       ///////////////////////
+   	 // public sub classes
+   	 ///////////////////////
+   	 
+         /// error class to hamdle exceptions
+     class error : public std::exception {
+        private:
+         string msg;
+         public:
+            /// with message only
+          error(string const &message)
+         { msg = "Error [eval]: " + message; }
+			/// error with identifier and messages
+          error(string const &id, string const &message)
+         { msg = "Error [mathex::" + id + "]: " + message; }
+          /// unkone error
+          error()
+         { msg = "Error [mathex]: unkonw error"; }
+          /// return error message
+          const char * what() const throw()
+         { 
+            return msg.c_str(); }            
+          ~error() throw() {}
+       }; // error		
+   	 
+   	////////////////////////////////////////////////////
+      // mathex public constants, variables and methods
+   
+      #ifdef _DEBUG_
+      void printbytecode(); // output byte code to cout
+      #endif
+   
+   
+    // add/delete variables
+      bool addvar(string const &name, double *x); /// < add new variable
+      bool delvar(string const &name); /// < delete variable
+       void delvar() /// < delete all variables
+      {vartable.clear(); status = notparsed; }
+   
+       /// undefined number of arguments (for user defined functions
+      static const int UNDEFARGS; // for user function arguments   
+      // add/delete used defined functions
+      bool addfunc(string const &name, double (*f)(vector<double> const &), int NumArgs); /// < add new function
+      bool delfunc(string const &name); /// < delete variable
+       void delfunc() /// < delete all variable
+      {functable.clear(); addstdfunc(); status=notparsed; }
+    // expression string
+       string const &expression() /// < return expression string
+      {
+         return expr;}
+       void expression(string const &formula) /// < set expression string
+      { expr = formula; status = notparsed; pos=0; }
+       unsigned long stopposition() /// < return parser stoped position
+      { 
+         return pos; }
+      void parse(); /// < parse expression 
+      double eval(); /// < eval expression
+      void reset(); /// < reset all
+       mathex() /// < default constructor
+      {reset();}
+       mathex(string const &formula) /// < constructor that assign expression string
+      {reset(); expr = formula;}
+   }; /// mathex
+
+
+} // namespace smlib {
+
+#endif // #ifndef _MATHEX_H
+
+// end of mathex.c
diff --git a/Copyright.txt b/Copyright.txt
new file mode 100644
index 0000000..9ffb9ac
--- /dev/null
+++ b/Copyright.txt
@@ -0,0 +1,33 @@
+MAdLib: Mesh Adaptation Library
+Version: 1.0
+
+Copyright (C) 2008-2009 Universite catholique de Louvain, Belgium,
+<http://www.uclouvain.be>. All Rights Reserved.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as 
+published by the Free Software Foundation, either version 3 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program (License.txt). If not, see <http://www.gnu.org/licenses/>.
+
+Disclaimer
+----------
+The Universite catholique de Louvain and the authors make no 
+representations about the suitability or fitness of this software 
+for any purpose. It is provided "as is" without express or implied 
+warranty.
+
+Report all bugs and problems to <contrib at madlib.be>
+Web site: http://www.madlib.be
+
+Authors
+-------
+
+See Credits.txt
diff --git a/Credits.txt b/Credits.txt
new file mode 100644
index 0000000..20fb364
--- /dev/null
+++ b/Credits.txt
@@ -0,0 +1,37 @@
+             MAdLib is copyright (C) 2008-2009
+
+             Universite catholique de Louvain
+                 <http://www.uclouvain.be>
+
+The main authors are Gaetan Compere and Jean-Francois Remacle.
+
+Gaetan Compere
+Departement of Civil Engineering
+Universite catholique de Louvain
+Avenue Georges Lemaitre 4, 1348 Louvain-la-Neuve, Belgium
+gaetan.compere at uclouvain.be
+
+Jean-Francois Remacle
+Departement of Civil Engineering
+Universite catholique de Louvain
+Avenue Georges Lemaitre 4, 1348 Louvain-la-Neuve, Belgium
+jean-francois.remacle at uclouvain.be
+
+Major code contributions have been provided by Cecile Dobrzynski
+(parallel adaptation and periodic meshes) and Koen Hillewaert 
+(high order elements and a lot of testing and bug reports/fixes).
+
+Other code contributors include: Arnaud Francois (edge swap operator), 
+Olivier Pierard (DESC, edge split and face collapse operators), 
+Richard Comblen (PETSc interface), Josue Barboza (parallel adaptation 
+testing and debugging), Jonathan Lambrechts (bug fixes) and Paul-Emile 
+Bernard (bug fixes).
+
+This version of MAdLib may contain code (in the Contrib/gmm
+subdirectory) copyright (C) 2002-2008 Yves Renard: check the
+configuration options.
+
+This version of MAdLib may contain code (in the Contrib/mathex
+subdirectory) copyright (C) 2000-2003 Sadao Massago: check the
+configuration options.
+
diff --git a/Geo/GM_Iterators.h b/Geo/GM_Iterators.h
new file mode 100644
index 0000000..7b63181
--- /dev/null
+++ b/Geo/GM_Iterators.h
@@ -0,0 +1,125 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _H_GM_ITERATORS
+#define _H_GM_ITERATORS
+
+#include "ModelInterface.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class GM_RegionIterator {
+
+  private:
+    MAdModel * model;
+    MAdModel::riter iter;
+
+  public:
+    GM_RegionIterator(MAdModel * _model):
+      model(_model)
+    { iter = model->firstRegion(); }
+    GM_RegionIterator(const GM_RegionIterator& it):
+      model(it.model),iter(it.iter) {}
+    ~GM_RegionIterator() {}
+
+    void reset() { iter = model->firstRegion(); }
+    MAdGRegion * next()
+    {
+      if ( iter == model->lastRegion() ) return NULL;
+      MAdGRegion * res = *iter;
+      iter++;
+      return res;
+    }
+  };
+
+  // -------------------------------------------------------------------
+  class GM_FaceIterator {
+
+  private:
+    MAdModel * model;
+    MAdModel::fiter iter;
+
+  public:
+    GM_FaceIterator(MAdModel * _model):
+      model(_model)
+    { iter = model->firstFace(); }
+    GM_FaceIterator(const GM_FaceIterator& it):
+      model(it.model),iter(it.iter) {}
+    ~GM_FaceIterator() {}
+
+    void reset() { iter = model->firstFace(); }
+    MAdGFace * next()
+    {
+      if ( iter == model->lastFace() ) return NULL;
+      MAdGFace * res = *iter;
+      iter++;
+      return res;
+    }
+  };
+
+  // -------------------------------------------------------------------
+  class GM_EdgeIterator {
+
+  private:
+    MAdModel * model;
+    MAdModel::eiter iter;
+
+  public:
+    GM_EdgeIterator(MAdModel * _model):
+      model(_model)
+    { iter = model->firstEdge(); }
+    GM_EdgeIterator(const GM_EdgeIterator& it):
+      model(it.model),iter(it.iter) {}
+    ~GM_EdgeIterator() {}
+
+    void reset() { iter = model->firstEdge(); }
+    MAdGEdge * next()
+    {
+      if ( iter == model->lastEdge() ) return NULL;
+      MAdGEdge * res = *iter;
+      iter++;
+      return res;
+    }
+  };
+
+  // -------------------------------------------------------------------
+  class GM_VertexIterator {
+
+  private:
+    MAdModel * model;
+    MAdModel::viter iter;
+
+  public:
+    GM_VertexIterator(MAdModel * _model):
+      model(_model)
+    { iter = model->firstVertex(); }
+    GM_VertexIterator(const GM_VertexIterator& it):
+      model(it.model),iter(it.iter) {}
+    ~GM_VertexIterator() {}
+
+    void reset() { iter = model->firstVertex(); }
+    MAdGVertex * next()
+    {
+      if ( iter == model->lastVertex() ) return NULL;
+      MAdGVertex * res = *iter;
+      iter++;
+      return res;
+    }
+  };
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Geo/GmshEntities.h b/Geo/GmshEntities.h
new file mode 100644
index 0000000..96c2ded
--- /dev/null
+++ b/Geo/GmshEntities.h
@@ -0,0 +1,34 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _H_MAD_GMSHENTITIES
+#define _H_MAD_GMSHENTITIES
+
+#ifdef _HAVE_GMSH_
+
+#include "gmsh/GEntity.h"
+
+namespace MAd {
+
+  typedef class GEntity MAdGEntity;
+  typedef class GEntityLessThan MAdGEntityLessThan;
+  typedef class GRegion MAdGRegion;
+  typedef class GFace   MAdGFace;
+  typedef class GEdge   MAdGEdge;
+  typedef class GVertex MAdGVertex;
+
+}
+
+#endif
+
+#endif
diff --git a/Geo/GmshModel.cc b/Geo/GmshModel.cc
new file mode 100644
index 0000000..74d754a
--- /dev/null
+++ b/Geo/GmshModel.cc
@@ -0,0 +1,82 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifdef _HAVE_GMSH_
+
+#include "GmshModel.h"
+
+#include "gmsh/discreteRegion.h"
+#include "gmsh/discreteFace.h"
+#include "gmsh/discreteEdge.h"
+#include "gmsh/discreteVertex.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  MAdGEntity * GmshModel::getEntityByTag(int dim, int tag)
+  {
+    switch(dim) {
+    case 3: return getRegionByTag(tag);
+    case 2: return getFaceByTag(tag);
+    case 1: return getEdgeByTag(tag);
+    case 0: return getVertexByTag(tag);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  MAdGRegion * GmshModel::getRegionByTag(int tag)
+  {
+    GRegion * pGR = model->getRegionByTag(tag);
+    if ( !pGR ) {
+      pGR = new discreteRegion(model,tag);
+      model->add(pGR);
+    }
+    return pGR;
+  }
+
+  // -------------------------------------------------------------------
+  MAdGFace * GmshModel::getFaceByTag(int tag)
+  {
+    GFace * pGF = model->getFaceByTag(tag);
+    if ( !pGF ) {
+      pGF = new discreteFace(model,tag);
+      model->add(pGF);
+    }
+    return pGF;
+  }
+
+  // -------------------------------------------------------------------
+  MAdGEdge * GmshModel::getEdgeByTag(int tag)
+  {
+    GEdge * pGE = model->getEdgeByTag(tag);
+    if ( !pGE ) {
+      pGE = new discreteEdge(model,tag,NULL,NULL);
+      model->add(pGE);
+    }
+    return pGE;
+  }
+
+  // -------------------------------------------------------------------
+  MAdGVertex * GmshModel::getVertexByTag(int tag)
+  {
+    GVertex * pGV = model->getVertexByTag(tag);
+    if ( !pGV ) {
+      pGV = new discreteVertex(model,tag);
+      model->add(pGV);
+    }
+    return pGV;
+  }
+
+  // -------------------------------------------------------------------
+}
+
+#endif
diff --git a/Geo/GmshModel.h b/Geo/GmshModel.h
new file mode 100644
index 0000000..63a6f40
--- /dev/null
+++ b/Geo/GmshModel.h
@@ -0,0 +1,90 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _H_GMSHMODEL
+#define _H_GMSHMODEL
+
+#ifdef _HAVE_GMSH_
+
+#include "MAdModel.h"
+#include "GmshEntities.h"
+
+#include "gmsh/GModel.h"
+#include <list>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class GmshModel : public MAdModel {
+
+  public:
+
+    GmshModel(std::string name=""): 
+      MAdModel(name)
+    { 
+      model = new GModel(_name);
+      GModel::current(GModel::list.size() - 1);
+    }
+    ~GmshModel() { if (model) delete model; }
+
+    ModelType type() const { return GMSHMODEL; }
+
+    // Gmsh mesh file format
+    int readMSH(const std::string &filename) { return model->readMSH(filename); }
+  
+    // Gmsh native CAD format
+    int readGEO(const std::string &filename) { return model->readGEO(filename); }
+    int writeGEO(const std::string &filename) { return model->writeGEO(filename); }
+  
+    // OCC formats
+    int readSTEP(const std::string &filename) { return model->readOCCSTEP(filename); }
+    int readBREP(const std::string &filename) { return model->readOCCBREP(filename); }
+    int readIGES(const std::string &filename) { return model->readOCCIGES(filename); }
+
+    GModel * getModel() { return model; }
+
+    // get the number of entities in this model
+    int getNumRegions()  const { return model->getNumRegions();  }
+    int getNumFaces()    const { return model->getNumFaces();    }
+    int getNumEdges()    const { return model->getNumEdges();    }
+    int getNumVertices() const { return model->getNumVertices(); }
+
+    // find the entity with the given tag and create it if not found
+    MAdGEntity * getEntityByTag(int dim, int tag);
+    MAdGRegion * getRegionByTag(int);
+    MAdGFace   * getFaceByTag  (int);
+    MAdGEdge   * getEdgeByTag  (int);
+    MAdGVertex * getVertexByTag(int);
+
+    // get an iterator initialized to the first/last entity in this model.
+    riter firstRegion() { return model->firstRegion(); }
+    fiter firstFace()   { return model->firstFace(); }
+    eiter firstEdge()   { return model->firstEdge(); }
+    viter firstVertex() { return model->firstVertex(); }
+    riter lastRegion()  { return model->lastRegion(); }
+    fiter lastFace()    { return model->lastFace(); }
+    eiter lastEdge()    { return model->lastEdge(); }
+    viter lastVertex()  { return model->lastVertex(); }
+
+  private:
+    GModel * model;
+
+  };
+
+}
+
+// -------------------------------------------------------------------
+
+#endif
+
+#endif
diff --git a/Geo/MAdModel.h b/Geo/MAdModel.h
new file mode 100644
index 0000000..2027fd7
--- /dev/null
+++ b/Geo/MAdModel.h
@@ -0,0 +1,91 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _H_MADMODEL
+#define _H_MADMODEL
+
+#ifdef _HAVE_GMSH_
+#include "GmshEntities.h"
+#else
+#include "NullEntities.h"
+#endif
+#include <string>
+#include <set>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  enum ModelType {
+    NULLMODEL,
+    GMSHMODEL
+  };
+
+  // -------------------------------------------------------------------
+  class MAdModel {
+
+  public:
+
+    MAdModel(std::string name="") { _name = name; }
+    virtual ~MAdModel() {};
+
+    virtual ModelType type() const = 0;
+
+    // Gmsh mesh file format
+    virtual int readMSH(const std::string &name) = 0;
+  
+    // Gmsh native CAD format
+    virtual int readGEO(const std::string &name) = 0;
+    virtual int writeGEO(const std::string &name) = 0;
+  
+    // OCC formats
+    virtual int readSTEP(const std::string &name) = 0;
+    virtual int readBREP(const std::string &name) = 0;
+    virtual int readIGES(const std::string &name) = 0;
+
+    // get the number of entities in this model
+    virtual int getNumRegions()  const = 0;
+    virtual int getNumFaces()    const = 0;
+    virtual int getNumEdges()    const = 0;
+    virtual int getNumVertices() const = 0;
+
+    // find the entity with the given tag and create it if not found
+    virtual MAdGEntity * getEntityByTag(int dim, int tag) = 0;
+    virtual MAdGRegion * getRegionByTag(int) = 0;
+    virtual MAdGFace   * getFaceByTag  (int) = 0;
+    virtual MAdGEdge   * getEdgeByTag  (int) = 0;
+    virtual MAdGVertex * getVertexByTag(int) = 0;
+
+    typedef std::set<MAdGRegion*, MAdGEntityLessThan>::iterator riter;
+    typedef std::set<MAdGFace*,   MAdGEntityLessThan>::iterator fiter;
+    typedef std::set<MAdGEdge*,   MAdGEntityLessThan>::iterator eiter;
+    typedef std::set<MAdGVertex*, MAdGEntityLessThan>::iterator viter;
+
+    // get an iterator initialized to the first/last entity in this model.
+    virtual riter firstRegion() = 0;
+    virtual fiter firstFace() = 0;
+    virtual eiter firstEdge() = 0;
+    virtual viter firstVertex() = 0;
+    virtual riter lastRegion() = 0;
+    virtual fiter lastFace() = 0;
+    virtual eiter lastEdge() = 0;
+    virtual viter lastVertex() = 0;
+
+  protected:
+    std::string _name;
+  };
+
+}
+
+// -------------------------------------------------------------------
+
+#endif
diff --git a/Geo/Makefile b/Geo/Makefile
new file mode 100644
index 0000000..7cabadf
--- /dev/null
+++ b/Geo/Makefile
@@ -0,0 +1,53 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information. 
+# You should have received a copy of these files along with MAdLib. 
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../variables
+
+LIB = ../lib/libMAdGeo${LIBEXT}
+
+INC =  ${MAdLib_INCLUDES}\
+       ${DASH}I$(MAdROOT)/Geo\
+       ${DASH}I$(MAdROOT)/Mesh\
+       ${DASH}I$(MAdROOT)/Common
+
+ALLFLAGS = ${OPTIM} ${CXXFLAGS} ${MAdLib_DEFS} ${FLAGS} ${INC} ${SYSINCLUDE}
+
+SRC = GmshModel.cc\
+      ModelInterface.cc\
+      NullModel.cc
+
+OBJ = ${SRC:.cc=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cc
+
+${LIB}: ${OBJ} 
+	${AR} ${ARFLAGS} ${LIB} ${OBJ}
+	${RANLIB} ${LIB}
+
+cpobj: ${OBJ} 
+	cp -f ${OBJ} ${MAdLib_TMPDIR}/.
+
+.cc${OBJEXT}:
+	${CXX} ${ALLFLAGS} ${DASH}c $< ${DASH}o $@
+
+clean:
+	${RM} */*.o *.o *.obj
+
+purge:
+
+depend:
+	(sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+         ${CXX} -MM ${ALLFLAGS} ${SRC} | sed 's/.o:/$${OBJEXT}:/g' \
+        ) > Makefile.new
+	cp Makefile Makefile.bak
+	cp Makefile.new Makefile
+	rm -f Makefile.new
\ No newline at end of file
diff --git a/Geo/ModelInterface.cc b/Geo/ModelInterface.cc
new file mode 100644
index 0000000..6f13763
--- /dev/null
+++ b/Geo/ModelInterface.cc
@@ -0,0 +1,649 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "ModelInterface.h"
+#include "MathUtils.h"
+#include "MAdMessage.h"
+#include "MAdDefines.h"
+
+#include <string.h>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  void GM_create(pGModel* model, std::string name)
+  { 
+    if (*model) delete (*model);
+#ifdef _HAVE_GMSH_
+    *model = new GmshModel(name);
+#else
+    *model = new NullModel(name);
+#endif
+  }
+
+  // -------------------------------------------------------------------
+  void GM_delete(pGModel model)
+  { 
+    if (model) { delete model; model=NULL; }
+  }
+  
+  // -------------------------------------------------------------------
+  enum GeoFileFormat {
+    FORMAT_MSH,
+    FORMAT_GEO,
+    FORMAT_STEP,
+    FORMAT_BREP,
+    FORMAT_IGES,
+    FORMAT_UNKNOWN
+  };
+
+  // -------------------------------------------------------------------
+  std::vector<std::string> SplitFileName(std::string fileName)
+  {
+    // returns [path, baseName, extension]
+    int idot = fileName.find_last_of('.');
+    int islash = fileName.find_last_of("/\\");
+    if(idot == std::string::npos) idot = -1;
+    if(islash == std::string::npos) islash = -1;
+    std::vector<std::string> s(3);
+    if(idot > 0)
+      s[2] = fileName.substr(idot);
+    if(islash > 0)
+      s[0] = fileName.substr(0, islash + 1);
+    s[1] = fileName.substr(s[0].size(), fileName.size() - s[0].size() - s[2].size());
+    return s;
+  }
+
+  // -------------------------------------------------------------------
+  GeoFileFormat guessFormatFromExtension(const std::string fileName)
+  {
+    std::string ext = SplitFileName(fileName)[2];
+    if     ( !strcmp(ext.c_str(),".msh" ) )  return FORMAT_MSH;
+    if     ( !strcmp(ext.c_str(),".geo" ) )  return FORMAT_GEO;
+    if     ( !strcmp(ext.c_str(),".stp" ) )  return FORMAT_STEP;
+    if     ( !strcmp(ext.c_str(),".step") )  return FORMAT_STEP;
+    if     ( !strcmp(ext.c_str(),".brep") )  return FORMAT_BREP;
+    if     ( !strcmp(ext.c_str(),".iges") )  return FORMAT_IGES;
+    return FORMAT_UNKNOWN;
+  }
+
+  // -------------------------------------------------------------------
+  int GM_read(pGModel model, const std::string fileName)
+  {
+    GeoFileFormat format = guessFormatFromExtension(fileName);
+    if ( format == FORMAT_MSH  ) return GM_readFromMSH (model,fileName);
+    if ( format == FORMAT_GEO  ) return GM_readFromGEO (model,fileName);
+    if ( format == FORMAT_STEP ) return GM_readFromSTEP(model,fileName);
+    if ( format == FORMAT_BREP ) return GM_readFromBREP(model,fileName);
+    if ( format == FORMAT_IGES ) return GM_readFromIGES(model,fileName);
+    MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                "Unknown geo file format %d",format);
+    return 0;
+  }
+
+  // -------------------------------------------------------------------
+  int GM_readFromMSH(pGModel model, const std::string name)
+  {
+    return (model->readMSH(name));
+  }
+
+  // -------------------------------------------------------------------
+  int GM_readFromGEO(pGModel model, const std::string name)
+  {
+    return (model->readGEO(name));
+  }
+
+  // -------------------------------------------------------------------
+  int GM_readFromSTEP(pGModel model, const std::string name)
+  {
+    return (model->readSTEP(name));
+  }
+
+  // -------------------------------------------------------------------
+  int GM_readFromBREP(pGModel model, const std::string name)
+  {
+    return (model->readBREP(name));
+  }
+
+  // -------------------------------------------------------------------
+  int GM_readFromIGES(pGModel model, const std::string name)
+  {
+    return (model->readIGES(name));
+  }
+
+  // -------------------------------------------------------------------
+  int GM_writeGEO(pGModel model, const std::string &name)
+  {
+    return (model->writeGEO(name));
+  }
+
+  // -------------------------------------------------------------------
+  pGEntity GM_entityByTag(pGModel model, int dim, int tag)
+  {
+    return model->getEntityByTag(dim,tag);
+  }
+  pGRegion GM_regionByTag(const pGModel model, int tag)
+  {
+    return model->getRegionByTag(tag);
+  }
+  pGFace GM_faceByTag(const pGModel model, int tag)
+  {
+    return model->getFaceByTag(tag);
+  }
+  pGEdge GM_edgeByTag(const pGModel model, int tag)
+  {
+    return model->getEdgeByTag(tag);
+  }
+  pGVertex GM_vertexByTag(const pGModel model, int tag)
+  {
+    return model->getVertexByTag(tag);
+  }
+
+  // -------------------------------------------------------------------
+  int GM_numVertices(const pGModel model)
+  {
+    return model->getNumVertices();
+  }
+  int GM_numEdges(const pGModel model)
+  {
+    return model->getNumEdges();
+  }
+  int GM_numFaces(const pGModel model)
+  {
+    return model->getNumFaces();
+  }
+  int GM_numRegions(const pGModel model)
+  {
+    return model->getNumRegions();
+  }
+
+  // -------------------------------------------------------------------
+  GRIter GM_regionIter(pGModel model)
+  {
+    return new GM_RegionIterator(model);
+  }
+  GFIter GM_faceIter(pGModel model)
+  {
+    return new GM_FaceIterator(model);
+  }
+  GEIter GM_edgeIter(pGModel model)
+  {
+    return new GM_EdgeIterator(model);
+  }
+  GVIter GM_vertexIter(pGModel model)
+  {
+    return new GM_VertexIterator(model);
+  }
+
+  pGRegion GRIter_next(GRIter iter) { return iter->next(); }
+  pGFace   GFIter_next(GFIter iter) { return iter->next(); }
+  pGEdge   GEIter_next(GEIter iter) { return iter->next(); }
+  pGVertex GVIter_next(GVIter iter) { return iter->next(); }
+
+  void GRIter_delete(GRIter iter) { delete (iter); }
+  void GFIter_delete(GFIter iter) { delete (iter); }
+  void GEIter_delete(GEIter iter) { delete (iter); }
+  void GVIter_delete(GVIter iter) { delete (iter); }
+
+  void GRIter_reset(GRIter iter) { iter->reset(); }
+  void GFIter_reset(GFIter iter) { iter->reset(); }
+  void GEIter_reset(GEIter iter) { iter->reset(); }
+  void GVIter_reset(GVIter iter) { iter->reset(); }
+
+  // -------------------------------------------------------------------
+  int GEN_tag(const pGEntity ent)
+  {
+    return ent->tag();
+  }
+
+  // -------------------------------------------------------------------
+  int GEN_type(const pGEntity ent)
+  {
+    return ent->dim();
+  }
+
+#ifdef _HAVE_GMSH_
+  // -------------------------------------------------------------------
+  std::list<pGEntity> GEN_closure(const pGEntity pGE)
+  {
+    std::list<pGEntity> theList;
+
+    int type = GEN_type(pGE);
+    switch (type) {
+    case 0: break;
+    case 1: {
+      std::list<pGVertex> vList = GE_vertices((pGEdge)pGE);
+      std::list<pGVertex>::const_iterator vIter = vList.begin();
+      for (; vIter != vList.end(); vIter++) {
+        theList.push_back(*vIter);
+      }
+      break;
+    }
+    case 2: {
+      std::list<pGEdge> eList = GF_edges((pGFace)pGE);
+      std::list<pGEdge>::const_iterator eIter = eList.begin();
+      for (; eIter != eList.end(); eIter++) {
+        theList.push_back(*eIter);
+      }
+      break;
+    }
+    case 3: {
+      std::list<pGFace> fList = GR_faces((pGRegion)pGE);
+      std::list<pGFace>::const_iterator fIter = fList.begin();
+      for (; fIter != fList.end(); fIter++) {
+        theList.push_back(*fIter);
+      }
+      break;
+    }
+    }
+
+    return theList;
+  }
+
+  // -------------------------------------------------------------------
+  std::list<pGFace> GR_faces(const pGRegion pGR)
+  {
+    return pGR->faces();
+  }
+
+  // -------------------------------------------------------------------
+  int GF_numRegions(const pGFace f)
+  {
+    return f->numRegions();
+  }
+
+  // -------------------------------------------------------------------
+  std::list<pGEdge> GF_edges(const pGFace pGF)
+  {
+    return pGF->edges();
+  }
+
+  // -------------------------------------------------------------------
+  //! Computes the parameter location of xyz in the surface. 
+  //! Returns false if xyz is not in the surface.
+  bool GF_getParams(const pGFace pGF, const double xyz[3], 
+                    double params[2])
+  {
+    //   SPoint2 sP = pGF->parFromPoint(SPoint3(xyz));
+    //   params[0] = sP.x();
+    //   params[1] = sP.y();
+
+    pGF->XYZtoUV( xyz[0], xyz[1], xyz[2],
+                  params[0], params[1], 1.);
+
+    //    throw;
+
+    // a test should be done to check that xyz was on the surface
+
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  //! Computes the coordinates of the point on the surface closest to xyz
+  void GF_closestPoint(const pGFace pGF, const double xyz[3],
+                       const double initGuess[2], double xyzOnF[3])
+  {
+    //   GPoint gP = pGF->closestPoint( SPoint3(xyz), initGuess );
+    //   xyzOnF[0] = gP.x();
+    //   xyzOnF[1] = gP.y();
+    //   xyzOnF[2] = gP.z();
+    throw;
+  }
+
+  // -------------------------------------------------------------------
+  void GF_xyz(const pGFace pGF, double u, double v, double xyz[3])
+  {
+    GPoint gP = pGF->point(u,v);
+    xyz[0] = gP.x();
+    xyz[1] = gP.y();
+    xyz[2] = gP.z();
+  }
+
+  // -------------------------------------------------------------------
+  //! Gets the curvature of the surface computed as the divergence of its normal
+  //! Result is bounded by cMaxBound. NaN curvatures are turned into cMaxBound.
+  double GF_curvatureDiv(const pGFace surface, const double u[2], 
+                         double cMaxBound)
+  {
+    SPoint2 param(u[0],u[1]);
+    double curv = surface->curvatureDiv(param);
+    if ( isnan(curv) ) {
+      MAdMsgSgl::instance().warning(__LINE__,__FILE__,"NaN curvature");
+      curv = cMaxBound;
+    }
+    return std::min(curv,cMaxBound);
+  }
+
+  // -------------------------------------------------------------------
+  //! Compute the min and max curvatures and the corresponding directions.
+  //! Returns the max curvature.
+  //! Min and max curvatures are bounded by cMaxBound. 
+  //! NaN curvatures are turned into cMaxBound.
+  double GF_curvatures(const pGFace surface, const double u[2],
+                       double dirMax[3], double dirMin[3],
+                       double *curvMax, double *curvMin, 
+                       double cMaxBound)
+  {
+    SPoint2 param(u[0],u[1]);
+    SVector3 dirMaxTmp = SVector3();
+    SVector3 dirMinTmp = SVector3();
+
+    surface->curvatures(param, &dirMaxTmp, &dirMinTmp, curvMax, curvMin);
+
+    dirMax[0] = dirMaxTmp.x();
+    dirMax[1] = dirMaxTmp.y();
+    dirMax[2] = dirMaxTmp.z();
+    if ( ( dotProd(dirMax,dirMax) <= MAdTOL ) ||
+         ( isnan(dirMax[0]) || isnan(dirMax[1]) || isnan(dirMax[2]) ) )
+      {
+        MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+                                      "NaN direction for maximum curvature");
+        dirMax[0] = 0.36436431;
+        dirMax[1] = 0.76356436;
+        dirMax[2] = 0.96983673;
+      }
+    
+    dirMin[0] = dirMinTmp.x();
+    dirMin[1] = dirMinTmp.y();
+    dirMin[2] = dirMinTmp.z();
+    if ( ( dotProd(dirMin,dirMin) <= MAdTOL ) ||
+         ( isnan(dirMin[0]) || isnan(dirMin[1]) || isnan(dirMin[2]) ) )
+      {
+        MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+                                      "Inconsistent direction for minimum curvature (u,v)=(%f,%f), direction: %f, %f, %f, curvature: %f",
+                                      u[0],u[1],dirMin[0],dirMin[1],dirMin[2],*curvMin);
+        double tmp[3] = { 0.86684859, 0.69576964, 0.39876864 };
+        crossProd(tmp,dirMax,dirMin);
+      }
+    
+    if ( isnan(*curvMax) ) {
+      MAdMsgSgl::instance().warning(__LINE__,__FILE__,"NaN maximum curvature");
+      *curvMax = cMaxBound;
+    }
+    *curvMax = std::min(*curvMax,cMaxBound);
+    if ( isnan(*curvMin) ) {
+      MAdMsgSgl::instance().warning(__LINE__,__FILE__,"NaN minimum curvature");
+      *curvMin = cMaxBound;
+    }
+    *curvMin = std::min(*curvMin,cMaxBound);
+
+    return *curvMax;
+  }
+
+  // -------------------------------------------------------------------
+  //! Computes the parametric coordinates of the point of an edge on 
+  //! a geodesic of the surface. t is the location on the edge ( 0 <= t <= 1 ).
+  void GF_centerOnGeodesic(const pGFace face, double t, 
+                           const double e[2][2], double c[2])
+  {
+    SPoint2 pt1(e[0][0],e[0][1]);
+    SPoint2 pt2(e[1][0],e[1][1]);
+    SPoint2 res = face->geodesic(pt1,pt2,t);
+    c[0] = res.x();
+    c[1] = res.y();
+  }
+
+  // -------------------------------------------------------------------
+  std::list<pGVertex> GE_vertices(const pGEdge pGE)
+  {
+    return pGE->vertices();
+  }
+
+  // -------------------------------------------------------------------
+  //! Computes the coordinates of the point on the line closest to xyz
+  void GE_closestPoint(const pGEdge pGE, const double xyz[3], 
+                       double xyzOnE[3])
+  {
+    //   GPoint gP = pGE->closestPoint( SPoint3(xyz) );
+    //   xyzOnE[0] = gP.x();
+    //   xyzOnE[1] = gP.y();
+    //   xyzOnE[2] = gP.z();
+    throw;
+  }
+
+  // -------------------------------------------------------------------
+  void GE_xyz(const pGEdge pGE, double u, double xyz[3])
+  {
+    GPoint gP = pGE->point(u);
+    xyz[0] = gP.x();
+    xyz[1] = gP.y();
+    xyz[2] = gP.z();
+  }
+
+  // -------------------------------------------------------------------
+  //! Given an edge which is a seam of the face, and a point of 
+  //! the edge with parametric coordinate uOnE on the edge, 
+  //! find the parametric coordinates of the point on the face.
+  //! uClose are the parametric coordinates of a close point of 
+  //! face used to determine the direction for the parametrization.
+  void GE_reparamOnFace(const pGEdge edge, const pGFace face, 
+                        double uOnE, double uOnF[2], double uClose[2])
+  {
+    //   assert( edge->isSeam(face) );
+
+    SPoint2 pt = edge->reparamOnFace(face, uOnE, 0);
+    uOnF[0] = pt.x();
+    uOnF[1] = pt.y();
+
+    if ( uClose )
+      {
+        double dist = 
+          ( uClose[0] - pt.x() ) * ( uClose[0] - pt.x() ) +
+          ( uClose[1] - pt.y() ) * ( uClose[1] - pt.y() );
+
+        SPoint2 pt2 = edge->reparamOnFace(face, uOnE, 1);
+        double dist2 = 
+          ( uClose[0] - pt2.x() ) * ( uClose[0] - pt2.x() ) +
+          ( uClose[1] - pt2.y() ) * ( uClose[1] - pt2.y() );
+
+        if ( dist2 < dist ) {
+          uOnF[0] = pt2.x();
+          uOnF[1] = pt2.y();
+        }
+      }
+  }
+
+  // -------------------------------------------------------------------
+  //! true if the edge is a seam for the given face.
+  bool GE_isSeam(const pGEdge edge, const pGFace face)
+  {
+    return edge->isSeam(face);
+  }
+
+  // -------------------------------------------------------------------
+  //! gets the curvature of the line at that point bounded by cMaxBound
+  double GE_curvature(const pGEdge line, double u, double cMaxBound)
+  {
+    double curv = line->curvature(u);
+    if ( isnan(curv) ) {
+      MAdMsgSgl::instance().warning(__LINE__,__FILE__,"NaN curvature");
+      curv = cMaxBound;
+    }
+    return std::min(curv,cMaxBound);
+  }
+
+  // -------------------------------------------------------------------
+  //! returns a list of the lines including the vertex
+  std::list<pGEdge> GV_edges(const pGVertex pGV)
+  {
+    return pGV->edges();
+  }
+
+  // -------------------------------------------------------------------
+  //! Given a geometric vertex which is on the face, find the parametric 
+  //! coordinates of the vertex on the face.
+  //! uClose are the parametric coordinates of a close point of 
+  //! face used to determine the direction for the parametrization.
+  void GV_reparamOnFace(const pGVertex vertex, const pGFace face, 
+                        double uOnF[2], double uClose[2])
+  {
+    SPoint2 pt = vertex->reparamOnFace(face, 0);
+    uOnF[0] = pt.x();
+    uOnF[1] = pt.y();
+
+    if ( uClose )
+      {
+        double dist = 
+          ( uClose[0] - pt.x() ) * ( uClose[0] - pt.x() ) +
+          ( uClose[1] - pt.y() ) * ( uClose[1] - pt.y() );
+
+        SPoint2 pt2 = vertex->reparamOnFace(face, 1);
+        double dist2 = 
+          ( uClose[0] - pt2.x() ) * ( uClose[0] - pt2.x() ) +
+          ( uClose[1] - pt2.y() ) * ( uClose[1] - pt2.y() );
+
+        if ( dist2 < dist ) {
+          uOnF[0] = pt2.x();
+          uOnF[1] = pt2.y();
+        }
+      }
+  }
+
+  // -------------------------------------------------------------------
+  //! Given a geometric vertex which is on the edge, find the parametric 
+  //! coordinates of the vertex on the edge.
+  //! uClose is the parametric coordinate of a close point of 
+  //! edge used to determine the direction for the parametrization.
+  void GV_reparamOnEdge(const pGVertex vertex, const pGEdge edge, 
+                        double * uOnE, double uClose)
+  {
+    Range<double> range = edge->parBounds(0);
+
+    if ( uClose >= 0. && 
+         vertex == edge->getBeginVertex() && 
+         vertex == edge->getEndVertex() ) {
+      *uOnE = range.low();
+      double dist  = ( uClose - *uOnE ) * ( uClose - *uOnE );
+      double dist2 = ( uClose - range.high() ) * ( uClose - range.high() );
+      if ( dist2 < dist ) *uOnE = range.high();
+      return;
+    }
+
+    if ( vertex == edge->getBeginVertex() ) { *uOnE = range.low();  return; }
+    if ( vertex == edge->getEndVertex() )   { *uOnE = range.high(); return; }
+
+    MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                "GVertex not in the closure of the GEdge");
+  }
+
+  // -------------------------------------------------------------------
+  //! Return true if the vertex is on a seam of the given face
+  bool GV_isOnSeam(const pGVertex vert, const pGFace face)
+  {
+    return vert->isOnSeam(face);
+  }
+
+#else
+
+  // -------------------------------------------------------------------
+  void GF_centerOnGeodesic(const pGFace face, double t,
+                           const double e[2][2], double c[2])
+  {
+    MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                "Using geodesics requires Gmsh");
+  }
+
+#endif
+
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  // PGList functions
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  PGList * PGList_new()
+  {
+    return new PGList();
+  }
+
+  // -------------------------------------------------------------------
+  void PGList_delete(PGList * lst)
+  {
+    if (lst) delete lst;
+    lst = NULL;
+  }
+
+  // -------------------------------------------------------------------
+  void PGList_clear(PGList * lst)
+  {
+    lst->clear();
+  }
+
+  // -------------------------------------------------------------------
+  PGList * PGList_appUnique(PGList * lst, pGEntity ent)
+  {
+    for ( unsigned int i=0; i<lst->entities.size(); i++ ) {
+      if ( lst->entities[i] == ent ) return lst;
+    }
+    lst->entities.push_back(ent);
+    return lst;
+  }
+
+  // -------------------------------------------------------------------
+  PGList * PGList_appPGListUnique(PGList * lst, PGList * source)
+  {
+    for ( unsigned int iSrc=0; iSrc<source->entities.size(); iSrc++ ) {
+      PGList_appUnique(lst,source->entities[iSrc]);
+    }
+    return lst;
+  }
+
+  // -------------------------------------------------------------------
+  PGList * PGList_append(PGList * lst, pGEntity ent)
+  {
+    lst->entities.push_back(ent);
+    return lst;
+  }
+
+  // -------------------------------------------------------------------
+  int PGList_size(PGList * lst)
+  {
+    return lst->entities.size();
+  }
+
+  // -------------------------------------------------------------------
+  pGEntity PGList_item(PGList * lst, int i)
+  {
+    return lst->entities[i];
+  }
+
+  // -------------------------------------------------------------------
+  pGEntity PGList_next(PGList * lst, void **restart)
+  {
+    if( *(int*)(restart) >= (int)lst->entities.size() ) return NULL;
+    return lst->entities[(*(int*)(restart))++];
+  }
+
+  // -------------------------------------------------------------------
+  int PGList_inList(PGList * lst, pGEntity ent)
+  {
+    for ( unsigned int i=0; i<lst->entities.size(); i++ ) {
+      if ( lst->entities[i] == ent ) return 1;
+    }
+    return 0;
+  }
+
+  // -------------------------------------------------------------------
+  void PGList_remItem(PGList * lst, pGEntity ent)
+  {
+    std::vector<pGEntity>::iterator eIter = lst->entities.begin();
+    for (; eIter != lst->entities.end() ; eIter++) {
+      if ( *eIter == ent ) lst->entities.erase(eIter);
+    }
+  }
+
+  // -------------------------------------------------------------------
+
+
+}
+
diff --git a/Geo/ModelInterface.h b/Geo/ModelInterface.h
new file mode 100644
index 0000000..fb3b1e5
--- /dev/null
+++ b/Geo/ModelInterface.h
@@ -0,0 +1,178 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _H_MODELINTERFACE
+#define _H_MODELINTERFACE
+
+#include <string>
+#include <list>
+
+#ifdef _HAVE_GMSH_
+#include "GmshModel.h"
+#else
+#include "NullModel.h"
+#endif
+
+#include "GM_Iterators.h"
+#include "PGList.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  typedef MAdModel *   pGModel;
+  typedef MAdGEntity * pGEntity;
+  typedef MAdGRegion * pGRegion;
+  typedef MAdGFace   * pGFace;
+  typedef MAdGEdge   * pGEdge;
+  typedef MAdGVertex * pGVertex;
+
+  typedef GM_RegionIterator * GRIter;
+  typedef GM_FaceIterator   * GFIter;
+  typedef GM_EdgeIterator   * GEIter;
+  typedef GM_VertexIterator * GVIter;
+
+  typedef PGList * pPGList;
+
+  // -------------------------------------------------------------------
+
+  // --- Model operators ---
+
+  // create an empty model
+  void GM_create(pGModel * model, std::string name="");
+
+  // delete the model
+  void GM_delete(pGModel model);
+
+  // read a model, guess file format from extension
+  int  GM_read(pGModel model, const std::string name);
+
+  // read particular file formats
+  int  GM_readFromMSH(pGModel model, const std::string name);
+  int  GM_readFromGEO(pGModel model, const std::string name);
+  int  GM_readFromSTEP(pGModel model, const std::string name);
+  int  GM_readFromBREP(pGModel model, const std::string name);
+  int  GM_readFromIGES(pGModel model, const std::string name);
+
+  // write geometry in a GEO format file (Gmsh native CAD format)
+  int  GM_writeGEO(pGModel model, const std::string &name);
+  // void GM_diagnostics(const pGModel model);
+
+  // Find the entity with the given tag. 
+  // Create it if it doesn't exist.
+  pGEntity GM_entityByTag(const pGModel model, int type, int tag);
+  pGRegion GM_regionByTag(const pGModel model, int tag);
+  pGFace   GM_faceByTag  (const pGModel model, int tag);
+  pGEdge   GM_edgeByTag  (const pGModel model, int tag);
+  pGVertex GM_vertexByTag(const pGModel model, int tag);
+
+  int GM_numVertices(const pGModel);
+  int GM_numEdges(const pGModel);
+  int GM_numFaces(const pGModel);
+  int GM_numRegions(const pGModel);
+
+  // --- Iterators ---
+
+  GRIter GM_regionIter(pGModel);
+  GFIter GM_faceIter(pGModel);
+  GEIter GM_edgeIter(pGModel);
+  GVIter GM_vertexIter(pGModel);
+
+  pGRegion GRIter_next(GRIter);
+  pGFace GFIter_next(GFIter);
+  pGEdge GEIter_next(GEIter);
+  pGVertex GVIter_next(GVIter);
+
+  void GRIter_delete(GRIter);
+  void GFIter_delete(GFIter);
+  void GEIter_delete(GEIter);
+  void GVIter_delete(GVIter);
+
+  void GRIter_reset(GRIter);
+  void GFIter_reset(GFIter);
+  void GEIter_reset(GEIter);
+  void GVIter_reset(GVIter);
+
+  // --- Entity operators ---
+
+  int GEN_tag(const pGEntity);
+  int GEN_type(const pGEntity);
+
+#ifdef _HAVE_GMSH_
+  std::list<pGEntity> GEN_closure(const pGEntity);
+
+  // --- Region operators ---
+
+  std::list<pGFace> GR_faces(const pGRegion);
+
+  // --- Face operators ---
+
+  int GF_numRegions(const pGFace);
+  std::list<pGEdge> GF_edges(const pGFace);
+  bool GF_getParams(const pGFace, const double[3], double[2]);
+  void GF_closestPoint(const pGFace, const double[3],
+                       const double[2], double[3]);
+  void GF_xyz(const pGFace, double, double, double[3]);
+  double GF_curvatureDiv(const pGFace, const double[2], 
+                         double cMaxBound);
+  double GF_curvatures(const pGFace, const double[2],
+                       double dirMax[3], double dirMin[3],
+                       double *curvMax, double *curvMin, 
+                       double cMaxBound);
+  void GF_centerOnGeodesic(const pGFace face, double t,
+                           const double e[2][2], double c[2]);
+
+  // --- Edge operators ---
+
+  std::list<pGVertex> GE_vertices(const pGEdge);
+  void GE_closestPoint(const pGEdge, const double[3], double[3]);
+  void GE_xyz(const pGEdge, double, double[3]);
+  void GE_reparamOnFace(const pGEdge, const pGFace, 
+                        double, double[2], double uClose[2]=NULL);
+  bool GE_isSeam(const pGEdge, const pGFace);
+  double GE_curvature(const pGEdge, double, double);
+
+  // --- Vertex operators ---
+
+  std::list<pGEdge> GV_edges(const pGVertex);
+
+  void GV_reparamOnFace(const pGVertex, const pGFace, double [2], 
+                        double uClose[2]=NULL);
+  void GV_reparamOnEdge(const pGVertex, const pGEdge, double *, 
+                        double uClose=-1.);
+  bool GV_isOnSeam(const pGVertex, const pGFace);
+#else
+  void GF_centerOnGeodesic(const pGFace face, double t,
+                           const double e[2][2], double c[2]);
+#endif
+
+  // --- pGList operators ---
+
+  pPGList  PGList_new();
+  pPGList  PGList_allocate();
+  void     PGList_delete          (pPGList);
+  void     PGList_deallocate      (pPGList);
+  void     PGList_clear           (pPGList);
+  pPGList  PGList_appPGListUnique (pPGList, pPGList source);
+  pPGList  PGList_appUnique       (pPGList, pGEntity);
+  pPGList  PGList_append          (pPGList, pGEntity);
+  int      PGList_size            (pPGList); 
+  pGEntity PGList_item            (pPGList, int n);
+  pGEntity PGList_next            (pPGList, void ** restart);
+  int      PGList_inList          (pPGList, pGEntity);
+  void     PGList_remItem         (pPGList, pGEntity);
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Geo/NullEntities.h b/Geo/NullEntities.h
new file mode 100644
index 0000000..9eaf244
--- /dev/null
+++ b/Geo/NullEntities.h
@@ -0,0 +1,102 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _H_NULLENTITIES
+#define _H_NULLENTITIES
+
+#ifndef _HAVE_GMSH_
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class NullGEntity {
+
+  public:
+    NullGEntity(): _tag(-1) {}
+    NullGEntity(int tag): _tag(tag) {}
+    NullGEntity(const NullGEntity& ge): _tag(ge._tag) {}
+    virtual ~NullGEntity() {}
+
+    virtual int dim() const { return -1; }
+    virtual int tag() const { return _tag; }
+
+  private:
+    int _tag;
+  };
+
+  // -------------------------------------------------------------------
+  class NullGEntityLessThan {
+  public:
+    bool operator()(const NullGEntity *ent1, const NullGEntity *ent2) const
+    { return ent1->tag() < ent2->tag(); }
+  };
+
+  // -------------------------------------------------------------------
+  class NullGRegion : public NullGEntity {
+
+  public:
+    NullGRegion() : NullGEntity() {}
+    NullGRegion(int tag) : NullGEntity(tag) {}
+    NullGRegion(const NullGRegion& gr) : NullGEntity(gr) {}
+    virtual ~NullGRegion() {}
+    int dim() const { return 3; }
+  };
+
+  // -------------------------------------------------------------------
+  class NullGFace : public NullGEntity {
+
+  public:
+    NullGFace() : NullGEntity() {}
+    NullGFace(int tag) : NullGEntity(tag) {}
+    NullGFace(const NullGFace& gf) : NullGEntity(gf) {}
+    virtual ~NullGFace() {}
+    int dim() const { return 2; }
+  };
+
+  // -------------------------------------------------------------------
+  class NullGEdge : public NullGEntity {
+
+  public:
+    NullGEdge() : NullGEntity() {}
+    NullGEdge(int tag) : NullGEntity(tag) {}
+    NullGEdge(const NullGEdge& ge) : NullGEntity(ge) {}
+    virtual ~NullGEdge() {}
+    int dim() const { return 1; }
+  };
+
+  // -------------------------------------------------------------------
+  class NullGVertex : public NullGEntity {
+
+  public:
+    NullGVertex() : NullGEntity() {}
+    NullGVertex(int tag) : NullGEntity(tag) {}
+    NullGVertex(const NullGVertex& gv) : NullGEntity(gv) {}
+    virtual ~NullGVertex() {}
+    int dim() const { return 0; }
+  };
+
+  // -------------------------------------------------------------------
+  typedef class NullGEntity MAdGEntity;
+  typedef class NullGEntityLessThan MAdGEntityLessThan;
+  typedef class NullGRegion MAdGRegion;
+  typedef class NullGFace   MAdGFace;
+  typedef class NullGEdge   MAdGEdge;
+  typedef class NullGVertex MAdGVertex;
+
+  // -------------------------------------------------------------------
+}
+
+#endif
+
+#endif
+
diff --git a/Geo/NullModel.cc b/Geo/NullModel.cc
new file mode 100644
index 0000000..9c8bd56
--- /dev/null
+++ b/Geo/NullModel.cc
@@ -0,0 +1,288 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _HAVE_GMSH_
+
+#include "NullModel.h"
+
+#include "MAdMessage.h"
+#include "MshTags.h"
+
+#include <stdio.h>
+#include <set>
+using std::set;
+#include <string.h>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  NullModel::~NullModel()
+  {
+    clean();
+  }
+
+  // -------------------------------------------------------------------
+  void NullModel::clean()
+  {
+    riter itR = regions.begin();
+    for (; itR != regions.end(); itR++) delete (*itR);
+    regions.clear();
+    fiter itF = faces.begin();
+    for (; itF != faces.end(); itF++) delete (*itF);
+    faces.clear();
+    eiter itE = edges.begin();
+    for (; itE != edges.end(); itE++) delete (*itE);
+    edges.clear();
+    viter itV = vertices.begin();
+    for (; itV != vertices.end(); itV++) delete (*itV);
+    vertices.clear();
+  }
+
+  // -------------------------------------------------------------------
+  MAdGEntity * NullModel::getEntityByTag(int dim, int tag)
+  {
+    switch(dim) {
+    case 3: return getRegionByTag(tag);
+    case 2: return getFaceByTag(tag);
+    case 1: return getEdgeByTag(tag);
+    case 0: return getVertexByTag(tag);
+    }
+    return NULL;
+  }
+
+  // -------------------------------------------------------------------
+  MAdGRegion *NullModel::getRegionByTag(int tag)
+  {
+    set<MAdGRegion *,MAdGEntityLessThan>::const_iterator it = regions.begin();
+    for (; it != regions.end(); it++) {
+      if ( (*it)->tag() == tag ) return *it;
+    }
+    MAdGRegion * newRegion = new MAdGRegion(tag);
+    regions.insert(newRegion);
+    return newRegion;
+  }
+
+  // -------------------------------------------------------------------
+  MAdGFace *NullModel::getFaceByTag(int tag)
+  {
+    set<MAdGFace *,MAdGEntityLessThan>::const_iterator it = faces.begin();
+    for (; it != faces.end(); it++) {
+      if ( (*it)->tag() == tag ) return *it;
+    }
+    MAdGFace * newFace = new MAdGFace(tag);
+    faces.insert(newFace);
+    return newFace;
+  }
+
+  // -------------------------------------------------------------------
+  MAdGEdge *NullModel::getEdgeByTag(int tag)
+  {
+    set<MAdGEdge *,MAdGEntityLessThan>::const_iterator it = edges.begin();
+    for (; it != edges.end(); it++) {
+      if ( (*it)->tag() == tag ) return *it;
+    }
+    MAdGEdge * newEdge = new MAdGEdge(tag);
+    edges.insert(newEdge);
+    return newEdge;
+  }
+
+  // -------------------------------------------------------------------
+  MAdGVertex *NullModel::getVertexByTag(int tag)
+  {
+    set<MAdGVertex *,MAdGEntityLessThan>::const_iterator it = vertices.begin();
+    for (; it != vertices.end(); it++) {
+      if ( (*it)->tag() == tag ) return *it;
+    }
+    MAdGVertex * newVertex = new MAdGVertex(tag);
+    vertices.insert(newVertex);
+    return newVertex;
+  }
+
+  // -------------------------------------------------------------------
+  int NullModel::readGEO(const std::string &filename)
+  {
+    MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                "Reading a model from a .geo file not implemented in NullModel");
+  }
+
+  // -------------------------------------------------------------------
+  void SwapBytes(char *array, int size, int n)
+  {
+    char *x = new char[size];
+    for(int i = 0; i < n; i++) {
+      char *a = &array[i * size];
+      memcpy(x, a, size);
+      for(int c = 0; c < size; c++)
+        a[size - 1 - c] = x[c];
+    }
+    delete [] x;
+  }
+
+  // -------------------------------------------------------------------
+  int NullModel::readMSH(const std::string &filename)
+  {
+    FILE *fp = fopen(filename.c_str(), "rb");
+    if(!fp){
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Unable to open file '%s'", filename.c_str());
+      return 0;
+    }
+
+    char str[256] = "XXX";
+    double version = 1.0;
+    bool binary = false, swap = false;
+ 
+    while(1) {
+
+      while(str[0] != '$'){
+        if(!fgets(str, sizeof(str), fp) || feof(fp))
+          break;
+      }
+    
+      if(feof(fp))
+        break;
+
+      if(!strncmp(&str[1], "MeshFormat", 10)) {
+
+        if(!fgets(str, sizeof(str), fp)) return 0;
+        int format, size;
+        if(sscanf(str, "%lf %d %d", &version, &format, &size) != 3) return 0;
+        if(format){
+          binary = true;
+          MAdMsgSgl::instance().info(__LINE__,__FILE__,
+                                     "Mesh is in binary format");
+          int one;
+          if(fread(&one, sizeof(int), 1, fp) != 1) return 0;
+          if(one != 1){
+            swap = true;
+            MAdMsgSgl::instance().info(__LINE__,__FILE__,
+                                       "Swapping bytes from binary file");
+          }
+        }
+
+      }
+      else if(!strncmp(&str[1], "PhysicalNames", 13)) {
+      }
+      else if(!strncmp(&str[1], "NO", 2) || !strncmp(&str[1], "Nodes", 5) ||
+              !strncmp(&str[1], "ParametricNodes", 15)) {
+      }
+      else if(!strncmp(&str[1], "ELM", 3) || !strncmp(&str[1], "Elements", 8)) {
+
+        if(!fgets(str, sizeof(str), fp)) return 0;
+        int numElements;
+        sscanf(str, "%d", &numElements);
+        MAdMsgSgl::instance().info(__LINE__,__FILE__,
+                                   "%d elements", numElements);
+        if(!binary){
+          for(int i = 0; i < numElements; i++) {
+            int num, type, physical = -1, elementary = -1, partition = 0, numVertices;
+            if(version <= 1.0){
+              fscanf(fp, "%d %d %d %d %d", &num, &type, &physical, &elementary, &numVertices);
+            }
+            else{
+              int numTags;
+              fscanf(fp, "%d %d %d", &num, &type, &numTags);
+              for(int j = 0; j < numTags; j++){
+                int tag;
+                fscanf(fp, "%d", &tag);       
+                if(j == 0)      physical = tag;
+                else if(j == 1) elementary = tag;
+                else if(j == 2) partition = tag;
+                // ignore any other tags for now
+                numVertices = getNumVerticesForElementTypeMSH(type);
+              }
+            }
+            int tmp;
+            for(int j = 0; j < numVertices; j++) fscanf(fp, "%d", &tmp);
+
+            int gTag = elementary;
+            if ( physical != -1 ) gTag = physical;
+            int gDim = getDimForElementTypeMSH(type);
+            getEntityByTag(gDim,gTag);
+          }
+        }
+        else{
+          int numElementsPartial = 0;
+          while(numElementsPartial < numElements){
+            int header[3];
+            if(fread(header, sizeof(int), 3, fp) != 3) return 0;
+            if(swap) SwapBytes((char*)header, sizeof(int), 3);
+            int type = header[0];
+            int numElms = header[1];
+            int numTags = header[2];
+            int numVertices = getNumVerticesForElementTypeMSH(type);
+            unsigned int n = 1 + numTags + numVertices;
+            int *data = new int[n];
+            for(int i = 0; i < numElms; i++) {
+              if(fread(data, sizeof(int), n, fp) != n) return 0;
+              if(swap) SwapBytes((char*)data, sizeof(int), n);
+              int num = data[0];
+              int physical = (numTags > 0) ? data[4 - numTags] : -1;
+              int elementary = (numTags > 1) ? data[4 - numTags + 1] : -1;
+              int partition = (numTags > 2) ? data[4 - numTags + 2] : 0;
+              int *indices = &data[numTags + 1];
+              int gTag = elementary;
+              if ( physical != -1 ) gTag = physical;
+              int gDim = getDimForElementTypeMSH(type);
+              getEntityByTag(gDim,gTag);
+            }
+            delete [] data;
+            numElementsPartial += numElms;
+          }
+        }
+
+      }
+
+      do {
+        if(!fgets(str, sizeof(str), fp) || feof(fp))
+          break;
+      } while(str[0] != '$');
+    }
+
+    fclose(fp);
+    return 1;
+  }
+
+  // -------------------------------------------------------------------
+  int NullModel::writeGEO(const std::string &filename)
+  {
+    MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                "Null model cannot write a GEO file");
+  }
+
+  // -------------------------------------------------------------------
+  int NullModel::readSTEP(const std::string &filename)
+  {
+    MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                "Null model cannot read STEP format");
+  }
+
+  // -------------------------------------------------------------------
+  int NullModel::readBREP(const std::string &filename)
+  {
+    MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                "Null model cannot read BREP format");
+  }
+
+  // -------------------------------------------------------------------
+  int NullModel::readIGES(const std::string &filename)
+  {
+    MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                "Null model cannot read IGES format");
+  }
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
+
diff --git a/Geo/NullModel.h b/Geo/NullModel.h
new file mode 100644
index 0000000..045d729
--- /dev/null
+++ b/Geo/NullModel.h
@@ -0,0 +1,88 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _H_NULLMODEL
+#define _H_NULLMODEL
+
+#ifndef _HAVE_GMSH_
+
+#include "MAdModel.h"
+#include "NullEntities.h"
+#include <set>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class NullModel : public MAdModel {
+
+  public:
+
+    NullModel(std::string name=""): MAdModel(name) {}
+    ~NullModel();
+
+    ModelType type() const { return NULLMODEL; }
+
+    // Gmsh mesh file format
+    int readMSH(const std::string &filename);
+  
+    // Gmsh native CAD format
+    int readGEO(const std::string &filename);
+    int writeGEO(const std::string &filename);
+  
+    // OCC formats
+    int readSTEP(const std::string &filename);
+    int readBREP(const std::string &filename);
+    int readIGES(const std::string &filename);
+
+    // get the number of entities in this model
+    int getNumRegions()  const { return regions.size();  }
+    int getNumFaces()    const { return faces.size();    }
+    int getNumEdges()    const { return edges.size();    }
+    int getNumVertices() const { return vertices.size(); }
+
+    // find the entity with the given tag and create it if not found
+    MAdGEntity * getEntityByTag(int dim, int tag);
+    MAdGRegion * getRegionByTag(int);
+    MAdGFace   * getFaceByTag  (int);
+    MAdGEdge   * getEdgeByTag  (int);
+    MAdGVertex * getVertexByTag(int);
+
+    // get an iterator initialized to the first/last entity in this model.
+    riter firstRegion() { return regions.begin(); }
+    fiter firstFace()   { return faces.begin(); }
+    eiter firstEdge()   { return edges.begin(); }
+    viter firstVertex() { return vertices.begin(); }
+    riter lastRegion()  { return regions.end(); }
+    fiter lastFace()    { return faces.end(); }
+    eiter lastEdge()    { return edges.end(); }
+    viter lastVertex()  { return vertices.end(); }
+
+  private:
+
+    // delete all geometric entities
+    void clean();
+
+    std::set<MAdGRegion *,MAdGEntityLessThan> regions;
+    std::set<MAdGFace   *,MAdGEntityLessThan> faces;
+    std::set<MAdGEdge   *,MAdGEntityLessThan> edges;
+    std::set<MAdGVertex *,MAdGEntityLessThan> vertices;
+
+  };
+
+}
+
+// -------------------------------------------------------------------
+
+#endif
+
+#endif
diff --git a/Geo/PGList.h b/Geo/PGList.h
new file mode 100644
index 0000000..bf65068
--- /dev/null
+++ b/Geo/PGList.h
@@ -0,0 +1,60 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+/*
+  Store a list of pointers to geometric entities
+
+  The list is stored as a standart vector:
+    - allow fast random access
+    - allow fast iterating
+    - can be allocated to a particular size
+    - slow at randomly adding/removing elements but not useful here
+*/
+
+#ifndef _H_PGLIST
+#define _H_PGLIST
+
+#include "ModelInterface.h"
+
+#include <vector>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class PGList {
+
+  public:
+
+    PGList() {};
+    PGList(const PGList& ori)
+    {
+      entities = ori.entities;
+    };
+  
+    ~PGList() {};
+
+  public:
+
+    void clear() { entities.clear(); };
+
+  public:
+
+    std::vector<MAdGEntity *> entities;
+
+  };
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/License.txt b/License.txt
new file mode 100644
index 0000000..8da168b
--- /dev/null
+++ b/License.txt
@@ -0,0 +1,850 @@
+This file contains:
+ - the terms of the GNU Lesser General Public License Version 3, 
+ - the terms of the GNU General Public License Version 3.
+
+//-----------------------------------------------------------------------
+
+		   GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions. 
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version. 
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
+
+
+
+//-----------------------------------------------------------------------
+
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/MAdConfig.h.in b/MAdConfig.h.in
new file mode 100644
index 0000000..28c7fff
--- /dev/null
+++ b/MAdConfig.h.in
@@ -0,0 +1,37 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information. 
+# You should have received a copy of these files along with MAdLib. 
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+#ifndef _H_MADCONFIG_MAD_
+#define _H_MADCONFIG_MAD_
+
+#undef HAVE_64BIT_SIZE_T
+#undef _HAVE_ANN_
+#undef HAVE_BLAS
+#undef _HAVE_BLAS_
+#undef HAVE_CBLAS
+#undef _HAVE_CBLAS_
+#undef _HAVE_GMM_
+#undef _HAVE_GMSH_
+#undef _HAVE_GSL_
+#undef HAVE_LAPACK
+#undef _HAVE_LAPACK_
+#undef _HAVE_METIS_
+#undef _HAVE_MPI_
+#undef HAVE_NO_DLL
+#undef HAVE_NO_SOCKLEN_T
+#undef _HAVE_OCC_
+#undef _HAVE_PARMETIS_
+#undef _HAVE_PARSER_
+#undef _HAVE_PETSC_
+#undef PARALLEL
+
+#endif
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..e89a239
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,403 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information. 
+# You should have received a copy of these files along with MAdLib. 
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include variables
+
+MADLIB_MAJOR_VERSION = 1
+MADLIB_MINOR_VERSION = 2
+MADLIB_PATCH_VERSION = 3
+MADLIB_EXTRA_VERSION =
+
+MADLIB_VERSION = ${MADLIB_MAJOR_VERSION}.${MADLIB_MINOR_VERSION}.${MADLIB_PATCH_VERSION}${MADLIB_EXTRA_VERSION}
+
+MADLIB_SHORT_LICENSE = "GNU Lesser General Public License"
+
+MADLIB_VERSION_FILE = Common/MAdLibVersion.h
+MADLIB_DATE = `date "+%Y%m%d"`
+MADLIB_PCFILE = MAdLib.pc
+
+MADLIB_API = \
+Adapt/AdaptInterface.h\
+Adapt/constraint/ModelConstraintManager.h\
+Adapt/constraint/Constraint.h\
+Adapt/MeshParametersManager.h\
+Adapt/operator/VertexMoveOp.h\
+Adapt/operator/SliverRegionHandler.h\
+Adapt/operator/FaceSwapOp.h\
+Adapt/operator/DESCOp.h\
+Adapt/operator/EdgeCollapseOp.h\
+Adapt/operator/EdgeSplitOp.h\
+Adapt/operator/EdgeSwapConfig.h\
+Adapt/operator/EdgeSwapOp.h\
+Adapt/operator/FaceCollapseOp.h\
+Adapt/operator/OperatorTools.h\
+Adapt/operator/SliverFaceHandler.h\
+Adapt/operator/RegionRemoveOp.h\
+Adapt/operator/MAdOperatorBase.h\
+Adapt/output/MAdOutput.h\
+Adapt/quality/ElementEvaluatorBase.h\
+Adapt/quality/ElementStatistics.h\
+Adapt/quality/MeshQualityManager.h\
+Adapt/quality/MeanRatioEvaluator.h\
+Adapt/quality/OrientedMeanRatioEvaluator.h\
+Adapt/repositioning/NodesRepositioningOp.h\
+Adapt/repositioning/GeoMatcher.h\
+Adapt/repositioning/MobileObject.h\
+Adapt/repositioning/LaplaceSmoothingOp.h\
+Adapt/repositioning/MAdElasticityOp.h\
+Adapt/sizeField/NullSField.h\
+Adapt/sizeField/MeshSizeBase.h\
+Adapt/sizeField/IsoMeshSize.h\
+Adapt/sizeField/LocalSizeField.h\
+Adapt/sizeField/AnalyticalSField.h\
+Adapt/sizeField/PWLinearSField.h\
+Adapt/sizeField/AnisoMeshSize.h\
+Adapt/sizeField/SizeFieldBase.h\
+Adapt/sizeField/SizeFieldManager.h\
+Adapt/sizeField/DiscreteSF.h\
+Adapt/utils/MAdStatistics.h\
+Adapt/utils/MAdLinearSystemSparskit.h\
+Adapt/utils/DistanceToPoints.h\
+Adapt/utils/DistanceFunction.h\
+Adapt/utils/MAdLinearSystemPETSc.h\
+Adapt/utils/MAdTimeManager.h\
+Adapt/utils/MAdLinearSystemGmm.h\
+Adapt/utils/NodalDataManager.h\
+Adapt/utils/CallBackManager.h\
+Adapt/utils/MAdLinearSystem.h\
+Adapt/utils/History.h\
+Geo/GM_Iterators.h\
+Geo/GmshEntities.h\
+Geo/GmshModel.h\
+Geo/MAdModel.h\
+Geo/ModelInterface.h\
+Geo/NullEntities.h\
+Geo/NullModel.h\
+Geo/PGList.h\
+Mesh/CheckMesh.h\
+Mesh/CheckOrientation.h\
+Mesh/Mark.h\
+Mesh/MeshDataBaseAttachable.h\
+Mesh/MeshDataBaseCommCheck.h\
+Mesh/MeshDataBaseComm.h\
+Mesh/MeshDataBaseCommPeriodic.h\
+Mesh/MeshDataBaseGEntity2Physical.h\
+Mesh/MeshDataBase.h\
+Mesh/MeshDataBaseInterface.h\
+Mesh/MeshDataBaseIO.h\
+Mesh/MeshDataBaseIterators.h\
+Mesh/MeshDataBaseLoadBalancing.h\
+Mesh/MeshDataBaseMessage.h\
+Mesh/MeshDataBaseMiniMesh.h\
+Mesh/MeshDataBaseParallelInterface.h\
+Mesh/MeshDataBaseParallelIO.h\
+Mesh/metisAdaptiveRepart.h\
+Mesh/MshTags.h\
+Mesh/MSops.h\
+Mesh/ParallelUtils.h\
+Mesh/PList.h\
+Common/MAdDefines.h\
+Common/MAdFieldEvaluator.h\
+Common/MAdMatrix.h\
+Common/MAdMessage.h\
+Common/MAdResourceManager.h\
+Common/MAdSingleton.h\
+Common/MAdStringFieldEvaluator.h\
+Common/MathUtils.h\
+Common/MAdLib.h\
+Common/MAdMetric.h\
+Common/MAdVector3.h\
+Common/MAdLibVersion.h\
+Contrib/mathex/mathex.h\
+Contrib/ANN/include/ANN/ANN.h
+
+docdir=${prefix}/doc
+
+# Main building rules
+
+#all: link
+
+#link: compile
+#	${LINKER} ${OPTIM} ${DASH}o bin/MAdLib${EXEEXT} ${MAdLib_LIBS}
+
+default: lib
+
+all: bench
+
+compile: variables initialtag dirs
+ifneq (${UNAME},WIN32MSVC)
+	@for i in ${MAdLib_DIRS}; do (cd $$i && ${MAKE}); done
+else
+	for %%i in (${MAdLib_DIRS}) do ${MAKE} -C %%i
+endif
+
+bench: lib
+ifneq (${UNAME},WIN32MSVC)
+	cd Benchmarks/moveIt; ln -s examples/tube/MyParams.h; cd -;
+	@for i in ${MAdLib_BENCHDIRS}; do (cd $$i && ${MAKE}); done
+else
+	for %%i in (${MAdLib_BENCHDIRS}) do ${MAKE} -C %%i
+endif
+
+tag:
+ifneq (${UNAME},WIN32MSVC)
+	echo "#define MADLIB_MAJOR_VERSION ${MADLIB_MAJOR_VERSION}" > ${MADLIB_VERSION_FILE}
+	echo "#define MADLIB_MINOR_VERSION ${MADLIB_MINOR_VERSION}" >> ${MADLIB_VERSION_FILE}
+	echo "#define MADLIB_PATCH_VERSION ${MADLIB_PATCH_VERSION}" >> ${MADLIB_VERSION_FILE}
+	echo "#define MADLIB_EXTRA_VERSION \"${MADLIB_EXTRA_VERSION}\"" >> ${MADLIB_VERSION_FILE}
+	echo "#define MADLIB_VERSION       \"${MADLIB_VERSION}\"" >> ${MADLIB_VERSION_FILE}
+	echo "#define MADLIB_DATE          \"`date`\"" >> ${MADLIB_VERSION_FILE}
+	echo "#define MADLIB_HOST          \"${HOSTNAME}\"" >> ${MADLIB_VERSION_FILE}
+	echo "#define MADLIB_PACKAGER      \"`whoami`\"" >> ${MADLIB_VERSION_FILE}
+	echo "#define MADLIB_OS            \"${UNAME}\"" >> ${MADLIB_VERSION_FILE}
+	echo "#define MADLIB_SHORT_LICENSE \"${MADLIB_SHORT_LICENSE}\"" >> ${MADLIB_VERSION_FILE}
+else
+	echo #define MADLIB_MAJOR_VERSION ${MADLIB_MAJOR_VERSION} > ${MADLIB_VERSION_FILE}
+	echo #define MADLIB_MINOR_VERSION ${MADLIB_MINOR_VERSION} >> ${MADLIB_VERSION_FILE}
+	echo #define MADLIB_PATCH_VERSION ${MADLIB_PATCH_VERSION} >> ${MADLIB_VERSION_FILE}
+	echo #define MADLIB_EXTRA_VERSION "${MADLIB_EXTRA_VERSION}" >> ${MADLIB_VERSION_FILE}
+	echo #define MADLIB_VERSION       "${MADLIB_VERSION}" >> ${MADLIB_VERSION_FILE}
+	echo #define MADLIB_DATE          "" >> ${MADLIB_VERSION_FILE}
+	echo #define MADLIB_HOST          "${HOSTNAME}" >> ${MADLIB_VERSION_FILE}
+	echo #define MADLIB_PACKAGER      "" >> ${MADLIB_VERSION_FILE}
+	echo #define MADLIB_OS            "${UNAME}" >> ${MADLIB_VERSION_FILE}
+	echo #define MADLIB_SHORT_LICENSE ${MADLIB_SHORT_LICENSE} >> ${MADLIB_VERSION_FILE}
+endif
+
+# Rules to build the MAdLib library
+
+.PHONY: lib
+lib: variables initialtag compile
+ifneq (${UNAME},WIN32MSVC)
+	@for i in ${MAdLib_DIRS}; do (cd $$i && ${MAKE} cpobj); done
+	${AR} ${ARFLAGS}lib/libMAdLib${LIBEXT}  ${MAdLib_TMPDIR}/*${OBJEXT}
+	${RANLIB} lib/libMAdLib${LIBEXT}
+	rm -f lib/*${OBJEXT}
+else
+	for %%i in (${MAdLib_DIRS}); do ${MAKE} -C %%i
+	${AR} ${ARFLAGS}bin\libMAdLib${LIBEXT} lib\*${LIBEXT}
+	erase lib\*${LIBEXT}
+	move bin\libMAdLib${LIBEXT} "lib"
+endif
+
+install: lib pc doc
+ifneq (${UNAME},WIN32MSVC)
+	mkdir -p ${includedir}/MAdLib
+	rm -f ${includedir}/MAdLib/*
+	cp -f ${MADLIB_API} ${includedir}/MAdLib
+	mkdir -p ${libdir}
+	cp -f lib/* ${libdir}/.
+ifneq (${DOXYGEN},)
+	mkdir -p ${docdir}
+	cp -rf doc/html ${docdir}/.
+	@echo "*********************************************************************"
+	@echo "MAdLib has been installed to the following locations:"
+	@echo "   * Libraries:            ${libdir}"
+	@echo "   * Header files:         ${includedir}"
+	@echo "   * Documentation:        ${docdir}"
+	@echo "Note that the libraries location should be found by the LD process."
+	@echo "*********************************************************************"
+else
+	@echo "*********************************************************************"
+	@echo "MAdLib has been installed to the following locations:"
+	@echo "   * Libraries:            ${libdir}"
+	@echo "   * Header files:         ${includedir}"
+	@echo "Note that the libraries location should be found by the LD process."
+	@echo "*********************************************************************"
+endif
+else
+	if not exist ${includedir}\MAdLib mkdir ${includedir}\MAdLib
+	if not exist ${libdir} mkdir ${libdir}
+	erase /q ${includedir}\MAdLib\*.h
+	for %%i in (${subst /,\,${MADLIB_API}}) do copy %%i ${includedir}\MAdLib
+	copy /y lib\libMAdLib${LIBEXT} ${libdir}\libMAdLib${LIBSUFFIX}${LIBEXT}
+endif
+
+install-bench: bench pc doc
+ifneq (${UNAME},WIN32MSVC)
+	mkdir -p ${includedir}/MAdLib
+	rm -f ${includedir}/MAdLib/*
+	cp -f ${MADLIB_API} ${includedir}/MAdLib
+	mkdir -p ${libdir}
+	cp -f lib/* ${libdir}/.
+	mkdir -p ${bindir}
+	-cp -f bin/* ${bindir}/.
+ifneq (${DOXYGEN},)
+	mkdir -p ${docdir}
+	cp -rf doc/html ${docdir}/.
+	@echo "*********************************************************************"
+	@echo "MAdLib has been installed to the following locations:"
+	@echo "   * Libraries:            ${libdir}"
+	@echo "   * Header files:         ${includedir}"
+	@echo "   * Executables:          ${bindir}"
+	@echo "   * Documentation:        ${docdir}"
+	@echo "Note that the libraries location should be found by the LD process."
+	@echo "*********************************************************************"
+else
+	@echo "*********************************************************************"
+	@echo "MAdLib has been installed to the following locations:"
+	@echo "   * Libraries:            ${libdir}"
+	@echo "   * Header files:         ${includedir}"
+	@echo "   * Executables:          ${bindir}"
+	@echo "Note that the libraries location should be found by the LD process."
+	@echo "*********************************************************************"
+endif
+#	cp -f lib/libMAdLib${LIBEXT} ${libdir}/libMAdLib${LIBSUFFIX}${LIBEXT}
+else
+	if not exist ${includedir}\MAdLib mkdir ${includedir}\MAdLib
+	if not exist ${libdir} mkdir ${libdir}
+	erase /q ${includedir}\MAdLib\*.h
+	for %%i in (${subst /,\,${MADLIB_API}}) do copy %%i ${includedir}\MAdLib
+	copy /y lib\libMAdLib${LIBEXT} ${libdir}\libMAdLib${LIBSUFFIX}${LIBEXT}
+endif
+
+uninstall:
+	rm -rf ${includedir}/MAdLib
+	rm -rf ${libdir}/libMAdLib${LIBSUFFIX}${LIBEXT}
+	rm -rf ${docdir}
+	rm -rf ${bindir}
+	rm ${MADLIB_PCFILE}
+
+# Utilities
+
+variables: configure
+	@echo "********************************************************************"
+	@echo "Please configure MAdLib by running ./configure"
+	@echo "For help, type ./configure --help"
+	@echo "********************************************************************"
+	@exit 1
+
+dirs:
+	-mkdir -p bin lib ${MAdLib_TMPDIR}
+
+purge:
+ifneq (${UNAME},WIN32MSVC)
+	for i in ${MAdLib_DIRS}; do (cd $$i && ${MAKE} purge); done
+	for i in ${MAdLib_BENCHDIRS}; do (cd $$i && ${MAKE} purge); done
+else
+	for %%i in (${MAdLib_DIRS}) do ${MAKE} -C %%i purge
+	for %%i in (${MAdLib_BENCHDIRS}) do ${MAKE} -C %%i purge
+endif
+
+clean:
+ifneq (${UNAME},WIN32MSVC)
+	for i in ${MAdLib_DIRS}; do (cd $$i && ${MAKE} clean); done
+	for i in ${MAdLib_BENCHDIRS}; do (cd $$i && ${MAKE} clean); done
+	rm -f ${MADLIB_VERSION_FILE}
+	rm -rf bin lib ${MAdLib_TMPDIR} doc
+else
+	for %%i in (${MAdLib_DIRS}) do ${MAKE} -C %%i clean
+	for %%i in (${MAdLib_BENCHDIRS}) do ${MAKE} -C %%i clean
+	erase ${MADLIB_VERSION_FILE}
+	rm -rf bin lib ${MAdLib_TMPDIR} doc
+endif
+
+depend: initialtag
+	mv -f Common/MAdLibConfig.h .
+	cp -f MAdLibConfig.depend Common/MAdLibConfig.h
+	for i in ${MAdLib_DIRS}; do (cd $$i && ${MAKE} depend); done
+	mv -f MAdLibConfig.h Common/
+
+nodepend:
+	for i in ${MAdLib_DIRS} ; do \
+          (cd $$i && (sed '/^# DO NOT DELETE THIS LINE/q' Makefile) > Makefile.new \
+          && cp Makefile Makefile.bak \
+          && cp Makefile.new Makefile \
+          && rm -f Makefile.new); \
+        done 
+
+initialtag:
+ifneq (${UNAME},WIN32MSVC)
+	@if [ ! -r ${MADLIB_VERSION_FILE} ]; then ${MAKE} tag ; fi
+else
+	${MAKE} tag
+endif
+
+tags:
+	gtags
+	htags
+
+etags:
+	etags `find . \( -name "*.cpp" -o -name "*.c" -o -name "*.h"\
+                      -o -name "*.y" -o -name "*.l" \)`
+
+# Rules to package the sources
+
+source-tree: purge
+	rm -rf MAdLib-${MADLIB_VERSION}
+	tar zcf MAdLib.tgz --exclude "*.o" --exclude "*.a" --exclude "libMAdLib*"\
+          --exclude "variables" --exclude "config.log" --exclude "config.status"\
+          --exclude "autom4*" --exclude "Makefile.distrib" --exclude "*.bak"\
+          --exclude "HTML" --exclude "*TAGS*" --exclude ".svn" --exclude "*.pos"\
+          --exclude "*.msh" --exclude "toPort" --exclude "poubelle"\
+          --exclude "Makefile.buildconfig"\
+          Geo Mesh Adapt Common Copyright.txt License.txt Credits.txt\
+          README *.in Contrib Makefile configure Tutorial doxygen.config
+	mkdir MAdLib-${MADLIB_VERSION}
+	cd MAdLib-${MADLIB_VERSION} && tar zxf ../MAdLib.tgz
+	rm -f MAdLib.tgz
+	tar zcf MAdLib_Benchmarks.tgz\
+          --exclude "*.bak"\
+          --exclude "*.msh"\
+          --exclude "*.pos"\
+          --exclude ".svn"\
+          --exclude "cpu" --exclude "*tmp*" --exclude "statistics"\
+          --exclude "slivers" --exclude "cpuinfo" --exclude "journal" --exclude "meshSize"\
+          Benchmarks/meshInfo Benchmarks/optimize\
+          Benchmarks/moveIt/*.h Benchmarks/moveIt/*.cc Benchmarks/moveIt/Makefile\
+          Benchmarks/moveIt/README\
+          Benchmarks/moveIt/examples/tube
+	cd MAdLib-${MADLIB_VERSION} && tar zxf ../MAdLib_Benchmarks.tgz
+	rm -f MAdLib_Benchmarks.tgz
+
+source: source-tree
+	cd MAdLib-${MADLIB_VERSION} && rm -rf ${MADLIB_VERSION_FILE}\
+          Common/MAdLibConfig.h 
+	tar zcf MAdLib-${MADLIB_VERSION}-source.tgz MAdLib-${MADLIB_VERSION}
+
+# Configuration file to include MAdLib within a pkg-config compilation
+
+pc:
+ifneq (${UNAME},WIN32MSVC)
+	echo "prefix=${prefix}" > ${MADLIB_PCFILE}
+	echo "exec_prefix=${prefix}/bin" >> ${MADLIB_PCFILE}
+	echo "libdir=${libdir}" >> ${MADLIB_PCFILE}
+	echo "includedir=${includedir}" >> ${MADLIB_PCFILE}
+	echo "">> ${MADLIB_PCFILE}
+	echo "Name: MAdLib" >> ${MADLIB_PCFILE}
+	echo "Version: ${MADLIB_VERSION}" >> ${MADLIB_PCFILE}
+	echo "Description: Mesh adaptation library" >> ${MADLIB_PCFILE}
+	echo "Libs: -L${libdir} -lMAdLib" >> ${MADLIB_PCFILE}
+	echo "Cflags: -I${includedir}" >> ${MADLIB_PCFILE}
+else
+	echo prefix=${prefix} > ${MADLIB_PCFILE}
+	echo exec_prefix=${prefix}/bin >> ${MADLIB_PCFILE}
+	echo libdir=${libdir} >> ${MADLIB_PCFILE}
+	echo includedir=${includedir} >> ${MADLIB_PCFILE}
+	echo >> ${MADLIB_PCFILE}
+	echo Name: MAdLib >> ${MADLIB_PCFILE}
+	echo Version: ${MADLIB_VERSION} >> ${MADLIB_PCFILE}
+	echo Description: Mesh adaptation library >> ${MADLIB_PCFILE}
+	echo Libs: -L${libdir} -lMAdLib >> ${MADLIB_PCFILE}
+	echo Cflags: -I${includedir} >> ${MADLIB_PCFILE}
+endif
+
+doc:
+ifneq (${DOXYGEN},)
+	${DOXYGEN} doxygen.config
+else
+ifneq (${UNAME},WIN32MSVC)
+	echo "Doxygen not found during configure process: documentation will not be generated"
+else
+	echo Doxygen not found during configure process: documentation will not be generated
+endif
+endif
diff --git a/Mesh/Balance.cc b/Mesh/Balance.cc
new file mode 100644
index 0000000..02aaa03
--- /dev/null
+++ b/Mesh/Balance.cc
@@ -0,0 +1,194 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "MeshDataBase.h"
+#include "MSops.h"
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseComm.h"
+#include "MeshDataBaseParallelInterface.h"
+#include "Mark.h"
+#include "MAdMessage.h"
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+#ifdef _HAVE_PARMETIS_
+#include "metisAdaptiveRepart.h"
+#endif
+#endif
+
+#include <stdio.h>
+
+using namespace MAd;
+
+namespace MAd {
+
+#ifdef PARALLEL
+  // -------------------------------------------------------------------
+  void Balance(pMesh mesh,MDB_DataExchanger &de) {
+
+    int dim = (mesh->tets.empty()) ? 2 : 3;
+    pMeshDataId tagElt= MD_newMeshDataId("EltDestination"); //dest = (int - 1)
+  
+    // --- Mark the elements to be moved and their destination ---
+    if(dim==2) MarkTriangles (mesh, tagElt);
+    else       MarkTets      (mesh, tagElt);
+    //  if(dim==2) MarkTrianglesSmooth (mesh, tagElt);
+    //  else       MarkTetsSmooth      (mesh, tagElt);
+
+    // --- Move marked elements ---
+    loadBalancing(mesh, tagElt, de);
+  
+    // --- Check that the mesh is not empty (debug) ---
+    if ( dim==2 ) assert( !( mesh->triangles.empty() ) );
+    if ( dim==3 ) assert( !( mesh->tets.empty() ) );
+
+    // ----------------------------------------------
+    // ------ Tagging inter-partition nodes
+    // ----------------------------------------------
+
+    pMeshDataId tag = MD_lookupMeshDataId("RemotePoint");
+  
+    V_createInfoInterface(mesh,tag);
+    E_createInfoInterface(mesh,tag);
+    F_createInfoInterface(mesh,tag);
+
+    return;
+  }
+  // -------------------------------------------------------------------
+  void Balance2(pMesh mesh,MDB_DataExchanger &de) {
+
+    int dim = (mesh->tets.empty()) ? 2 : 3;
+    pMeshDataId tagElt= MD_newMeshDataId("EltDestination"); //dest = (int - 1)
+
+    // --- Mark the elements to be moved and their destination ---
+    if(dim==2) MarkTriangles (mesh, tagElt);
+    else       MarkTets      (mesh, tagElt);
+
+    // --- Move marked elements ---
+    loadBalancing2(mesh, tagElt, de);
+
+    // --- Check that the mesh is not empty (debug) ---
+    if ( dim==2 ) assert( !( mesh->triangles.empty() ) );
+    if ( dim==3 ) assert( !( mesh->tets.empty() ) );
+    // ----------------------------------------------
+    // ------ Tagging inter-partition nodes
+    // ----------------------------------------------
+
+    pMeshDataId tag = MD_lookupMeshDataId("RemotePoint");
+ 
+    V_createInfoInterface(mesh,tag);
+    E_createInfoInterface(mesh,tag);
+    F_createInfoInterface(mesh,tag);
+
+    return;
+  }
+
+  // -------------------------------------------------------------------
+  int BalanceManifold(pMesh mesh,MDB_DataExchanger &de) {
+  
+    int dim = (mesh->tets.empty()) ? 2 : 3;  
+    pMeshDataId tagElt= MD_newMeshDataId("EltDestination"); //dest = (int - 1)
+  
+    int nmanifold = MarkTetsManifold(mesh,tagElt);
+    
+    loadBalancing(mesh,tagElt,de);
+
+    if ( dim==3 ) assert( !(mesh->tets.empty()) );
+ 
+    return(nmanifold);
+  }
+
+  // -------------------------------------------------------------------
+  void BalanceRandom(pMesh mesh, MDB_DataExchanger &de) {
+
+    int dim = (mesh->tets.empty()) ? 2 : 3;
+    pMeshDataId tagElt = MD_newMeshDataId("EltDestination"); //dest = (int - 1)
+
+    if(dim==2) MarkTrianglesRandom(mesh,tagElt);
+    else       MarkTetsRandom(mesh,tagElt);
+
+    loadBalancing(mesh,tagElt,de);
+
+    if ( dim==3 ) assert( !(mesh->tets.empty()) );
+  }
+
+  // -------------------------------------------------------------------
+#ifdef _HAVE_PARMETIS_
+  void BalanceMetis(pMesh mesh,MDB_DataExchanger &de) {
+  
+    int dim = (mesh->tets.empty()) ? 2 : 3;
+  
+    //std::cout<<"metisAdaptiveRepart"<<mesh->nbPoints<<" "<<mesh->nbTets<<std::endl;
+    pMeshDataId tagElt    = MD_newMeshDataId("EltDestination"); //dest = (int - 1)
+    std::cout <<"USING PARMETIS"<<std::endl;
+    metisAdaptiveRepart(mesh,tagElt);
+
+    loadBalancing(mesh,tagElt,de);
+
+    //std::cout<<"end metisAdaptiveRepart"<<mesh->nbPoints<<" "<<mesh->nbTets<<std::endl;
+  
+    if ( dim==3 ) assert( !(mesh->tets.empty()) );
+  
+    return;
+  }
+#endif
+
+  // -------------------------------------------------------------------
+#ifdef _HAVE_PARMETIS_
+  void BalanceMetis2(pMesh mesh, MDB_DataExchanger &de) {
+  
+    int dim = M_dim(mesh);
+  
+    pMeshDataId tagElt = MD_newMeshDataId("EltDestination"); //dest = (int - 1)
+    metisAdaptiveRepart(mesh,tagElt);
+    loadBalancing2(mesh,tagElt,de);
+
+    if ( M_dim(mesh) != dim ) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "The dimension of the mesh has been reduced from %d to %d during a balancing operation",
+                                  dim, M_dim(mesh));
+    }
+
+    pMeshDataId tag = MD_lookupMeshDataId("RemotePoint");
+    V_createInfoInterface(mesh,tag);
+    E_createInfoInterface(mesh,tag);
+    F_createInfoInterface(mesh,tag);
+  }
+#endif
+
+  // -------------------------------------------------------------------
+#endif
+
+  // -------------------------------------------------------------------
+  void BalancePeriodic(pMesh mesh,int dim,MDB_DataExchanger &de,
+                       MDB_DataExchangerPeriodic &deperiodic,std::vector<std::vector<int> >& transfo) {
+    pMeshDataId tagMove = MD_newMeshDataId("TagMovePeriodic");
+    pMeshDataId tagElt  = MD_newMeshDataId("EltDestination"); //dest = (int - 1)
+    /*for 3-periodic cases*/
+    pMeshDataId tagTransfo  = MD_newMeshDataId("Transformation"); 
+  
+    if(dim==2) MarkPeriodicTriangles(mesh,transfo,tagElt,tagMove,tagTransfo);
+    else       MarkPeriodicTets(mesh,transfo,tagElt,tagMove,tagTransfo);  
+  
+    PeriodicInterfaceMigration(mesh,tagElt,tagMove,tagTransfo,de,deperiodic);
+  
+    MD_deleteMeshDataId(tagMove);
+    MD_deleteMeshDataId(tagElt);
+    MD_deleteMeshDataId(tagTransfo);
+  
+    return;
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Mesh/CheckMesh.cc b/Mesh/CheckMesh.cc
new file mode 100644
index 0000000..d34835f
--- /dev/null
+++ b/Mesh/CheckMesh.cc
@@ -0,0 +1,825 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "CheckMesh.h"
+#include "MAdMessage.h"
+
+#include <stdio.h>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  // checkGeometricalCompatibility:
+
+  // *** For 2D meshes ***
+
+  // --- Faces ---
+  //   - check every face is classified on a surface
+
+  // --- Edges ---
+  // For every edge:
+  //   - if is classified on a surface: the edge is used by exactly 
+  //     2 faces with the same classification as the edge,
+  //   - if classified on a line: the edge is used by exactly 1 face.
+  //   - is not classified on a point
+  
+  // --- Vertices ---
+  // For every vertex:
+  //   - if classified on a surface: all edges using it have to be 
+  //     classified on the same surface,
+  //   - if classified on a line: exactly two edges classified on the 
+  //     same line use it. No other edge classified on a line use it.
+  //   - if classified on a point, at least two edges classified 
+  //     on different lines use it.
+
+  // *** For 3D meshes ***
+
+  // --- Regions ---
+  //  - check every mesh region is classified on a model region
+
+  // --- Faces ---
+  // For every face:
+  //   - if classified on a model region: the face is used by exactly 
+  //     2 mesh regions with the same classification as the face,
+  //   - if classified on a surface: the face is used by exactly 1 
+  //     mesh region.
+  //   - is not classified on a line
+  //   - is not classified on a point
+
+  // --- Edges ---
+  // For every edge:
+  //   - if classified on a model region: check that all faces using 
+  //     it are classified on the same model region,
+  //   - if classified on a surface: check that exactly 2 faces using it 
+  //     are classified on the same surface, and that no face is classified 
+  //     on a different surface,
+  //   - if classified on a line: check that at least two faces using it 
+  //     are classified on surfaces (it can be the same surface: revoluted 
+  //     cylinder).
+  //   - is not classified on a point
+
+  // --- Vertices ---
+  // For every vertex:
+  //   - if classified on a model region: all edges using it have to be 
+  //     classified on the same model region,
+  //   - if classified on a surface: at least 3 edges using it are 
+  //     classified on the same surface, and no edge can be classified 
+  //     on a line or on a different surface.
+  //   - if classified on a line: exactly 2 edges using it are 
+  //     classified on the same line and no other edge is classified 
+  //     on a line,
+  //   - if classified on a point: at least 1 edge using it is 
+  //     classified on a line (only 1: for revoluted cones).
+  
+  int checkGeomCompatibility(MDB_Mesh * mesh, int verbose, std::ostream& out)
+  {
+#ifdef PARALLEL
+    // In a mesh partitioned with MDB, the parallel boundary 
+    // faces are not classified on a model face and the following 
+    // check fails
+    return 1;
+#endif
+
+// #warning "check geometric compatibility not implemented for 2D meshes"
+    if ( M_dim(mesh) < 3 ) return 1;
+
+    int gDim;
+
+    int flag = 1;
+
+    // --- Regions ---
+
+    pRegion pr;
+    RIter rIt= M_regionIter(mesh);
+    while ( ( pr = RIter_next(rIt) ) )
+      {
+        gDim = R_whatInType(pr);
+        if ( gDim != 3 ) {
+          flag = 0;
+          if (verbose) {
+            out <<  "Mesh region not classified on a model region\n";
+            R_info_topology(pr,out);
+          }
+          break;
+        }
+      }
+    RIter_delete(rIt);
+    if ( !flag ) return 0;
+
+    // -- Faces ---
+
+    pFace pf;
+    FIter fIt= M_faceIter(mesh);
+    while ( flag && ( pf = FIter_next(fIt) ) )
+      {
+        gDim = F_whatInType(pf);
+        switch (gDim) {
+        case 3: {
+          int nRgn = F_numRegions(pf); 
+          if ( nRgn != 2 ) {
+            flag = 0;
+            if (verbose) {
+              out << "Face classif on dim 3 with not exactly 2 regions\n";
+              F_info(pf,"",out);
+            }
+          }
+          if ( ( F_whatIn(pf) != R_whatIn( F_region(pf,0) ) ) || 
+               ( F_whatIn(pf) != R_whatIn( F_region(pf,1) ) ) ) {
+            flag = 0;
+            if (verbose) {
+              out << "Face classif on dim 3 used by regions classif on different entities\n";
+              F_info(pf,"",out);
+            }
+          }
+          break;
+        }
+        case 2: {
+          int nRgn = F_numRegions(pf); 
+          if ( nRgn != 1 ) {
+            flag = 0;
+            if (verbose) {
+              out << "Face classif on dim 2 with not exactly 1 region\n";
+              F_info(pf,"",out);
+            }
+          }
+          break;
+        }
+        default: {
+          flag = 0;
+          if (verbose) {
+            out << "Face classif on wrong dimension\n";
+            F_info(pf,"",out);
+          }
+        }
+        }
+      }
+    FIter_delete(fIt);
+    if ( !flag ) return 0;
+
+    // -- Edges ---
+
+    pEdge pe;
+    pGEntity pge;
+    pPList eFaces;
+    void * temp;
+    EIter eIt = M_edgeIter(mesh);
+    while ( flag && ( pe = EIter_next(eIt) ) )
+      {
+        pge  = E_whatIn(pe);
+        gDim = GEN_type(pge);
+        switch (gDim) {
+        case 3: {
+          eFaces = E_faces(pe);
+          temp = NULL;
+          while ( ( pf = (pFace) PList_next(eFaces,&temp) ) ) {
+            if ( F_whatIn(pf) != pge ) {
+              flag = 0;
+              if (verbose) {
+                out << "Edge classif on a region but used by faces "
+                    << "not classif on the same region\n";
+                E_info(pe,"",out);
+              }
+            }
+          }
+          PList_delete(eFaces);
+          break;
+        }
+        case 2: {
+          int nbBF = 0;
+          eFaces = E_faces(pe);
+          temp = NULL;
+          while ( ( pf = (pFace) PList_next(eFaces,&temp) ) ) {
+            if ( F_whatInType(pf) == 2 ) {
+              if ( F_whatIn(pf) != pge ) {
+                flag = 0;
+                if (verbose) {
+                  out << "Edge classif on a surface used by a face classif "
+                      << "on another surface\n";
+                  E_info(pe,"",out);
+                }
+              }
+              nbBF++;
+            }
+          }
+          PList_delete(eFaces);
+          if ( nbBF != 2 ) {
+            flag = 0;
+            if (verbose) {
+              out << "Edge classif on a surface and not used by exactly "
+                  << "2 faces classif on surfaces\n";
+              E_info(pe,"",out);
+            }
+          }
+          break;
+        }
+        case 1: {
+          int nbBF = 0;
+          eFaces = E_faces(pe);
+          temp = NULL;
+          while ( ( pf = (pFace) PList_next(eFaces,&temp) ) ) {
+            if ( F_whatInType(pf) == 2 ) nbBF++;
+          }
+          PList_delete(eFaces);
+          if ( nbBF < 2 ) {
+            flag = 0;
+            if (verbose) {
+              out << "Edge classif on a line and not used by at least"
+                  << " 2 faces classif on surfaces\n";
+              E_info(pe,"",out);
+            }
+          }
+          break;
+        }
+        default: {
+          flag = 0;
+          if (verbose) {
+            out << "Edge classif on wrong dimension\n";
+            E_info(pe,"",out);
+          }
+        }
+        }
+      }
+    EIter_delete(eIt);
+    if ( !flag ) return 0;
+
+    // -- Vertices ---
+
+    pPList vEdges;
+    pVertex pv;
+    VIter vIt = M_vertexIter(mesh);
+    while ( flag && ( pv = VIter_next(vIt) ) )
+      {
+        pge  = V_whatIn(pv);
+        gDim = GEN_type(pge);
+        switch (gDim) {
+        case 3: {
+          vEdges = V_edges(pv);
+          temp = NULL;
+          while ( ( pe = (pEdge) PList_next(vEdges,&temp) ) ) {
+            if ( E_whatIn(pe) != pge ) {
+              flag = 0;
+              if (verbose) {
+                out << "Vertex classif on a region but used by edges "
+                    << "not classif on the same region\n";
+                V_info(pv,"",out);
+              }
+            }
+          }
+          PList_delete(vEdges);
+          break;
+        }
+        case 2: {
+          int nbE = 0;
+          vEdges = V_edges(pv);
+          temp = NULL;
+          while ( ( pe = (pEdge) PList_next(vEdges,&temp) ) ) {
+            if ( E_whatInType(pe) == 3 ) continue;
+            if ( E_whatIn(pe) != pge ) {
+              flag = 0;
+              if (verbose) {
+                out << "Vertex classif on a surface but used by edges "
+                    << "not classif on the same surface or on a region\n";
+                V_info(pv,"",out);
+              }
+            }
+            nbE++;
+          }
+          PList_delete(vEdges);
+          if ( nbE < 3 ) {
+            flag = 0;
+            if (verbose) {
+              out << "Vertex classif on a surface and not used by at least"
+                  << " 3 edges classif on surfaces\n";
+              V_info(pv,"",out);
+            }
+          }
+          break;
+        }
+        case 1: {
+          int nbE = 0;
+          vEdges = V_edges(pv);
+          temp = NULL;
+          while ( ( pe = (pEdge) PList_next(vEdges,&temp) ) ) {
+            if ( E_whatInType(pe) > 1 ) continue;
+            if ( E_whatIn(pe) != pge ) {
+              flag = 0;
+              if (verbose) {
+                out << "Vertex classif on a line and used by an edge "
+                    << "classif on another line\n";
+                V_info(pv,"",out);
+              }
+            }
+            nbE++;
+          }
+          PList_delete(vEdges);
+          if ( nbE != 2 ) {
+            flag = 0;
+            if (verbose) {
+              out << "Vertex classif on a line and not used by exactly"
+                  << " 2 edges classif on the same line\n";
+              V_info(pv,"",out);
+            }
+          }
+          break;
+        }
+        case 0: {
+          int nbE = 0;
+          std::set<pGEntity> glines;
+          vEdges = V_edges(pv);
+          temp = NULL;
+          while ( ( pe = (pEdge) PList_next(vEdges,&temp) ) ) {
+            if ( E_whatInType(pe) > 1 ) continue;
+            nbE++;
+            glines.insert(E_whatIn(pe));
+          }
+          PList_delete(vEdges);
+          if ( nbE == 0 ) {
+            flag = 0;
+            if (verbose) {
+              out << "Vertex classif on a point and not used by an"
+                  << " edge classif on a line\n";
+              V_info(pv,"",out);
+            }
+          }
+//           if ( nbE < 2 ) {
+//             flag = 0;
+//             if (verbose) {
+//               out << "Vertex classif on a point and used by less than"
+//                   << " 2 edges classif on lines\n";
+//               V_info(pv,"",out);
+//             }
+//           }
+//           if ( glines.size() < 2 ) {
+//             flag = 0;
+//             if (verbose) {
+//               out << "Vertex classif on a point and not used by edges"
+//                   << " classified on different lines\n";
+//               V_info(pv,"",out);
+//             }
+//           }
+          break;
+        }
+        default: {
+          flag = 0;
+          if (verbose) {
+            out << "Vertex classif on non-existing dimension\n";
+            V_info(pv,"",out);
+          }
+        }
+        }
+      }
+    VIter_delete(vIt);
+    if ( !flag ) return 0;
+
+    return flag;
+    
+  }
+
+  // -------------------------------------------------------------------
+  int checkRegionsVolume(MDB_Mesh * mesh, int verbose, std::ostream& out)
+  {
+    int flag = 1;
+    pRegion r;
+    RIter rIt= M_regionIter(mesh);
+    while ( ( r = RIter_next(rIt) ) ) {
+      if (R_volume(r) < 0.) {
+        flag = 0;
+        if (verbose) {
+          out << "Negative volume found !\n";
+          R_info_topology(r,out);
+        }
+        break;
+      }  
+    }
+    RIter_delete(rIt);
+    return flag;
+  }
+
+  // -------------------------------------------------------------------
+  int checkEdgeToRegionConnectivity(MDB_Mesh * mesh, int verbose, 
+                                    std::ostream& out)
+  {
+#ifdef PARALLEL
+    // In a mesh partitioned with MDB, the parallel boundary 
+    // faces are not classified on a model face and the following 
+    // check fails
+    return 1;
+#endif
+
+    if ( M_dim(mesh) <= 2 ) return 1;
+
+    int flag = 1;
+    pEdge edge;
+    EIter eIt = M_edgeIter(mesh);
+    while ( ( edge = EIter_next(eIt) ) ) {
+
+      if ( E_whatInType(edge) != 3 ) continue;
+
+      pFace face = E_face(edge,0);
+      pRegion start_region = F_region(face,0);
+      
+      pFace current_face = face;
+      pRegion current_region = start_region;
+      pFace next_face;
+      pRegion next_region = NULL;
+      while ( next_region != start_region )
+      {
+        next_face = E_otherFace(edge, current_face, current_region);
+        next_region = F_region(next_face, 0);
+        if( next_region == current_region ) {
+          next_region = F_region(next_face, 1);
+        }
+        current_face   = next_face;
+        current_region = next_region;
+        
+        if ( !next_region ) {
+          flag = 0;
+          if (verbose) {
+            out << "Found a wrong edge to region connectivity !\n";
+            E_info(edge,"",out);
+          }
+          break;
+        }
+      }
+    }
+    EIter_delete(eIt);
+    return flag;
+  }
+
+  // -------------------------------------------------------------------
+  // Obsolete: included in checkGeomCompatibility()
+  int checkFaceToRegionConnectivity(MDB_Mesh * mesh, int verbose, std::ostream& out) {
+
+#ifdef PARALLEL
+    // In a mesh partitioned with MDB, the parallel boundary 
+    // faces are not classified on a model face and the following 
+    // check fails
+    return 1;
+#endif
+
+    if ( M_dim(mesh) <= 2 ) return 1;
+
+    int flag = 1;
+    pFace f;
+    FIter fIt= M_faceIter(mesh);
+    while ( ( f = FIter_next(fIt) ) ) {
+      int ok = 1;
+      int nRgn = F_numRegions(f); 
+      if (nRgn==0) out << "nRgn: " << nRgn << "\n";
+      int type = F_whatInType(f);
+      if (              nRgn == 0 ) ok = 0;
+      if ( type == 2 && nRgn != 1 ) ok = 0;
+      if ( type == 3 && nRgn != 2 ) ok = 0;
+      if (!ok) {
+        flag = 0;
+        if (verbose) {
+          out << "Found a wrong face to region connectivity !\n";
+          F_info(f,"",out);
+        }
+        break;
+      }  
+    }
+    FIter_delete(fIt);
+    return flag;
+  }
+
+  // -------------------------------------------------------------------
+  int checkFaceToVertexConnectivity(MDB_Mesh * mesh, int verbose, std::ostream& out)
+  {
+    int flag = 1;
+    pFace f;
+    pVertex v0,v1,v2;
+    FIter fIt = M_faceIter(mesh);
+    while ( ( f = FIter_next(fIt) ) ) {
+      v0 = F_vertex(f,0);
+      v1 = F_vertex(f,1);
+      v2 = F_vertex(f,2);
+      if ( v0 == v1 || v0 == v2 || v1 == v2 ) {
+        flag = 0;
+        if (verbose) {
+          out << "Found a wrong face to vertex connectivity !\n";
+          F_info(f,"",out);
+        }
+        break;
+      }
+    }
+    FIter_delete(fIt);
+    return flag;
+  }
+
+  // -------------------------------------------------------------------
+  // Check that there is at least one face attached to each edge in 2D, 
+  // one region and two faces in 3D.
+  int checkEdgeConnectivity(MDB_Mesh * mesh, int verbose, std::ostream& out) {
+
+#ifdef PARALLEL
+    // In a mesh partitioned with MDB, the parallel boundary 
+    // edges are not classified on a model line and the following 
+    // check fails
+    return 1;
+#endif
+
+    int dim = M_dim(mesh);
+    if ( dim <= 1 ) return 1;
+
+    int flag = 1;
+    pEdge e;
+    EIter eIt= M_edgeIter(mesh);
+    while ( ( e = EIter_next(eIt) ) ) {
+      int nFace = E_numFaces(e);
+      int nRgn  = E_numRegions(e);
+      if ( dim == 2 ) {
+        if ( (nRgn != 0) || (nFace < 1) ) {
+          flag = 0; break;
+        }
+      }
+      else if ( dim == 3 ) {
+        if ( (nRgn < 1) || (nFace < 2) ) {
+          flag = 0; break;
+        }
+      }
+    }
+    EIter_delete(eIt);
+    if ( (!flag) && verbose ) {
+      out << "Found an ill-connected edge !\n";
+      E_info(e,"",out);
+    }
+    return flag;
+  }
+
+  // -------------------------------------------------------------------
+  int checkEntityPointers(MDB_Mesh * mesh, int verbose, std::ostream& out) {
+
+    int flag = 1;
+
+    VIter vIt = M_vertexIter(mesh);
+    pVertex pv;
+    while ( ( pv = VIter_next(vIt) ) ) {
+      if ( !pv ) {
+        flag = 0;
+        if (verbose) out << "Found a null pointer when iterating on vertices\n";
+      } 
+    }
+    VIter_delete(vIt);
+
+    EIter eIt = M_edgeIter(mesh);
+    pEdge pe;
+    while ( ( pe = EIter_next(eIt) ) ) {
+      if ( !pe ) {
+        flag = 0;
+        if (verbose) out << "Found a null pointer when iterating on edges\n";
+      } 
+    }
+    EIter_delete(eIt);
+
+    FIter fIt = M_faceIter(mesh);
+    pFace pf;
+    while ( ( pf = FIter_next(fIt) ) ) {
+      if ( !pf ) {
+        flag = 0;
+        if (verbose) out << "Found a null pointer when iterating on faces\n";
+      } 
+    }
+    FIter_delete(fIt);
+
+    RIter rIt = M_regionIter(mesh);
+    pRegion pr;
+    while ( ( pr = RIter_next(rIt) ) ) {
+      if ( !pr ) {
+        flag = 0;
+        if (verbose) out << "Found a null pointer when iterating on regions\n";
+      } 
+    }
+    RIter_delete(rIt);
+  
+    return flag;
+  }
+
+  // -------------------------------------------------------------------
+  int checkIterators(MDB_Mesh * mesh, int verbose, std::ostream& out) {
+
+    int flag = 1;
+
+    int nbMeshV = M_numVertices(mesh);
+    int nbIterV = 0;
+    VIter vIt= M_vertexIter(mesh);
+    while ( VIter_next(vIt) )  nbIterV++;
+    VIter_delete(vIt);
+    if ( nbMeshV != nbIterV ) {
+      flag = 0;
+      if (verbose) {
+        out << "Incoherent number of vertices: " 
+            << nbMeshV << " in mesh, " 
+            << nbIterV << " in iterator\n";
+      }
+    }
+
+    int nbMeshE = M_numEdges(mesh);
+    int nbIterE = 0;
+    EIter eIt= M_edgeIter(mesh);
+    while ( EIter_next(eIt) )  nbIterE++;
+    EIter_delete(eIt);
+    if ( nbMeshE != nbIterE ) {
+      flag = 0;
+      if (verbose) {
+        out << "Incoherent number of edges: "
+            << nbMeshE << " in mesh, "
+            << nbIterE << " in iterator\n";
+      }
+    }
+
+    int nbMeshF = M_numFaces(mesh);
+    int nbIterF = 0;
+    FIter fIt= M_faceIter(mesh);
+    while ( FIter_next(fIt) )  nbIterF++;
+    FIter_delete(fIt);
+    if ( nbMeshF != nbIterF ) {
+      flag = 0;
+      if (verbose) {
+        out << "Incoherent number of faces: "
+            << nbMeshF << " in mesh, "
+            << nbIterF << " in iterator\n";
+      }
+    }
+
+    int nbMeshR = M_numRegions(mesh);
+    int nbIterR = 0;
+    RIter rIt= M_regionIter(mesh);
+    while ( RIter_next(rIt) )  nbIterR++;
+    RIter_delete(rIt);
+    if ( nbMeshR != nbIterR ) {
+      flag = 0;
+      if (verbose) {
+        out << "Incoherent number of regions: "
+            << nbMeshR << " in mesh, "
+            << nbIterR << " in iterator\n";
+      }
+    }
+
+    return flag;
+  }
+
+  // -------------------------------------------------------------------
+  int checkParameters(MDB_Mesh * mesh, int verbose, std::ostream& out)
+  {
+    if ( !M_isParametric(mesh) ) return 1;
+
+    int flag = 1;
+
+    pVertex pv;
+    double tmp0,tmp1;
+    VIter vIt= M_vertexIter(mesh);
+    while ( ( pv = VIter_next(vIt) ) ) {
+      int gDim = V_whatInType(pv);
+      bool param = V_params(pv,&tmp0,&tmp1);
+      if ( ( gDim==0 || gDim==1 || gDim==2 ) && !param ) {
+        flag = 0;
+        if (verbose) {
+          out << "Non parametric point classified on geo entity with dim " <<gDim<<"\n";
+          V_info(pv,"",out);
+        }
+      }
+      if ( ( gDim==3 ) && param ) {
+        flag = 0;
+        if (verbose) {
+          out << "Parametric point classified on geo entity with dim " <<gDim<<"\n";
+          V_info(pv,"",out);
+        }
+      }
+    }
+    VIter_delete(vIt);
+
+    return flag;
+  }
+
+  // -------------------------------------------------------------------
+  bool checkMesh(MDB_Mesh * mesh, checkType type, int verbose, 
+                 std::ostream& out, MeshStatus * status) {
+
+    switch (type) {
+    case CHECK_ALL: {
+      if ( !checkRegionsVolume(mesh, verbose, out) ) {
+        if(status) *status = NEGATIVE_VOLUME; 
+        return false;
+      }
+      if ( !checkGeomCompatibility(mesh, verbose, out) ) {
+        if(status) *status = GEOM_INCOMPATIBILITY;
+        return false;
+      }
+      if ( !checkEdgeToRegionConnectivity(mesh, verbose, out) ) {
+        if(status) *status = WRONG_EDGE_TO_RGN_CONN;
+        return false;
+      }
+      if ( !checkFaceToRegionConnectivity(mesh, verbose, out) ) {
+        if(status) *status = WRONG_FACE_TO_RGN_CONN;
+        return false;
+      }
+      if ( !checkFaceToVertexConnectivity(mesh, verbose, out) ) {
+        if(status) *status = WRONG_FACE_TO_VTX_CONN;
+        return false;
+      }
+      if ( !checkEdgeConnectivity(mesh, verbose, out) ) {
+        if(status) *status = WRONG_EDGE_CONN;
+        return false;
+      }
+      if ( !checkEntityPointers(mesh, verbose, out) ) {
+        if(status) *status = WRONG_ENTITY_POINTERS;
+        return false;
+      }
+      if ( !checkIterators(mesh, verbose, out) ) {
+        if(status) *status = WRONG_ITERATORS;
+        return false;
+      }
+      if ( !checkParameters(mesh, verbose, out) ) {
+        if(status) *status = WRONG_PARAMETERS;
+        return false;
+      }
+      break;
+    }
+    case CHECK_VOLUME: {
+      if ( !checkRegionsVolume(mesh, verbose, out) ) {
+        if(status) *status = NEGATIVE_VOLUME;
+        return false;
+      }
+      break;
+    }
+    case CHECK_GEOM_COMPATIBILITY: {
+      if ( !checkGeomCompatibility(mesh, verbose, out) ) {
+        if(status) *status = GEOM_INCOMPATIBILITY;
+        return false;
+      }
+      break;
+    }
+    case CHECK_EDGE_TO_RGN_CONN: {
+      if ( !checkEdgeToRegionConnectivity(mesh, verbose, out) ) {
+        if(status) *status = WRONG_EDGE_TO_RGN_CONN;
+        return false;
+      }
+      break;
+    }
+    case CHECK_FACE_TO_RGN_CONN: {
+      if ( !checkFaceToRegionConnectivity(mesh, verbose, out) ) {
+        if(status) *status = WRONG_FACE_TO_RGN_CONN;
+        return false;
+      }
+      break;
+    }
+    case CHECK_FACE_TO_VTX_CONN: {
+      if ( !checkFaceToVertexConnectivity(mesh, verbose, out) ) {
+        if(status) *status = WRONG_FACE_TO_VTX_CONN;
+        return false;
+      }
+      break;
+    }
+    case CHECK_EDGE_CONN: {
+      if ( !checkEdgeConnectivity(mesh, verbose, out) ) {
+        if(status) *status = WRONG_EDGE_CONN;
+        return false;
+      }
+      break;
+    }
+    case CHECK_ENTITY_POINTERS: {
+      if ( !checkEntityPointers(mesh, verbose, out) ) {
+        if(status) *status = WRONG_ENTITY_POINTERS;
+        return false;
+      }
+      break;
+    }
+    case CHECK_ITERATORS: {
+      if ( !checkIterators(mesh, verbose, out) ) {
+        if(status) *status = WRONG_ITERATORS;
+        return false;
+      }
+      break;
+    }
+    case CHECK_PARAMETERS: {
+      if ( !checkParameters(mesh, verbose, out) ) {
+        if(status) *status = WRONG_PARAMETERS;
+        return false;
+      }
+      break;
+    }
+    default: {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Not a valid checkType: %d",type);
+      return false;
+    }
+    }
+
+    if(status) *status = VALID;
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Mesh/CheckMesh.h b/Mesh/CheckMesh.h
new file mode 100644
index 0000000..fcf46b7
--- /dev/null
+++ b/Mesh/CheckMesh.h
@@ -0,0 +1,58 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _CHECKMESH_H_
+#define _CHECKMESH_H_
+
+#include "MeshDataBaseInterface.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  typedef enum MeshStatus { 
+    VALID                   = 0,
+    NEGATIVE_VOLUME         = 1,
+    GEOM_INCOMPATIBILITY    = 2,
+    WRONG_EDGE_TO_RGN_CONN  = 3,
+    WRONG_FACE_TO_RGN_CONN  = 4,
+    WRONG_FACE_TO_VTX_CONN  = 5,
+    WRONG_EDGE_CONN         = 6,
+    WRONG_ENTITY_POINTERS   = 7,
+    WRONG_ITERATORS         = 8,
+    WRONG_PARAMETERS        = 9
+  } MeshStatus;
+
+  // -------------------------------------------------------------------
+  typedef enum checkType { 
+    CHECK_ALL,
+    CHECK_VOLUME,
+    CHECK_GEOM_COMPATIBILITY,
+    CHECK_EDGE_TO_RGN_CONN,
+    CHECK_FACE_TO_RGN_CONN,
+    CHECK_FACE_TO_VTX_CONN,
+    CHECK_EDGE_CONN,
+    CHECK_ENTITY_POINTERS,
+    CHECK_ITERATORS,
+    CHECK_PARAMETERS
+  } checkType;
+
+  // -------------------------------------------------------------------
+  // return 1 if the mesh passes the test successfully, 0 otherwise
+  bool checkMesh(MDB_Mesh * mesh, checkType type, int verbose, 
+                 std::ostream& out=std::cout, MeshStatus * status=NULL);
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Mesh/CheckOrientation.cc b/Mesh/CheckOrientation.cc
new file mode 100644
index 0000000..94269c8
--- /dev/null
+++ b/Mesh/CheckOrientation.cc
@@ -0,0 +1,415 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "MSops.h"
+
+#ifdef PARALLEL
+#include <cassert>
+
+#include "mpi.h"
+#include "autopack.h"
+
+#include "MeshDataBase.h"
+
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseParallelInterface.h"
+
+#include "CheckOrientation.h"
+
+namespace MAd {
+  
+  struct edge_comm
+  {
+    pVertex p1,p2;                //pointer in dest
+    int     sendID;       
+  };
+  
+  struct face_comm {
+    pVertex pdest[3];
+  };  
+
+  int CheckEdgesOrientation(pMesh mesh){
+#ifdef DEBUG
+    int norient = 0;
+#endif
+    int nproc,myrank;
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+    int *sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+
+    pMeshDataId tagData   = MD_lookupMeshDataId("RemotePoint");
+    EIter eit = M_edgeIter(mesh);
+    pEdge pedge;  
+    while ((pedge = EIter_next(eit))) {
+      pVertex p[2];
+      p[0] = E_vertex(pedge,0);
+      p[1] = E_vertex(pedge,1);
+      int tmp1;
+      int isInterface1 = EN_getDataInt((pEntity) p[0] ,tagData, &tmp1);
+      int tmp2;
+      int isInterface2 = EN_getDataInt((pEntity) p[1] ,tagData, &tmp2);
+      if(!isInterface1 || !isInterface2) continue;
+      const std::vector<std::pair<int , pVertex> > *recup1 = (std::vector<std::pair<int , pVertex> > *) tmp1;
+      const std::vector<std::pair<int , pVertex> > *recup2 = (std::vector<std::pair<int , pVertex> > *) tmp2;
+      int size1 = (*recup1).size();
+      int size2 = (*recup2).size();
+      assert(size1);assert(size2);
+      int *tab=new int[size1];
+      for(int i=0 ; i< size1 ; i++) tab[i] = (*recup1)[i].first;
+      //check if myrank must send
+      int nSender = myrank;
+      for(int j=0 ; j< size2 ; j++) {    
+        int iProc = (*recup2)[j].first;
+        int i;
+        for(i=0 ; i<size1 ; i++) {
+          if(iProc == tab[i]) break;
+        }
+        if(i<size1) {
+          if(iProc < nSender) nSender = iProc;
+        }
+      }
+      if(nSender != myrank) continue;
+      for(int j=0 ; j< size2 ; j++) {    
+        int iProc = (*recup2)[j].first;
+        int i;
+        for(i=0 ; i<size1 ; i++) {
+          if(iProc == tab[i]) break;
+        }
+        if(i < size1) {  
+          pVertex remote1 = (*recup1)[i].second;
+          pVertex remote2 = (*recup2)[j].second;
+          assert(iProc != myrank);
+          assert(iProc > myrank);
+          void *buf = AP_alloc(iProc,444,sizeof(edge_comm));
+          edge_comm *castbuf = (edge_comm *) buf;
+          castbuf->p1	   = remote1;
+          castbuf->p2	   = remote2,
+            castbuf->sendID    = myrank;
+          AP_send(buf);
+          sendcounts[iProc]++;         
+        }
+      }  
+      delete []tab;
+    }
+    EIter_delete(eit); 
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+  
+    int message=0;
+    int count;
+  
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int from;
+      int tag;
+      int size;
+      int rc;
+      rc=AP_recv(MPI_ANY_SOURCE,444, AP_BLOCKING|AP_DROPOUT,
+                 &msg, &size, &from, &tag);
+      if (rc) {
+        message++;
+        edge_comm * castbuf = (edge_comm*) msg;
+        pVertex p1recv,p2recv;
+        p1recv = castbuf -> p1;
+        p2recv = castbuf -> p2;
+        assert(p1recv);assert(p2recv);
+        int nprocrecv = castbuf->sendID;
+        assert(nprocrecv==from);
+        pEdge pe = E_exist(p1recv,p2recv);
+        if(pe) {
+          //check orientation
+          if(E_vertex(pe,0) != p1recv) {
+#ifdef DEBUG
+            norient++;
+#endif
+            pe->p1 = p1recv;
+            pe->p2 = p2recv;
+            assert(E_vertex(pe,0) == p1recv);
+          }
+        } 
+        AP_free(msg);
+      }
+    }    
+    AP_check_sends(AP_WAITALL); 
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;
+#ifdef DEBUG
+    return norient;
+#else    
+    return 0;
+#endif  
+  }
+
+
+  int CheckFacesOrientation(pMesh mesh){
+#ifdef DEBUG
+    int norient = 0;
+#endif
+    int mysize,myrank;
+    MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank); 
+ 
+    int *sendcounts = new int[mysize];
+    for(int i=0;i<mysize;i++) sendcounts[i]=0;
+  
+    pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+  
+    FIter fit = M_faceIter(mesh);
+    pFace pface;  
+    while ((pface = FIter_next(fit))) {
+      pVertex p1 = F_vertex(pface,0);
+      pVertex p2 = F_vertex(pface,1);
+      pVertex p3 = F_vertex(pface,2);
+      void *temp_ptr1,*temp_ptr2,*temp_ptr3; 
+      int isInterface1 = EN_getDataPtr((pEntity) p1 , tagData, &temp_ptr1);
+      int isInterface2 = EN_getDataPtr((pEntity) p2 , tagData, &temp_ptr2);
+      int isInterface3 = EN_getDataPtr((pEntity) p3 , tagData, &temp_ptr3);
+      if(!(isInterface1 && isInterface2 && isInterface3)) continue;
+   
+      const std::vector<std::pair<int , pVertex> > *recup1 = (std::vector<std::pair<int , pVertex> > *) temp_ptr1;
+      const std::vector<std::pair<int , pVertex> > *recup2 = (std::vector<std::pair<int , pVertex> > *) temp_ptr2;
+      const std::vector<std::pair<int , pVertex> > *recup3 = (std::vector<std::pair<int , pVertex> > *) temp_ptr3;
+      int size = (*recup1).size();
+      int *tab=new int[size];
+      for(int i=0 ; i< size ; i++) tab[i] = (*recup1)[i].first;
+    
+      int size2 = (*recup2).size();
+      int *tab2=new int[size2];
+      for(int i=0 ; i< size2 ; i++) tab2[i] = (*recup2)[i].first;
+
+      // check if I must send
+      int nSender = myrank;
+      for(unsigned int k=0 ; k<(*recup3).size() ; k++) {	 
+        int iProc = (*recup3)[k].first;
+        int i;
+        for(i=0 ; i<size ; i++) {
+          if(iProc == tab[i]) break;
+        }
+        int j;
+        for(j=0 ; j<size2 ; j++) {
+          if(iProc == tab2[j]) break;
+        }       
+        if(i < size && j < size2) {
+          if(iProc < nSender) nSender = iProc;
+        }
+      }
+    
+      if(nSender != myrank) continue;
+    
+      for(unsigned int k=0 ; k<(*recup3).size() ; k++) {	 
+        int iProc = (*recup3)[k].first;
+        int i;
+        for(i=0 ; i<size ; i++) {
+          if(iProc == tab[i]) break;
+        }
+        int j;
+        for(j=0 ; j<size2 ; j++) {
+          if(iProc == tab2[j]) break;
+        }       
+        if(i < size && j < size2) {
+          assert(tab[i]==iProc);
+          assert(tab2[j]==iProc);
+        
+          pVertex remote1 = (*recup1)[i].second;
+          pVertex remote2 = (*recup2)[j].second;
+          pVertex remote3 = (*recup3)[k].second;
+        
+          void *buf = AP_alloc(iProc,444,sizeof(face_comm));       
+          face_comm *castbuf = (face_comm *) buf;
+          castbuf->pdest[0]	   = remote1;
+          castbuf->pdest[1]	   = remote2,
+            castbuf->pdest[2]	   = remote3,
+            AP_send(buf);
+          sendcounts[iProc]++;    
+        }
+      }
+      delete []tab;
+      delete []tab2;
+    }      
+    FIter_delete(fit);  
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts); 
+  
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        face_comm * facecom = (face_comm * ) msg;
+        pVertex  p1 = facecom->pdest[0];
+        pVertex  p2 = facecom->pdest[1];
+        pVertex  p3 = facecom->pdest[2];
+        pEdge    pe[3];
+        pe[0] =  E_exist(p1,p2);
+        pe[1] =  E_exist(p2,p3);
+        pe[2] =  E_exist(p1,p3);
+      
+        if(pe[0] && pe[1] && pe[2]) {
+          // pFace pface = F_exist(2,p1,p2,p3,0);
+          pFace pface = F_exist(p1,p2,p3,0);
+          assert(pface);
+      
+          //check orientation
+          if(F_edge(pface,0) != pe[0] || F_edge(pface,1) != pe[1]) {
+            ((MDB_Triangle*)pface)->e1 = pe[0];
+            ((MDB_Triangle*)pface)->e2 = pe[1];
+            ((MDB_Triangle*)pface)->e3 = pe[2];
+#ifdef DEBUG
+            norient++;
+#endif	  	
+          }        
+        }       
+        AP_free(msg);      
+      }    
+    }      
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;
+#ifdef DEBUG
+    return norient;
+#else  
+    return 0;
+#endif	  	
+  }
+
+/*
+// version with sets for the parallel nodes
+int CheckEdgesOrientation(pMesh mesh){
+#ifdef DEBUG
+int norient = 0;
+#endif
+int nproc,myrank;
+MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+int *sendcounts = new int[nproc];
+for(int i=0;i<nproc;i++)sendcounts[i]=0;
+
+pMeshDataId tagData   = MD_lookupMeshDataId("RemotePoint");
+EIter eit = M_edgeIter(mesh);
+pEdge pedge;  
+while ((pedge = EIter_next(eit))) {
+pVertex p[2];
+p[0] = E_vertex(pedge,0);
+p[1] = E_vertex(pedge,1);
+int tmp1;
+int isInterface1 = EN_getDataInt((pEntity) p[0] ,tagData, &tmp1);
+int tmp2;
+int isInterface2 = EN_getDataInt((pEntity) p[1] ,tagData, &tmp2);
+if(!isInterface1 || !isInterface2) continue;
+const std::set<std::pair<int, MDB_Point*> > *recup1 = (std::set<std::pair<int, MDB_Point*> > *) temp_ptr1;
+const std::set<std::pair<int, MDB_Point*> > *recup2 = (std::set<std::pair<int, MDB_Point*> > *) temp_ptr2;
+int size1 = (*recup1).size();
+int size2 = (*recup2).size();
+assert(size1);assert(size2);
+int *tab=new int[size1];
+std::set<std::pair<int, MDB_Point*> >::const_iterator rIter1 = recup1->begin();
+for (int i=0; rIter1 != recup1->end(); rIter1++, i++) tab[i] = (*rIter1).first;
+int nSender = myrank;
+std::set<std::pair<int, MDB_Point*> >::const_iterator rIter2 = recup2->begin();
+for (int j=0; rIter2 != recup2->end(); rIter2++, j++) {
+int iProc = (*rIter2).first;
+int i;
+for(i=0 ; i<size1 ; i++) {
+if(iProc == tab[i]) break;
+}
+if(i<size1) {
+if(iProc < nSender) nSender = iProc;
+}
+}
+if(nSender != myrank) continue;
+rIter2 = recup2->begin();
+for (int j=0; rIter2 != recup2->end(); rIter2++, j++) {
+int iProc = (*rIter2).first;
+int i;
+rIter1 = recup1->begin();
+for (i=0; rIter1 != recup1->end(), i<size1; rIter1++, i++) {
+if(iProc == tab[i]) break;
+}
+if(i < size1) {
+pVertex remote1 = (*rIter1).second;
+pVertex remote2 = (*rIter2).second;
+assert(iProc != myrank);
+assert(iProc > myrank);
+void *buf = AP_alloc(iProc,444,sizeof(edge_comm));
+edge_comm *castbuf = (edge_comm *) buf;
+castbuf->p1	   = remote1;
+castbuf->p2	   = remote2,
+castbuf->sendID    = myrank;
+AP_send(buf);
+sendcounts[iProc]++;         
+}
+}  
+delete []tab;
+}
+EIter_delete(eit); 
+AP_check_sends(AP_NOFLAGS);
+AP_reduce_nsends(sendcounts);
+  
+int message=0;
+int count;
+  
+while (!AP_recv_count(&count) || message<count) {
+void *msg;
+int from;
+int tag;
+int size;
+int rc;
+rc=AP_recv(MPI_ANY_SOURCE,444, AP_BLOCKING|AP_DROPOUT,
+&msg, &size, &from, &tag);
+if (rc) {
+message++;
+edge_comm * castbuf = (edge_comm*) msg;
+pVertex p1recv,p2recv;
+p1recv = castbuf -> p1;
+p2recv = castbuf -> p2;
+assert(p1recv);assert(p2recv);
+int nprocrecv = castbuf->sendID;
+assert(nprocrecv==from);
+pEdge pe = E_exist(p1recv,p2recv);
+if(pe) {
+//check orientation
+if(E_vertex(pe,0) != p1recv) {
+#ifdef DEBUG
+norient++;
+#endif
+pe->p1 = p1recv;
+pe->p2 = p2recv;
+assert(E_vertex(pe,0) == p1recv);
+}
+} 
+AP_free(msg);
+}
+}    
+AP_check_sends(AP_WAITALL); 
+MPI_Barrier(MPI_COMM_WORLD);
+delete [] sendcounts;
+#ifdef DEBUG
+return norient;
+#else    
+return 0;
+#endif  
+}
+*/
+
+}
+
+#endif
diff --git a/Mesh/CheckOrientation.h b/Mesh/CheckOrientation.h
new file mode 100644
index 0000000..35d4bea
--- /dev/null
+++ b/Mesh/CheckOrientation.h
@@ -0,0 +1,28 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _CHECKORIENTATION_H_
+#define _CHECKORIENTATION_H_
+
+#ifdef PARALLEL
+
+#include "MeshDataBaseInterface.h"
+
+namespace  MAd {
+  int CheckEdgesOrientation(pMesh mesh);
+  int CheckFacesOrientation(pMesh mesh);
+}
+
+#endif
+
+#endif
diff --git a/Mesh/MSops.h b/Mesh/MSops.h
new file mode 100644
index 0000000..77ef95f
--- /dev/null
+++ b/Mesh/MSops.h
@@ -0,0 +1,18 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _MESHDATABASE_OPS
+#define _MESHDATABASE_OPS
+#include "ModelInterface.h"
+#include "MeshDataBaseInterface.h"
+#endif
diff --git a/Mesh/Makefile b/Mesh/Makefile
new file mode 100644
index 0000000..055132f
--- /dev/null
+++ b/Mesh/Makefile
@@ -0,0 +1,69 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information. 
+# You should have received a copy of these files along with MAdLib. 
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../variables
+
+LIB = ../lib/libMAdMesh${LIBEXT}
+
+INC =  ${MAdLib_INCLUDES}\
+       ${DASH}I$(MAdROOT)/Geo\
+       ${DASH}I$(MAdROOT)/Mesh\
+       ${DASH}I$(MAdROOT)/Common
+
+ALLFLAGS = ${OPTIM} ${CXXFLAGS} ${MAdLib_DEFS} ${FLAGS} ${INC} ${SYSINCLUDE}
+
+SRC = Balance.cc\
+      CheckMesh.cc\
+      CheckOrientation.cc\
+      Mark.cc\
+      MeshDataBase.cc\
+      MeshDataBaseComm.cc\
+      MeshDataBaseCommCheck.cc\
+      MeshDataBaseGEntity2Physical.cc\
+      MeshDataBaseInterface.cc\
+      MeshDataBaseIO.cc\
+      MeshDataBaseLoadBalancing.cc\
+      MeshDataBaseMessage.cc\
+      MeshDataBaseMigration.cc\
+      MeshDataBaseMiniMesh.cc\
+      MeshDataBaseParallelInterface.cc\
+      MeshDataBaseParallelIO.cc\
+      metisAdaptiveRepart.cc\
+      ParallelUtils.cc\
+      PeriodicInterfaceMigration.cc
+
+OBJ = ${SRC:.cc=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cc
+
+${LIB}: ${OBJ} 
+	${AR} ${ARFLAGS} ${LIB} ${OBJ}
+	${RANLIB} ${LIB}
+
+cpobj: ${OBJ} 
+	cp -f ${OBJ} ${MAdLib_TMPDIR}/.
+
+.cc${OBJEXT}:
+	${CXX} ${ALLFLAGS} ${DASH}c $< ${DASH}o $@
+
+clean:
+	${RM} */*.o *.o *.obj
+
+purge:
+
+depend:
+	(sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+         ${CXX} -MM ${ALLFLAGS} ${SRC} | sed 's/.o:/$${OBJEXT}:/g' \
+        ) > Makefile.new
+	cp Makefile Makefile.bak
+	cp Makefile.new Makefile
+	rm -f Makefile.new
\ No newline at end of file
diff --git a/Mesh/Mark.cc b/Mesh/Mark.cc
new file mode 100644
index 0000000..9828ea6
--- /dev/null
+++ b/Mesh/Mark.cc
@@ -0,0 +1,1332 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "Mark.h"
+#include "MSops.h"
+#include "MeshDataBase.h"
+
+#include "assert.h"
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+#endif
+
+namespace MAd {
+
+#ifdef PARALLEL
+  // -------------------------------------------------------------------
+  void MarkTets(pMesh mesh,pMeshDataId tagElt)
+  {
+    int nproc,myrank;
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+    pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+
+    int * tab = new int[nproc];
+    int sendnum = mesh->nbPoints; 
+    if(myrank) {
+      MPI_Send(&sendnum,1,MPI_INT,0,myrank,MPI_COMM_WORLD);   
+    } else {
+      MPI_Status status;
+      tab[0] = sendnum;
+      for(int i=1 ; i<nproc ; i++) {
+        MPI_Recv(&tab[i],1,MPI_INT,i,i,MPI_COMM_WORLD,&status);
+      }
+    }
+  
+    MPI_Bcast(&tab[0],nproc,MPI_INT,0,MPI_COMM_WORLD);
+    MPI_Barrier(MPI_COMM_WORLD);
+
+    int npGlob = 0;
+    for(int i=0 ; i<nproc ; i++) npGlob +=tab[i];
+  
+    /* 1) marked regions*/
+    RIter rit = M_regionIter(mesh);
+    pRegion pr;  
+    while ((pr = RIter_next(rit))) {
+      //int dest  = rand()%nproc;
+
+      int dest = myrank;// = rand()%nproc;
+      pVertex nod[4];
+      for(int i=0 ; i<4 ; i++) {
+        nod[i] = R_vertex(pr,i);
+        void *temp_ptr; 
+        int isInterface = EN_getDataPtr((pEntity) nod[i] , tagData, &temp_ptr);
+        int maxproc = myrank;
+        if(isInterface) {
+          const std::vector<std::pair<int , pVertex> > *recup = (std::vector<std::pair<int , pVertex> > *) temp_ptr;
+          for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+            int numproc = (*recup)[j].first;
+            if(tab[numproc] < tab[maxproc]) {
+              maxproc = numproc;
+            }
+          }
+        }
+        if(tab[maxproc] < tab[dest]) dest = maxproc;
+      }  
+      assert(dest<nproc);
+      assert(dest>=0);
+      if(dest == myrank) continue;
+      EN_attachDataInt((pEntity) pr ,tagElt, dest + 1);
+    }  
+    RIter_delete(rit);
+    delete []tab;
+  }
+
+
+  // -------------------------------------------------------------------
+  void MarkTetsSmooth(pMesh mesh,pMeshDataId tagElt)
+  {
+    int nproc,myrank;
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+    pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+
+    int *tab=new int[nproc];
+    int sendnum = mesh->nbPoints; 
+    if(myrank) {
+      MPI_Send(&sendnum,1,MPI_INT,0,myrank,MPI_COMM_WORLD);   
+    } else {
+      MPI_Status status;
+      tab[0] = sendnum;
+      for(int i=1 ; i<nproc ; i++) {
+        MPI_Recv(&tab[i],1,MPI_INT,i,i,MPI_COMM_WORLD,&status);
+      }
+    }
+  
+    MPI_Bcast(&tab[0],nproc,MPI_INT,0,MPI_COMM_WORLD);
+    MPI_Barrier(MPI_COMM_WORLD);
+
+    int npGlob = 0;
+    for(int i=0 ; i<nproc ; i++) npGlob +=tab[i];
+  
+    /* 1) marked regions*/
+    RIter rit = M_regionIter(mesh);
+    pRegion pr;  
+    while ((pr = RIter_next(rit))) {
+      //int dest  = rand()%nproc;
+
+      int dest = myrank;// = rand()%nproc;
+      pVertex nod[4];
+      for(int i=0 ; i<4 ; i++) {
+        nod[i] = R_vertex(pr,i);
+        void *temp_ptr; 
+        int isInterface = EN_getDataPtr((pEntity) nod[i] , tagData, &temp_ptr);
+        int maxproc = myrank;
+        if(isInterface) {
+          const std::vector<std::pair<int , pVertex> > *recup = (std::vector<std::pair<int , pVertex> > *) temp_ptr;
+          for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+            int numproc = (*recup)[j].first;
+            if(tab[numproc] < tab[maxproc]) {
+              maxproc = numproc;
+            }
+          }
+        }
+        if(tab[maxproc] < tab[dest]) dest = maxproc;
+      }  
+      assert(dest<nproc);
+      assert(dest>=0);
+      if(dest == myrank) continue;
+      EN_attachDataInt((pEntity) pr ,tagElt, dest + 1);
+    }  
+    RIter_delete(rit);
+
+    //mark neighboor of interface tetras
+    int    iter = 0;
+    int maxiter = 1;
+    int  tetmove = 10;  
+    while(iter<maxiter) {
+      tetmove = 0;
+      rit = M_regionIter(mesh); 
+      while ((pr = RIter_next(rit))) {
+        int dest;
+        int isMove = EN_getDataInt((pEntity) pr ,tagElt, &dest);
+        if(!isMove) continue;
+        if(iter%2)
+          if(dest < 0) continue;
+          else 
+            if(dest > 0) continue;
+        EN_attachDataInt((pEntity) pr ,tagElt, -dest) ;
+        for(int i = 0 ; i<4 ; i++) {
+          pFace pface     = R_face(pr,i);
+          pRegion prother;
+          int k =0;
+          for(k = 0; k <  F_numRegions(pface); k++) {
+            prother = F_region(pface,k);
+            if(prother != pr) break;
+          }
+          if(k ==	F_numRegions(pface)) continue;
+          int destother;
+          int is = EN_getDataInt((pEntity) prother ,tagElt, &destother);
+          if(!is) EN_attachDataInt((pEntity) prother ,tagElt, -dest) ;    
+        }
+      }  
+      RIter_delete(rit);  
+      //printf("iter neigh %d : %d\n",iter,trmove);
+      iter++;
+    }
+    //smooth new interfaces
+    iter = 0;
+    maxiter = 10;
+    tetmove = 10;
+    while(tetmove && iter<maxiter) {
+      tetmove = 0;
+      rit = M_regionIter(mesh); 
+      while ((pr = RIter_next(rit))) {
+        int dest;
+        int isMove = EN_getDataInt((pEntity) pr ,tagElt, &dest);
+        if(!isMove) continue;
+        if(dest < 0) EN_attachDataInt((pEntity) pr ,tagElt, abs(dest));
+        dest = abs(dest);
+        if((dest-1)== myrank) continue;
+        //how many neighboors in dest-1?
+        int nbN = 0;
+        int destreal = dest;
+        int nb = 0;
+        for(int i = 0 ; i < 4 ; i++) {
+          pFace pface     = R_face(pr,i);
+          pRegion prother;
+          int k =0;
+          for(k = 0; k <  F_numRegions(pface); k++) {
+            prother = F_region(pface,k);
+            if(prother != pr) break;
+          }
+          if(k ==	F_numRegions(pface)) continue;
+          int destother;
+          int is = EN_getDataInt((pEntity) prother ,tagElt, &destother);
+          if(!is) continue;
+          if(destother == dest) nb++;
+          else destreal = destother;    
+        }
+        int nbGood = 4 - nbN + nb;
+        if(nbGood==1 || nbGood==2) {
+          tetmove++;
+          //printf("smoothing new interfaces : %d\n",pface->iD);
+          if(destreal == dest) {
+            //printf("nbGood : %d %d\n",nbN,nb);
+            EN_deleteData((pEntity) pr ,tagElt);
+          } else {
+            EN_attachDataInt((pEntity) pr ,tagElt, abs(destreal));
+          }
+        }
+      }  
+      RIter_delete(rit);
+      //printf("iter smoothing %d : %d\n",iter,tetmove);
+      iter++;
+    }
+  
+    //attach positive destination
+    rit = M_regionIter(mesh);
+    while ((pr = RIter_next(rit))) {
+      int dest;
+      int isMove = EN_getDataInt((pEntity) pr ,tagElt, &dest);
+      if(isMove) {
+        if(dest < 0) EN_attachDataInt((pEntity) pr ,tagElt, abs(dest));
+        //assert(dest > 0);
+      }
+    }  
+    RIter_delete(rit);
+    delete []tab;
+  }
+
+  // -------------------------------------------------------------------
+  void MarkTetsRandom(pMesh mesh, pMeshDataId tagElt) {
+
+    int nproc,myrank;
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+  
+    RIter rit = M_regionIter(mesh);
+    pRegion pr;  
+    while ((pr = RIter_next(rit))) {
+      int dest = rand() % nproc;
+      if(dest == myrank) continue;
+      EN_attachDataInt((pEntity) pr, tagElt, dest + 1);
+    }  
+    RIter_delete(rit);
+  }
+
+  // -------------------------------------------------------------------
+  int MarkTetsManifold(pMesh mesh,pMeshDataId tagElt) {
+
+    int nmanifold = 0;
+
+    int nproc,myrank;
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+    pMeshDataId tagData   = MD_lookupMeshDataId("RemotePoint");
+    EIter eit = M_edgeIter(mesh);
+    pEdge ped;
+    while ((ped = EIter_next(eit))) {
+      pVertex p1 = E_vertex(ped,0);
+      pVertex p2 = E_vertex(ped,1);
+      void *temp_ptr1,*temp_ptr2; 
+      int isInterface1 = EN_getDataPtr((pEntity) p1 , tagData, &temp_ptr1);
+      int isInterface2 = EN_getDataPtr((pEntity) p2 , tagData, &temp_ptr2);
+      if(!(isInterface1 && isInterface2)) continue;
+      int nFace = 0;
+      int dest = myrank;// = rand()%nproc;
+      int maxproc = myrank;
+      for(int i=0 ; i<E_numFaces(ped) ; i++) {
+        pFace pface = E_face(ped,i);
+        for(int j=0 ; j<F_numRegions(pface) ; j++) {
+          pRegion pr = F_region(pface,j);
+          pVertex nod[4];
+          for(int i=0 ; i<4 ; i++) {
+            nod[i] = R_vertex(pr,i);
+            void *temp_ptr; 
+            int isInterface = EN_getDataPtr((pEntity) nod[i] , tagData, &temp_ptr);
+            int maxproc = myrank;
+            if(isInterface) {
+              const std::vector<std::pair<int , pVertex> > *recup = (std::vector<std::pair<int , pVertex> > *) temp_ptr;
+              for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+                int numproc = (*recup)[j].first;
+                if(numproc < maxproc) {
+                  maxproc = numproc;
+                }
+              }
+            }
+          }
+          if(maxproc < dest) dest = maxproc;  	
+        }
+        if(F_numRegions(pface)==2) continue;
+        int j;
+        for(j=0 ; j<3 ; j++) {
+          pVertex pp = F_vertex(pface,j);
+          void *temp_ptr; 
+          int isInterface = EN_getDataPtr((pEntity) pp , tagData, &temp_ptr);
+          if(!isInterface) break;
+        }
+        if(j==3) nFace++;
+      }
+      if(nFace<=2) continue;
+      nmanifold++;
+      //printf("nFace %d non manifold edge\n",nFace);
+      if(dest == myrank) continue;
+      for(int i=0 ; i<E_numFaces(ped) ; i++) {
+        pFace pface = E_face(ped,i);
+        for(int j=0 ; j<F_numRegions(pface) ; j++) {
+          pRegion pr = F_region(pface,j);
+          EN_attachDataInt((pEntity) pr ,tagElt, dest + 1);
+        }
+      }
+    }
+    EIter_delete(eit);
+  
+    return(nmanifold);  
+  }
+
+  // -------------------------------------------------------------------
+  void MarkTriangles(pMesh mesh, pMeshDataId tagElt)
+  {
+    int nproc,myrank;
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+    pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+
+    // --- Every proc send its number of nodes -> collected in tab ---
+    int * tab = new int[nproc];
+    int sendnum = M_numVertices(mesh); 
+    if(myrank) {
+      MPI_Send(&sendnum,1,MPI_INT,0,myrank,MPI_COMM_WORLD);   
+    } else {
+      MPI_Status status;
+      tab[0] = sendnum;
+      for(int i=1 ; i<nproc ; i++) {
+        MPI_Recv(&tab[i],1,MPI_INT,i,i,MPI_COMM_WORLD,&status);
+      }
+    }
+    MPI_Bcast(&tab[0],nproc,MPI_INT,0,MPI_COMM_WORLD);
+    MPI_Barrier(MPI_COMM_WORLD);
+
+    int npGlob = 0;
+    for(int i=0 ; i<nproc ; i++) npGlob +=tab[i];
+  
+    // --- Mark the triangles which have at least one vertex on an interface 
+    //     with a distant mesh that has less nodes than the current one ---
+    FIter fit = M_faceIter(mesh);
+    pFace pface;
+    while ( (pface = FIter_next(fit)) ) {
+      pVertex nod[3];
+      pface->getNodes(nod);
+      int dest = myrank;
+      for(int i=0; i<3; i++) {
+        void *temp_ptr;
+        int isInterface = EN_getDataPtr((pEntity) nod[i], tagData, &temp_ptr);
+        int maxproc = myrank;
+        if(isInterface) {
+          const std::vector<std::pair<int, pVertex> > *recup = (const std::vector<std::pair<int, pVertex> > *) temp_ptr;
+          for(int j=0; j<(int)((*recup).size()); j++) {
+            int numproc = (*recup)[j].first;
+            if(tab[numproc] < tab[maxproc]) maxproc = numproc;
+          }
+        }
+        if(tab[maxproc] < tab[dest]) dest = maxproc;
+      }  
+      assert(dest<nproc);
+      assert(dest>=0);
+      if(dest == myrank) continue;
+      EN_attachDataInt((pEntity) pface, tagElt, dest + 1);
+    }  
+    FIter_delete(fit);
+    delete []tab;
+  }
+
+
+  
+  // -------------------------------------------------------------------
+  void MarkTrianglesSmooth(pMesh mesh,pMeshDataId tagElt)
+  {
+    int nproc,myrank;
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+    pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+
+    // --- Every proc send its number of nodes -> collected in tab ---
+    int * tab = new int[nproc];
+    int sendnum = M_numVertices(mesh); 
+    if(myrank) {
+      MPI_Send(&sendnum,1,MPI_INT,0,myrank,MPI_COMM_WORLD);   
+    } else {
+      MPI_Status status;
+      tab[0] = sendnum;
+      for(int i=1 ; i<nproc ; i++) {
+        MPI_Recv(&tab[i],1,MPI_INT,i,i,MPI_COMM_WORLD,&status);
+      }
+    } 
+    MPI_Bcast(&tab[0],nproc,MPI_INT,0,MPI_COMM_WORLD);
+    MPI_Barrier(MPI_COMM_WORLD);
+
+    int npGlob = 0;
+    for(int i=0 ; i<nproc ; i++) npGlob += tab[i];
+  
+    // --- Mark the triangles which have at least one vertex on an interface 
+    //     with a distant mesh that has less nodes than the current one ---
+    FIter fit = M_faceIter(mesh);
+    pFace pface;
+    while ( (pface = FIter_next(fit)) ) {
+      pVertex nod[3];
+      pface->getNodes(nod);
+      int dest = myrank;
+      for(int i=0; i<3; i++) {
+        void *temp_ptr;
+        int isInterface = EN_getDataPtr((pEntity) nod[i], tagData, &temp_ptr);
+        int maxproc = myrank;
+        if(isInterface) {
+          const std::vector<std::pair<int, pVertex> > *recup = (const std::vector<std::pair<int, pVertex> > *) temp_ptr;
+          for(int j=0; j<(int)((*recup).size()); j++) {
+            int numproc = (*recup)[j].first;
+            if(tab[numproc] < tab[maxproc]) maxproc = numproc;
+          }
+        }
+        if(tab[maxproc] < tab[dest]) dest = maxproc;
+      }  
+      assert(dest<nproc);
+      assert(dest>=0);
+      if(dest == myrank) continue;
+      EN_attachDataInt((pEntity) pface, tagElt, dest + 1);
+    }  
+    FIter_delete(fit);
+  
+    // --- Mark the neighbour triangles of the marked triangles (do it n times) ---
+    // GCREMARK: why not apply the same principle as for the first marking -> mark around nodes ?
+    int    iter = 0;
+    int maxiter = 1;
+    int  trmove = 10;  
+    while(iter<maxiter) {
+      trmove = 0;
+      fit = M_faceIter(mesh); 
+      while ((pface = FIter_next(fit))) {
+        int dest;
+        int isMove = EN_getDataInt((pEntity) pface ,tagElt, &dest);
+        if(!isMove) continue;
+        if(iter%2)
+          if(dest < 0) continue;
+          else 
+            if(dest > 0) continue;
+        EN_attachDataInt((pEntity) pface ,tagElt, -dest) ;
+        for(int i = 0 ; i<3 ; i++) {
+          pEdge ped     = F_edge(pface,i);
+          pFace pfother;
+          int k =0;
+          for(k = 0; k <  E_numFaces(ped); k++) {
+            pfother = E_face(ped,k);
+            if(pfother != pface) break;
+          }
+          if(k ==	E_numFaces(ped)) continue;
+          int destother;
+          int is = EN_getDataInt((pEntity) pfother ,tagElt, &destother);
+          if(!is) EN_attachDataInt((pEntity) pfother ,tagElt, -dest) ;    
+        }
+      }  
+      FIter_delete(fit);  
+      //printf("iter neigh %d : %d\n",iter,trmove);
+      iter++;
+    }
+
+    // --- Smooth new interfaces ---
+    iter = 0;
+    maxiter = 10;
+    trmove = 10;
+    while(trmove && iter<maxiter) {
+      trmove = 0;
+      fit = M_faceIter(mesh); 
+      while ((pface = FIter_next(fit))) {
+        int dest;
+        int isMove = EN_getDataInt((pEntity) pface ,tagElt, &dest);
+        if(!isMove) continue;
+        if(dest < 0) EN_attachDataInt((pEntity) pface ,tagElt, abs(dest));
+        dest = abs(dest);
+        if((dest-1)== myrank) continue;
+        //how many neighbours in dest-1?
+        int nbN = 0;
+        int destreal = dest;
+        int nb = 0;
+        for(int i = 0 ; i < 3 ; i++) {
+          pEdge ped     = F_edge(pface,i);
+          pFace pfother;
+          int k =0;
+          for(k = 0; k <  E_numFaces(ped); k++) {
+            pfother = E_face(ped,k);
+            if(pfother != pface) break;
+          }
+          if(k ==	E_numFaces(ped)) continue;
+          int destother;
+          int is = EN_getDataInt((pEntity) pfother ,tagElt, &destother);
+          if(!is) continue;
+          if(destother == dest) nb++;
+          else destreal = destother;    
+        }
+        int nbGood = 3 - nbN + nb;
+        if(nbGood==1) {
+          trmove++;
+          //printf("smoothing new interfaces : %d\n",pface->iD);
+          if(destreal == dest) {
+            //printf("nbGood : %d %d\n",nbN,nb);
+            EN_deleteData((pEntity) pface ,tagElt);
+          } else {
+            EN_attachDataInt((pEntity) pface ,tagElt, abs(destreal));
+          }
+        }
+      }  
+      FIter_delete(fit);
+      printf("iter smoothing %d : %d\n",iter,trmove);
+      iter++;
+    }
+
+    // --- Attach positive destination ---
+    fit = M_faceIter(mesh);
+    while ((pface = FIter_next(fit))) {
+      int dest;
+      int isMove = EN_getDataInt((pEntity) pface ,tagElt, &dest);
+      if(isMove) {
+        if(dest < 0) EN_attachDataInt((pEntity) pface ,tagElt, abs(dest));
+        //assert(dest > 0);
+      }
+    }  
+    FIter_delete(fit);
+    delete []tab;
+  }
+
+  // -------------------------------------------------------------------
+  void MarkTrianglesRandom(pMesh mesh, pMeshDataId tagElt) {
+
+    int nproc,myrank;
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+  
+    FIter fit = M_faceIter(mesh);
+    pFace pf;
+    while ((pf = FIter_next(fit))) {
+      int dest = rand() % nproc;
+      if(dest == myrank) continue;
+      EN_attachDataInt((pEntity) pf, tagElt, dest + 1);
+    }
+    FIter_delete(fit);
+  }
+#endif
+
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  /*loop on an edges list for 3-periodic cases*/   
+  bool compare(pEdge p1, pEdge p2) {
+    pVertex p10 = E_vertex(p1,0);
+    pVertex p11 = E_vertex(p1,1);
+    pVertex p20 = E_vertex(p2,0);
+    pVertex p21 = E_vertex(p2,1);
+
+    double len1 = (p10->X-p11->X)*(p10->X-p11->X) + (p10->Y-p11->Y)*(p10->Y-p11->Y) +(p10->Z-p11->Z)*(p10->Z-p11->Z);
+    double len2 = (p20->X-p21->X)*(p20->X-p21->X) + (p20->Y-p21->Y)*(p20->Y-p21->Y) +(p20->Z-p21->Z)*(p20->Z-p21->Z);
+    //	printf("    edge %d %d : %e\n",EN_id((pEntity) p10),EN_id((pEntity) p11),len1) ;
+    //	printf(" et edge %d %d : %e\n",EN_id((pEntity) p20),EN_id((pEntity) p21),len2) ;
+    int num11 = EN_id((pEntity) p10);
+    int num12 = EN_id((pEntity) p11);
+    int num21 = EN_id((pEntity) p20);
+    int num22 = EN_id((pEntity) p21);  
+    //	printf("egal %d %d %d\n",len1==len2,num11==num21,num12<num22)  ;
+	
+    if(len1==len2) {
+      if(num11==num21) {
+        return(num12>num22);
+      } else {
+        return(num11>num21);  
+      }
+    }
+    return ((len1 > len2));
+  }  
+
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  void VertexTagMoveList(pMesh mesh, std::vector<std::vector<int> >& transforef,
+                         pMeshDataId tagMove,pMeshDataId tagTransfo) {
+    pMeshDataId tagPeriodic     = MD_lookupMeshDataId("PeriodicPoint");
+  
+    /*building list*/ 
+    std::list<pEdge> listedge;
+    EIter eit = M_edgeIter(mesh);
+    pEdge ped;  
+    while ((ped = EIter_next(eit))) { 
+      //	pVertex p0 = E_vertex(ped,0);
+      //    pVertex p1 = E_vertex(ped,1);
+      //printf("adding %d %d\n",EN_id((pEntity) p0),EN_id((pEntity) p1));
+      listedge.push_back(ped);
+    } 
+    EIter_delete(eit);  
+    //GCRMK: anisotropic case!!
+    listedge.sort(compare);   
+
+    /*favorite direction ?*/
+    int direct = 0;
+    int refsize = transforef.size();
+    for(unsigned int kt = 0 ; kt < transforef[0].size(); kt++) {
+      direct += transforef[0][kt]*transforef[0][kt];
+    }
+    //printf("********** favorite direction ??? %d\n",direct);
+
+
+    for(std::list<pEdge>::iterator it = listedge.begin() ; it!=listedge.end() ; it++) {  
+      pEdge ped = (*it);
+      /*summits of edge ped*/
+      pVertex p0 = E_vertex(ped,0);
+      pVertex p1 = E_vertex(ped,1);
+      if(it==listedge.begin()) printf("the longest is %d %d\n",EN_id(p0),EN_id(p1));
+      pVertex pFix0,pFix1;
+      std::vector<int> vectnod;
+      int find = 0; 	
+      /*sommets periodics ?*/
+      void *temp_ptr0; 
+      int isP0 = EN_getDataPtr((pEntity) p0 , tagPeriodic, &temp_ptr0);
+      if(!isP0) continue;
+      void *temp_ptr1; 
+      int isP1 = EN_getDataPtr((pEntity) p1 , tagPeriodic, &temp_ptr1);
+      if(!isP1) continue; 
+      /*sommets deja tagges ?*/
+      int move0;
+      int isM0 = EN_getDataInt((pEntity) p0 ,tagMove, &move0);
+      if(!(!isM0 || (move0 == -2))) continue;	  
+      int move1;
+      int isM1 = EN_getDataInt((pEntity) p1 ,tagMove, &move1);
+      if(!(!isM1 || (move1 == -2))) continue;	  
+    
+      //printf("treat edge %d %d\n",EN_id((pEntity) p0),EN_id((pEntity) p1));    
+      std::vector<std::pair<std::vector<int> , pVertex> > *recup0 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr0;
+      std::vector<std::pair<std::vector<int> , pVertex> > *recup1 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr1;
+    
+      /*a-t-on deja une direction privilegiee ?*/
+      if(1/*!direct*/) {
+        unsigned int j=0;
+        for(j=0 ; j<(*recup0).size() ; j++) {
+          std::vector<int> transfo0 = (*recup0)[j].first;
+          pVertex pImg0 = (*recup0)[j].second;
+          //if(pImg0==p1) continue; 
+          unsigned int j1;
+          for(j1=0 ; j1<(*recup1).size() ; j1++) {
+            std::vector<int> transfo1 = (*recup1)[j1].first;
+            pVertex pImg1 = (*recup1)[j1].second;
+            //if(pImg1==p0) continue;  
+    
+            /*transfo0 == transfo1 ?*/
+            assert(transfo1.size()==transfo0.size());
+            unsigned int kt = 0;
+            for(kt = 0 ; kt < transfo0.size(); kt++) {
+              if(transfo0[kt] != transfo1[kt]) break;
+            }
+            if(kt!=transfo0.size()) continue; 
+            /* pImg1-pImg0 existe ?*/
+            if ( !E_exist(pImg0,pImg1) && !E_exist(pImg1,pImg0) ) continue;
+            /* a-t-on deja trouve une arete img ?*/
+            //printf("img edge %d %d\n",EN_id((pEntity) pImg0),EN_id((pEntity) pImg1));    
+            if(!find) {
+              //if(it==listedge.begin()) printf("c'est bon on bouge\n");
+              /*si le point img bouge, on bouge pas!*/
+              int moveI0;
+              int isMI0 = EN_getDataInt((pEntity) pImg0 ,tagMove, &moveI0);
+              int moveI1;
+              int isMI1 = EN_getDataInt((pEntity) pImg1 ,tagMove, &moveI1);
+              if (isMI0 && (moveI0==1) ) continue;   	  
+              if (isMI1 && (moveI1==1) ) continue;  
+              if(!direct) { 	  
+                find = 1;
+                int move = 1;  
+                EN_attachDataInt((pEntity) p0 ,tagMove, move);
+                EN_attachDataInt((pEntity) p1 ,tagMove, move);
+                move = -1;  
+                EN_attachDataInt((pEntity) pImg0 ,tagMove, move);
+                EN_attachDataInt((pEntity) pImg1 ,tagMove, move);
+    
+                /*on garde les deux points img*/
+                pFix0 = pImg0;
+                pFix1 = pImg1;
+                /*rajout de la transfo avec laquelle bouger les points*/
+                for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+                  vectnod.push_back(transfo0[kt]);
+                  transforef[0][kt] = transfo0[kt];         
+                } 
+                EN_attachDataPtr((pEntity) p0 , tagTransfo,new std::vector<int>(vectnod)); 
+                EN_attachDataPtr((pEntity) p1 , tagTransfo,new std::vector<int>(vectnod)); 	
+                for(unsigned int kt = 0 ; kt < transforef[0].size(); kt++) {
+                  direct += transforef[0][kt]*transforef[0][kt];
+                } 
+                //printf("on a une direct %d : %d %d\n",direct,transforef.size(),refsize);
+              } else { /*on a deja une direction privilegiee*/
+                double pds = 0;
+                for(int st = 0 ; st < refsize; st++) {
+                  for(unsigned int kt = 0 ; kt < transforef[st].size(); kt++) {
+                    pds += transforef[st][kt]*transfo0[kt];
+                  }
+                  if(pds!=0) break; 
+                }
+                if(pds>=0) {
+                  //printf("direction ok : %d %d %d (%d)\n",transfo0[0],transfo0[1],transfo0[2],transforef.size()); 
+                  if(pds==0) {/*on rajoute une direction privilegiee*/
+                    transforef.push_back(transfo0);
+                    refsize++;       
+                    //printf("on rajoute la direction au ref : %d \n",refsize);
+                  }   
+                  find = 1;
+                  int move = 1;  
+                  EN_attachDataInt((pEntity) p0 ,tagMove, move);
+                  EN_attachDataInt((pEntity) p1 ,tagMove, move);
+                  move = -1;  
+                  EN_attachDataInt((pEntity) pImg0 ,tagMove, move);
+                  EN_attachDataInt((pEntity) pImg1 ,tagMove, move);
+    
+                  /*on garde les deux points img*/
+                  pFix0 = pImg0;
+                  pFix1 = pImg1;
+                  /*rajout de la transfo avec laquelle bouger les points*/
+                  for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+                    vectnod.push_back(transfo0[kt]);         
+                  }
+                  EN_attachDataPtr((pEntity) p0 , tagTransfo,new std::vector<int>(vectnod)); 
+                  EN_attachDataPtr((pEntity) p1 , tagTransfo,new std::vector<int>(vectnod)); 	
+                } else {/*la direction est opposee a celle souhaitee --> on fait l'inverse*/
+                  //printf("bad direction : %d %d %d (%d %d)\n",transfo0[0],transfo0[1],transfo0[2],transforef.size(),refsize);    
+                  /*****INUTILE ????????******/
+                  int moveI0;
+                  int isMI0 = EN_getDataInt((pEntity) p0 ,tagMove, &moveI0);
+                  int moveI1;
+                  int isMI1 = EN_getDataInt((pEntity) p1 ,tagMove, &moveI1);
+                  if (isMI0 && (moveI0==1) ) break;  	  
+                  if (isMI1 && (moveI1==1) ) break;     	  
+                  if(!(!isMI0 || (moveI0 == -2))) break;     
+                  if(!(!isMI0 || (moveI0 == -2))) break;  
+                  /*****FIN INUTILE ????????******/
+                  find = 1;
+                  int move = -1;  
+                  EN_attachDataInt((pEntity) p0 ,tagMove, move);
+                  EN_attachDataInt((pEntity) p1 ,tagMove, move);
+                  move = 1;  
+                  EN_attachDataInt((pEntity) pImg0 ,tagMove, move);
+                  EN_attachDataInt((pEntity) pImg1 ,tagMove, move);
+
+                  /*on garde les deux points img*/
+                  pFix0 = p0;
+                  pFix1 = p1;
+                  /*rajout de la transfo avec laquelle bouger les points*/
+                  for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+                    vectnod.push_back((-1)*transfo0[kt]);         
+                  }
+                  EN_attachDataPtr((pEntity) pImg0 , tagTransfo,new std::vector<int>(vectnod)); 
+                  EN_attachDataPtr((pEntity) pImg1 , tagTransfo,new std::vector<int>(vectnod)); 	
+                }  
+              }  /*end if direct*/        
+              break;
+            } else {
+              /*si le point bouge deja, on veut pas chger sa destination!!!*/
+              int moveI0;
+              int isMI0 = EN_getDataInt((pEntity) pImg0 ,tagMove, &moveI0);
+              int moveI1;
+              int isMI1 = EN_getDataInt((pEntity) pImg1 ,tagMove, &moveI1);
+              if (isMI0 && (moveI0==1) ) continue;   	  
+              if (isMI1 && (moveI1==1) ) continue;   	  
+          
+              int move = 1; 
+              EN_attachDataInt((pEntity) pImg0 ,tagMove, move);
+              EN_attachDataInt((pEntity) pImg1 ,tagMove, move); 
+          
+              /*on sait que pImg0pImg1 doit aller sur pFix0pFix1 il faut trouver la transfo*/
+              /*si PFix0==p0   transfo = -transfo0*/ 
+              /*sinon          transfo = -transfo0 + vecnod  */
+              std::vector<int> vecttrans;
+              if(pFix0==p0) {
+                for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+                  vecttrans.push_back(-transfo0[kt]);
+                }			
+              } else {
+                for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+                  vecttrans.push_back(-transfo0[kt]);
+                }
+                for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+                  vecttrans[kt] += vectnod[kt];
+                }			
+              }     
+              EN_attachDataPtr((pEntity) pImg0 , tagTransfo,new std::vector<int>(vecttrans)); 
+              EN_attachDataPtr((pEntity) pImg1 , tagTransfo,new std::vector<int>(vecttrans)); 		      
+              break;			
+            }	    
+          } /*end j1*/
+          if(j1==(*recup1).size()){
+            //printf("arete not found\n");
+            /* int move = -2;  
+               EN_attachDataInt((pEntity) pImg0 ,tagMove, move);  */  	  
+          }
+        } /*end j*/	  
+  	  //if(!find) {printf("on n'a pas trouve d'arete img donc on tag pas\n");       exit(0);}
+      } else {/*if direct*/
+	
+      }    
+    }       
+    return;
+  }
+
+
+  // -------------------------------------------------------------------
+  /*boucle sur les aretes pour traiter les cas 3-periodic*/
+  void VertexTagMove(pMesh mesh,pMeshDataId tagMove,pMeshDataId tagTransfo) {
+    pMeshDataId tagPeriodic     = MD_lookupMeshDataId("PeriodicPoint");
+
+    EIter eit = M_edgeIter(mesh);
+    pEdge ped,pedla;  
+    double lenla = 0;
+    while ((ped = EIter_next(eit))) { 
+      /*les deux sommets de l'arete ped*/
+      pVertex p0 = E_vertex(ped,0);
+      pVertex p1 = E_vertex(ped,1);
+
+      /*sommets periodics ?*/
+      void *temp_ptr0; 
+      int isP0 = EN_getDataPtr((pEntity) p0 , tagPeriodic, &temp_ptr0);
+      if(!isP0) continue;
+      void *temp_ptr1; 
+      int isP1 = EN_getDataPtr((pEntity) p1 , tagPeriodic, &temp_ptr1);
+      if(!isP1) continue; 
+
+      double len = (p0->X-p1->X)*(p0->X-p1->X) + (p0->Y-p1->Y)*(p0->Y-p1->Y) +(p0->Z-p1->Z)*(p0->Z-p1->Z);
+      if(len > lenla) {
+        lenla = len;
+        pedla = ped;
+      }
+
+    }               
+    //printf("lenla %e %p : %d %d\n",lenla,pedla,EN_id((pEntity) E_vertex(pedla,0)),EN_id((pEntity) E_vertex(pedla,1)));
+    EIter_delete(eit);  
+    eit = M_edgeIter(mesh);  
+    while ((ped = EIter_next(eit))) { 
+      if(ped!=pedla) continue;
+      /*les deux sommets de l'arete ped*/
+      pVertex p0 = E_vertex(ped,0);
+      pVertex p1 = E_vertex(ped,1);
+      pVertex pFix0,pFix1;
+      std::vector<int> vectnod;
+      int find = 0; 	
+      /*sommets periodics ?*/
+      void *temp_ptr0; 
+      int isP0 = EN_getDataPtr((pEntity) p0 , tagPeriodic, &temp_ptr0);
+      if(!isP0) continue;
+      void *temp_ptr1; 
+      int isP1 = EN_getDataPtr((pEntity) p1 , tagPeriodic, &temp_ptr1);
+      if(!isP1) continue; 
+      /*sommets deja tagges ?*/
+      int move0;
+      int isM0 = EN_getDataInt((pEntity) p0 ,tagMove, &move0);
+      if(!(!isM0 || (move0 == -2))) continue;	  
+      int move1;
+      int isM1 = EN_getDataInt((pEntity) p1 ,tagMove, &move1);
+      if(!(!isM1 || (move1 == -2))) continue;	  
+
+      //printf("treat edge %d %d\n",EN_id((pEntity) p0),EN_id((pEntity) p1));    
+      std::vector<std::pair<std::vector<int> , pVertex> > *recup0 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr0;
+      std::vector<std::pair<std::vector<int> , pVertex> > *recup1 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr1;
+
+      unsigned int j=0;
+      for(j=0 ; j<(*recup0).size() ; j++) {
+        std::vector<int> transfo0 = (*recup0)[j].first;
+        pVertex pImg0 = (*recup0)[j].second;
+        if(pImg0==p1) continue; 
+        unsigned int j1;
+        for(j1=0 ; j1<(*recup1).size() ; j1++) {
+          std::vector<int> transfo1 = (*recup1)[j1].first;
+          pVertex pImg1 = (*recup1)[j1].second;
+          if(pImg1==p0) continue;  
+
+          /*transfo0 == transfo1 ?*/
+          assert(transfo1.size()==transfo0.size());
+          unsigned int kt = 0;
+          for(kt = 0 ; kt < transfo0.size(); kt++) {
+            if(transfo0[kt] != transfo1[kt]) break;
+          }
+          if(kt!=transfo0.size()) continue; 
+          /* pImg1-pImg0 existe ?*/
+          if ( !E_exist(pImg0,pImg1) && !E_exist(pImg1,pImg0) ) continue;
+          /* a-t-on deja trouve une arete img ?*/
+          //printf("img edge %d %d\n",EN_id((pEntity) pImg0),EN_id((pEntity) pImg1));    
+          if(!find) {
+            /*si le point img bouge, on bouge pas!*/
+            int moveI0;
+            int isMI0 = EN_getDataInt((pEntity) pImg0 ,tagMove, &moveI0);
+            int moveI1;
+            int isMI1 = EN_getDataInt((pEntity) pImg1 ,tagMove, &moveI1);
+            if (isMI0 && (moveI0==1) ) continue;   	  
+            if (isMI1 && (moveI1==1) ) continue;   	  
+            find = 1;
+            int move = 1;  
+            EN_attachDataInt((pEntity) p0 ,tagMove, move);
+            EN_attachDataInt((pEntity) p1 ,tagMove, move);
+            move = -1;  
+            EN_attachDataInt((pEntity) pImg0 ,tagMove, move);
+            EN_attachDataInt((pEntity) pImg1 ,tagMove, move);
+
+            /*on garde les deux points img*/
+            pFix0 = pImg0;
+            pFix1 = pImg1;
+
+            /*rajout de la transfo avec laquelle bouger les points*/
+            for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+              vectnod.push_back(transfo0[kt]);
+            }
+            EN_attachDataPtr((pEntity) p0 , tagTransfo,new std::vector<int>(vectnod)); 
+            EN_attachDataPtr((pEntity) p1 , tagTransfo,new std::vector<int>(vectnod)); 		      
+            //printf("mark vertex : %d %d -- %d %d\n",EN_id((pEntity) p0),EN_id((pEntity) p1),EN_id((pEntity) pImg0),EN_id((pEntity) pImg1));
+            //printf("transfo : %d %d %d\n",transfo0[0],transfo0[1],transfo0[2]);
+            break;
+          } else {
+            /*si le point bouge deja, on veut pas chger sa destination!!!*/
+            int moveI0;
+            int isMI0 = EN_getDataInt((pEntity) pImg0 ,tagMove, &moveI0);
+            int moveI1;
+            int isMI1 = EN_getDataInt((pEntity) pImg1 ,tagMove, &moveI1);
+            if (isMI0 && (moveI0==1) ) continue;   	  
+            if (isMI1 && (moveI1==1) ) continue;   	  
+
+            int move = 1; 
+            EN_attachDataInt((pEntity) pImg0 ,tagMove, move);
+            EN_attachDataInt((pEntity) pImg1 ,tagMove, move); 
+
+            /*on sait que pImg0pImg1 doit aller sur pFix0pFix1 il faut trouver la transfo*/ 
+            /*transfo = -transfo0 + vecnod  */
+            std::vector<int> vecttrans;
+            for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+              vecttrans.push_back(-transfo0[kt]);
+            }
+            for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+              vecttrans[kt] += vectnod[kt];
+            }
+            //printf("on applique la transfo %d %d %d\n",vecttrans[0],vecttrans[1],vecttrans[2]);
+            //printf("mark vertex : %d %d \n",EN_id((pEntity) pImg0),EN_id((pEntity) pImg1));
+            EN_attachDataPtr((pEntity) pImg0 , tagTransfo,new std::vector<int>(vecttrans)); 
+            EN_attachDataPtr((pEntity) pImg1 , tagTransfo,new std::vector<int>(vecttrans)); 		      
+            break;			
+          }	    
+        } /*end j1*/
+        if(j1==(*recup1).size()){
+          //printf("arete not found\n");
+          /* int move = -2;  
+             EN_attachDataInt((pEntity) pImg0 ,tagMove, move);  */  	  
+        }
+      } /*end j*/	  
+	//if(!find) {printf("on n'a pas trouve d'arete img donc on tag pas\n");       exit(0);}
+    }  
+    EIter_delete(eit);  
+    eit = M_edgeIter(mesh);
+    while ((ped = EIter_next(eit))) { 
+      /*les deux sommets de l'arete ped*/
+      pVertex p0 = E_vertex(ped,0);
+      pVertex p1 = E_vertex(ped,1);
+      pVertex pFix0,pFix1;
+      std::vector<int> vectnod;
+      int find = 0;
+
+      /*sommets periodics ?*/
+      void *temp_ptr0; 
+      int isP0 = EN_getDataPtr((pEntity) p0 , tagPeriodic, &temp_ptr0);
+      if(!isP0) continue;
+      void *temp_ptr1; 
+      int isP1 = EN_getDataPtr((pEntity) p1 , tagPeriodic, &temp_ptr1);
+      if(!isP1) continue; 
+      /*sommets deja tagges ?*/
+      int move0;
+      int isM0 = EN_getDataInt((pEntity) p0 ,tagMove, &move0);
+      if(!(!isM0 || (move0 == -2))) continue;	  
+      int move1;
+      int isM1 = EN_getDataInt((pEntity) p1 ,tagMove, &move1);
+      if(!(!isM1 || (move1 == -2))) continue;	  
+
+      //printf("treat edge %d %d\n",EN_id((pEntity) p0),EN_id((pEntity) p1));    
+      std::vector<std::pair<std::vector<int> , pVertex> > *recup0 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr0;
+      std::vector<std::pair<std::vector<int> , pVertex> > *recup1 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr1;
+      unsigned int j=0;
+      for(j=0 ; j<(*recup0).size() ; j++) {
+        std::vector<int> transfo0 = (*recup0)[j].first;
+        pVertex pImg0 = (*recup0)[j].second;
+        if(pImg0==p1) continue; 
+        unsigned int j1;
+        for(j1=0 ; j1<(*recup1).size() ; j1++) {
+          std::vector<int> transfo1 = (*recup1)[j1].first;
+          pVertex pImg1 = (*recup1)[j1].second;
+          if(pImg1==p0) continue;  
+
+          /*transfo0 == transfo1 ?*/
+          assert(transfo1.size()==transfo0.size());
+          unsigned int kt = 0;
+          for(kt = 0 ; kt < transfo0.size(); kt++) {
+            if(transfo0[kt] != transfo1[kt]) break;
+          }
+          if(kt!=transfo0.size()) continue; 
+          /* pImg1-pImg0 existe ?*/
+          if ( !E_exist(pImg0,pImg1) && !E_exist(pImg1,pImg0) ) continue;
+          /* a-t-on deja trouve une arete img ?*/
+          //printf("img edge %d %d\n",EN_id((pEntity) pImg0),EN_id((pEntity) pImg1));    
+          if(!find) {
+            /*si le point img bouge, on bouge pas!*/
+            int moveI0;
+            int isMI0 = EN_getDataInt((pEntity) pImg0 ,tagMove, &moveI0);
+            int moveI1;
+            int isMI1 = EN_getDataInt((pEntity) pImg1 ,tagMove, &moveI1);
+            if (isMI0 && (moveI0==1) ) continue;   	  
+            if (isMI1 && (moveI1==1) ) continue;   	  
+            find = 1;
+            int move = 1;  
+            EN_attachDataInt((pEntity) p0 ,tagMove, move);
+            EN_attachDataInt((pEntity) p1 ,tagMove, move);
+            move = -1;  
+            EN_attachDataInt((pEntity) pImg0 ,tagMove, move);
+            EN_attachDataInt((pEntity) pImg1 ,tagMove, move);
+
+            /*on garde les deux points img*/
+            pFix0 = pImg0;
+            pFix1 = pImg1;
+
+            /*rajout de la transfo avec laquelle bouger les points*/
+            for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+              vectnod.push_back(transfo0[kt]);
+            }
+            EN_attachDataPtr((pEntity) p0 , tagTransfo,new std::vector<int>(vectnod)); 
+            EN_attachDataPtr((pEntity) p1 , tagTransfo,new std::vector<int>(vectnod)); 		      
+            //printf("mark vertex : %d %d -- %d %d\n",EN_id((pEntity) p0),EN_id((pEntity) p1),EN_id((pEntity) pImg0),EN_id((pEntity) pImg1));
+            break;
+          } else {
+            /*si le point bouge deja, on veut pas chger sa destination!!!*/
+            int moveI0;
+            int isMI0 = EN_getDataInt((pEntity) pImg0 ,tagMove, &moveI0);
+            int moveI1;
+            int isMI1 = EN_getDataInt((pEntity) pImg1 ,tagMove, &moveI1);
+            if (isMI0 && (moveI0==1) ) continue;   	  
+            if (isMI1 && (moveI1==1) ) continue;   	  
+            int move = 1; 
+            EN_attachDataInt((pEntity) pImg0 ,tagMove, move);
+            EN_attachDataInt((pEntity) pImg1 ,tagMove, move); 
+
+            /*on sait que pImg0pImg1 doit aller sur pFix0pFix1 il faut trouver la transfo*/ 
+            /*transfo = -transfo0 + vecnod  */
+            std::vector<int> vecttrans;
+            for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+              vecttrans.push_back(-transfo0[kt]);
+            }
+            for(unsigned int kt = 0 ; kt < transfo0.size(); kt++) {
+              vecttrans[kt] += vectnod[kt];
+            }
+            //printf("on applique la transfo %d %d %d\n",vecttrans[0],vecttrans[1],vecttrans[2]);
+            //printf("mark vertex : %d %d \n",EN_id((pEntity) pImg0),EN_id((pEntity) pImg1));
+            EN_attachDataPtr((pEntity) pImg0 , tagTransfo,new std::vector<int>(vecttrans)); 
+            EN_attachDataPtr((pEntity) pImg1 , tagTransfo,new std::vector<int>(vecttrans)); 		      
+            break;			
+          }	    
+        } /*end j1*/
+        if(j1==(*recup1).size()){
+          //printf("arete not found\n");
+          /* int move = -2;  
+             EN_attachDataInt((pEntity) pImg0 ,tagMove, move);  */  	  
+        }
+      } /*end j*/	  
+	//if(!find) {printf("on n'a pas trouve d'arete img donc on tag pas\n");       exit(0);}
+    }  
+    EIter_delete(eit);
+    return;
+  }
+
+  // -------------------------------------------------------------------
+  void VertexTagMove_old(pMesh mesh,pMeshDataId tagMove,int imove) {
+    pMeshDataId tagPeriodic     = MD_lookupMeshDataId("PeriodicPoint");
+
+    VIter vit = M_vertexIter(mesh);
+    pVertex pv;  
+    while ((pv = VIter_next(vit))) {
+      void *temp_ptr; 
+      int isPeriodic = EN_getDataPtr((pEntity) pv , tagPeriodic, &temp_ptr);
+      if(isPeriodic) {
+        /*****************************************************************************/
+        /********nouvelle facon de bouger (sans pbs pour les tri-periodicite)*********/
+        /*****************************************************************************/
+        int move;
+        int isMove = EN_getDataInt((pEntity) pv ,tagMove, &move);
+        if((isMove && move==-1) || (isMove && move==1)) continue;	  
+        /*****************************************************************************/
+        /*****************************************************************************/
+        std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+        move = -1;
+        unsigned int j=0;
+        for(j=0 ; j<(*recup).size() ; j++) {
+          std::vector<int> transfo = (*recup)[j].first;
+          /*****************************************************************************/
+          /********************ancienne facon*******************************************/
+          /*****************************************************************************/		
+          /*unsigned int k=0;
+            for(k = 0 ; k<transfo.size() ; k++) {
+            if(transfo[k]< 0) break;	
+            }                    
+            if(k==transfo.size()) move=1;*/  
+          /*****************************************************************************/
+		    
+          /*on bouge que par rapport à x*/
+	  /*  int somme = 0;
+              for(int kk = 0 ; kk<transfo.size() ; kk++) {  
+              //if(kk==imove) continue;
+              somme +=  abs(transfo[kk] );
+              }
+              int inv = (imove>=0) ? 1 : -1;
+              if(inv < 0) imove = abs(imove)-1; 
+              for(k = imove ; k<imove+1 ; k++) {
+              if((transfo[k] == 0) || (inv * transfo[k] < 0)) break;	
+              }                 
+              if(k==imove+1 && somme < 2) move=1;   */  
+          /*****************************************************************************/
+          /********nouvelle facon de bouger (sans pbs pour les tri-periodicite)*********/
+          /*****************************************************************************/
+          pVertex pImg = (*recup)[j].second;
+          int movimg;
+          int isM = EN_getDataInt((pEntity) pImg ,tagMove, &movimg);
+          if(isM && movimg==1) continue;
+    
+          /*unsigned int k=0;
+	    for(k = 0 ; k<transfo.size() ; k++) {
+            if(transfo[k]< 0) break;	
+            }                    
+            if(k==transfo.size()) {
+            move=1;
+            break;
+            } */
+          move=1;
+          break;
+          /*****************************************************************************/
+          /*****************************************************************************/
+        }
+        /*****************************************************************************/
+        /********nouvelle facon de bouger (sans pbs pour les tri-periodicite)*********/
+        /*****************************************************************************/
+        if(move==1) {    
+          //printf("on traite le point %d -> %d: j = %d / %d\n",EN_id((pEntity) pv),EN_id((pEntity) (*recup)[j].second),j,(*recup).size());
+          unsigned int j2=0;
+          for(j2=0 ; j2<(*recup).size() ; j2++) {
+            std::vector<int> transfo = (*recup)[j2].first;
+            pVertex pImg = (*recup)[j2].second;
+            if(j2==j) {  
+              int movimg;
+              int isM = EN_getDataInt((pEntity) pImg ,tagMove, &movimg);    
+              assert(!isM || (isM && movimg==-1) || (isM && movimg==-2));   
+              movimg = -1;
+              if(!isM)  EN_attachDataInt((pEntity) pImg ,tagMove, movimg);    
+              continue;
+            }
+            /*le point pImg doit bouger sur le meme point que pv*/
+            int movimg;
+            int isM = EN_getDataInt((pEntity) pImg ,tagMove, &movimg); 
+            if(!(!isM || (isM && movimg==-2) || (isM && movimg==1))) printf("point %d : %d %d\n",EN_id((pEntity) pImg),isM,movimg);   
+            assert(!isM || (isM && movimg==-2) || (isM && movimg==1)); 
+            movimg = 1;
+            if(!isM)  EN_attachDataInt((pEntity) pImg ,tagMove, movimg);    
+            // GCRMK: remove this part
+            /****verifier que (*recup)[j].second existe dans les img de pImg*/
+            pVertex pcheck = (*recup)[j].second;
+            void *temp_ptrimg; 
+            int isP = EN_getDataPtr((pEntity) pImg , tagPeriodic, &temp_ptrimg);
+            assert(isP);
+            std::vector<std::pair<std::vector<int> , pVertex> > *recupimg = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptrimg;
+            unsigned int j3=0;
+            for(j3=0 ; j3<(*recupimg).size() ; j3++) {
+              pVertex pI2 = (*recup)[j3].second;
+              if(pI2==pcheck) break;
+            }
+            assert(j3!=(*recupimg).size()); 
+            /****end check*/
+          }
+        } else {
+          move=-2;  
+        }
+        /*****************************************************************************/
+        /*****************************************************************************/
+        //printf("on traite le point %d : %d\n",EN_id((pEntity) pv),move);
+        EN_attachDataInt((pEntity) pv ,tagMove, move);
+      }
+    }  
+    VIter_delete(vit);  
+
+    return;
+  }
+
+  // -------------------------------------------------------------------
+  void VertexTagMoveInverse(pMesh mesh,pMeshDataId tagMove) {
+    pMeshDataId tagPeriodic     = MD_lookupMeshDataId("PeriodicPoint");
+
+    VIter vit = M_vertexIter(mesh);
+    pVertex pv;  
+    while ((pv = VIter_next(vit))) {
+      void *temp_ptr; 
+      int isPeriodic = EN_getDataPtr((pEntity) pv , tagPeriodic, &temp_ptr);
+      if(isPeriodic) {
+        std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+        int move = -1;
+        for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+          std::vector<int> transfo = (*recup)[j].first;
+          unsigned int k=0;
+          for(k = 0 ; k<transfo.size() ; k++) {
+            if(pv->X > 1) printf("%e %e %d\n",pv->X,pv->Y,transfo[k]);
+            if(transfo[k] >= -1) break;
+            //if((transfo[k] >= 0) || (transfo[k] >= -1 && transfo[k] <= 1)) break;	
+            printf("tr %d\n",transfo[k]);
+          }
+          if(k==transfo.size()) move=1;
+        }
+        EN_attachDataInt((pEntity) pv ,tagMove, move);
+      }
+    }  
+    VIter_delete(vit);  
+
+    return;
+  }
+
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  void MarkPeriodicTets(pMesh mesh,std::vector<std::vector<int> >& transfo,
+                        pMeshDataId tagElt,pMeshDataId tagMove,pMeshDataId tagTransfo) {
+  
+    /* 1) define if periodic vertex can move : 1 : yes / -1 : no*/
+    VertexTagMoveList(mesh,transfo,tagMove,tagTransfo);   
+    /*ancienne version*/
+    //VertexTagMove_old(mesh,tagMove,1);
+  
+    /* 2) marked tetras and vertex*/
+    RIter rit = M_regionIter(mesh);
+    pRegion pr;  
+    while ((pr = RIter_next(rit))) {
+      pVertex nod[4];
+      pr->getNodes(nod);  
+      int dest = 0;
+      for(int i=0 ; i<4 ; i++) {
+        int move; 
+        int isPeriodic = EN_getDataInt((pEntity) nod[i] , tagMove, &move);  
+        //GCRMK: remove this check
+        if(isPeriodic && move==-2) printf("point %d argggg \n",EN_id((pEntity) nod[i])) ;
+        if(isPeriodic) assert(move!=-2);
+        if(isPeriodic && (move==1)) {
+          dest = 1;	
+        }
+      }
+      if(dest) EN_attachDataInt((pEntity) pr ,tagElt, dest);
+    }  
+    RIter_delete(rit);  
+
+  }
+
+
+  // -------------------------------------------------------------------
+  int MarkGroupPeriodicTets(pMesh mesh,pMeshDataId tagElt,pMeshDataId tagMove) {
+  
+    int mark = 0;
+  
+    /* 1) define if periodic vertex can move : 1 : yes / -1 : no*/
+    VertexTagMoveInverse(mesh,tagMove);
+  
+    /* 2) marked tetras and vertex*/
+    RIter rit = M_regionIter(mesh);
+    pRegion pr;  
+    while ((pr = RIter_next(rit))) {
+      pVertex nod[4];
+      pr->getNodes(nod);  
+      int dest = 0;
+      for(int i=0 ; i<4 ; i++) {
+        int move; 
+        int isPeriodic = EN_getDataInt((pEntity) nod[i] , tagMove, &move);
+        if(isPeriodic && (move==1)) {
+ 	  dest = 1;	
+        }
+      }
+      if(dest) {
+        EN_attachDataInt((pEntity) pr ,tagElt, dest);
+        mark++;
+      }
+    }  
+    RIter_delete(rit); 
+    return mark; 
+
+  }
+
+  // -------------------------------------------------------------------
+  void MarkPeriodicTriangles(pMesh mesh,std::vector<std::vector<int> >& transfo,pMeshDataId tagElt,pMeshDataId tagMove,pMeshDataId tagTransfo) {
+
+
+    /* 1) define if periodic vertex can move : 1 : yes / -1 : no*/
+    //VertexTagMove(mesh,tagMove,tagTransfo);
+    VertexTagMoveList(mesh,transfo,tagMove,tagTransfo);
+  
+    /* 2) marked faces and vertex*/
+    FIter fit = M_faceIter(mesh);
+    pFace pface;  
+    while ((pface = FIter_next(fit))) {
+      pVertex nod[3];
+      pface->getNodes(nod);  
+      int dest = 0;
+      for(int i=0 ; i<3 ; i++) {
+        int move; 
+        int isPeriodic = EN_getDataInt((pEntity) nod[i] , tagMove, &move);
+        if(isPeriodic && (move==1)) {
+ 	  dest = 1;	
+        }
+      }
+      if(dest) EN_attachDataInt((pEntity) pface ,tagElt, dest);
+    }  
+    FIter_delete(fit);
+  }
+
+  // -------------------------------------------------------------------
+
+}
+
diff --git a/Mesh/Mark.h b/Mesh/Mark.h
new file mode 100644
index 0000000..0b3f6e7
--- /dev/null
+++ b/Mesh/Mark.h
@@ -0,0 +1,51 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _MARK_H_
+#define _MARK_H_
+
+#include "MSops.h"
+
+#include <vector>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+#ifdef PARALLEL
+  void MarkTriangles       (pMesh mesh, pMeshDataId tagElt);
+  void MarkTrianglesSmooth (pMesh mesh, pMeshDataId tagElt);
+  void MarkTrianglesRandom (pMesh mesh, pMeshDataId tagElt);
+  void MarkTets            (pMesh mesh, pMeshDataId tagElt);
+  void MarkTetsSmooth      (pMesh mesh, pMeshDataId tagElt);
+  void MarkTetsRandom      (pMesh mesh, pMeshDataId tagElt);
+  int  MarkTetsManifold    (pMesh mesh, pMeshDataId tagElt);
+#endif
+
+  // -------------------------------------------------------------------
+  void VertexTagMove         (pMesh mesh, pMeshDataId tagMove);
+  void VertexTagMoveList     (pMesh mesh, std::vector<std::vector<int> >& transfo,
+                              pMeshDataId tagMove, pMeshDataId tagTransfo);
+  void VertexTagMoveInverse  (pMesh mesh, pMeshDataId tagMove);
+
+  // -------------------------------------------------------------------
+  void MarkPeriodicTriangles (pMesh mesh, std::vector<std::vector<int> >& transfo,
+                              pMeshDataId tagElt, pMeshDataId tagMove, pMeshDataId tagTransfo);
+  void MarkPeriodicTets      (pMesh mesh, std::vector<std::vector<int> >& transfo,
+                              pMeshDataId tagElt, pMeshDataId tagMove, pMeshDataId tagTransfo);
+  int  MarkGroupPeriodicTets (pMesh mesh, pMeshDataId tagElt, pMeshDataId tagMove);
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Mesh/MeshDataBase.cc b/Mesh/MeshDataBase.cc
new file mode 100644
index 0000000..839d1d2
--- /dev/null
+++ b/Mesh/MeshDataBase.cc
@@ -0,0 +1,2144 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere, Koen Hillewaert
+// -------------------------------------------------------------------
+
+#include "MeshDataBase.h"
+#include "MeshDataBaseGEntity2Physical.h"
+#include "MSops.h"
+#include "MeshDataBaseMessage.h"
+#include "MAdMessage.h"
+#include "MAdDefines.h"
+#include "MathUtils.h"
+
+#include <set>
+using std::set;
+using std::cout;
+
+#ifdef PARALLEL
+#include "mpi.h"
+#endif
+
+namespace MAd {
+
+  MDB_Mesh::MDB_Mesh (int _MAXX)
+    :  parametric(false), shrinked(false), maxId(_MAXX), idIncrement(1),
+       nbPoints(0), nbEdges(0), nbTriangles(0), nbQuads(0), nbTets(0), 
+       nbHexes(0), nbPrisms(0)
+  {
+    initializeIdData();
+  }
+
+  void MDB_Mesh::initializeIdData( )
+  {
+#ifdef PARALLEL
+    int myRank = 0, nbProc = 0;
+    MPI_Comm_size(MPI_COMM_WORLD, &nbProc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
+
+    int maxIdGlob = -1;
+    MPI_Allreduce(&maxId,&maxIdGlob,1,MPI_INT,MPI_MAX,MPI_COMM_WORLD);
+    maxId = maxIdGlob + myRank;
+    idIncrement = nbProc;
+    MPI_Barrier(MPI_COMM_WORLD);
+#else
+    idIncrement = 1;
+#endif
+  }
+
+  void MDB_Mesh::deleteTheHighOrderPoint(std::set < MDB_Point *, PointLessThan >::iterator it){
+    MDB_Point *pt;
+    if (it != points.end())
+      {
+        pt = *it;
+        points.erase(it);
+        nbPoints--;
+      }
+    else throw;
+  }
+
+  void MDB_Point::getTriangles(MDB_ListF&t) const
+  {
+    t.clear();
+    MDB_VectorE::const_iterator it = edges.begin();
+    MDB_VectorE::const_iterator ite = edges.end();
+    while(it != ite) {
+      int NF = (*it)->numfaces();
+      for(int i = 0; i < NF; ++i) {
+        MDB_Triangle *tt = (*it)->faces(i);
+        if(tt) {
+          MDB_ListF::iterator tit = t.begin();
+          MDB_ListF::iterator tite = t.end();
+          int found = 0;
+          while(tit != tite) {
+            if(tt == *tit)
+              found = 1;
+            ++tit;
+          }
+          if(!found)
+            t.push_back(tt);
+        }
+      }
+      ++it;
+    }
+  }
+
+  void MDB_Point::getQuads(MDB_ListQ&q) const
+  {
+    q.clear();
+    MDB_VectorE::const_iterator it = edges.begin();
+    MDB_VectorE::const_iterator ite = edges.end();
+    while(it != ite) {
+      int NF = (*it)->numquads();
+      for(int i = 0; i < NF; ++i) {
+        MDB_Quad *qq = (*it)->quads(i);
+        if(qq) {
+          MDB_ListQ::iterator qit = q.begin();
+          MDB_ListQ::iterator qite = q.end();
+          int found = 0;
+          while(qit != qite) {
+            if(qq == *qit)
+              found = 1;
+            ++qit;
+          }
+          if(!found)
+            q.push_back(qq);
+        }
+      }
+      ++it;
+    }
+  }
+
+
+  MDB_Point * MDB_Mesh::add_point(int num, double x, double y, double z, pGEntity pg)
+  {
+    int newId = num;
+    if ( newId < 0 ) {
+      maxId += idIncrement;
+      newId = maxId;
+    }
+
+    MDB_Point *pp = new MDB_Point(newId, x, y, z);
+    pp->g = pg;
+    points.insert(pp);
+    maxId = (maxId < newId) ? newId : maxId;
+    nbPoints++;
+    return pp;
+  }
+
+  MDB_PointParam * MDB_Mesh::add_pointParam(int num , double x, double y, double z, 
+                                            double u, double v, pGEntity pg)
+  {
+    int newId = num;
+    if ( newId < 0 ) {
+      maxId += idIncrement;
+      newId = maxId;
+    }
+
+    MDB_PointParam *pp = new MDB_PointParam(newId, x, y, z, u, v);
+    pp->g = pg;
+    points.insert(pp);
+    maxId = (maxId < newId) ? newId : maxId;
+    nbPoints++;
+    parametric = true;
+    return pp;
+  }
+
+  MDB_Point *MDB_Mesh::find_point(int p)
+  {
+    MDB_Point P(p);
+    std::set < MDB_Point *, PointLessThan >::iterator it = points.find(&P);
+    if(it != points.end()) return (MDB_Point *) (*it);
+    return 0;
+
+    //   MDB_PointParam VP(p);
+    //   it = points.find(&VP);
+    //   if(it != points.end()) return (MDB_Point *) (*it);
+    //   else return 0;
+  }
+
+  MDB_Edge *MDB_Mesh::find_edge(int num1, int num2)
+  {
+    MDB_Point *p = find_point(num1);
+    MDB_VectorE::iterator eit = p->edges.begin();
+    while(eit != p->edges.end()) {
+      if((*eit)->p1 == p && (*eit)->p2->iD == num2)
+        return (*eit);
+      if((*eit)->p2 == p && (*eit)->p1->iD == num2)
+        return (*eit);
+      ++eit;
+    }
+    return 0;
+  }
+
+  MDB_Edge *MDB_Mesh::find_edge(MDB_Point * p1, MDB_Point * p2) const
+  {
+    const int nbe1 = p1->edges.size();
+    const int nbe2 = p2->edges.size();
+    if (nbe1 < nbe2)
+      {
+        for (int i=0;i<nbe1;i++)
+          {
+            MDB_Edge *e = p1->edges [i];
+            if (e->p1 == p1 && e->p2 == p2)return e;
+            if (e->p2 == p1 && e->p1 == p2)return e;
+          }
+      }
+    else
+      {
+        for (int i=0;i<nbe2;i++)
+          {
+            MDB_Edge *e = p2->edges [i];
+            if (e->p1 == p1 && e->p2 == p2)return e;
+            if (e->p2 == p1 && e->p1 == p2)return e;
+          }
+      }
+    return 0;
+  }
+
+
+  MDB_Edge *MDB_Mesh::find_edge(MDB_Point * p1, MDB_Point * p2,
+                                MDB_Triangle * t) const
+  {
+    if((t->e1->p1->iD == p1->iD && t->e1->p2->iD == p2->iD) ||
+       (t->e1->p1->iD == p2->iD && t->e1->p2->iD == p1->iD))
+      return t->e1;
+    if((t->e2->p1->iD == p1->iD && t->e2->p2->iD == p2->iD) ||
+       (t->e2->p1->iD == p2->iD && t->e2->p2->iD == p1->iD))
+      return t->e2;
+    if((t->e3->p1->iD == p1->iD && t->e3->p2->iD == p2->iD)||
+       (t->e3->p1->iD == p2->iD && t->e3->p2->iD == p1->iD))
+      return t->e3;
+    return 0;
+  }
+
+  MDB_Edge *MDB_Mesh::find_clone_edge(MDB_Edge * edge) const
+  {
+    double xyz[3];
+    double eXYZ[2][3];
+    MDB_Point * P = edge->p1;
+    eXYZ[0][0] = P->X; eXYZ[0][1] = P->Y; eXYZ[0][2] = P->Z;
+    P = edge->p2;
+    eXYZ[1][0] = P->X; eXYZ[1][1] = P->Y; eXYZ[1][2] = P->Z;
+    
+    MDB_ListE::const_iterator eit = edges.begin();
+    for(; eit != edges.end(); ++eit) {
+
+      if ( (*eit) == edge ) continue; 
+
+      P = (*eit)->p1;
+      xyz[0] = P->X; xyz[1] = P->Y; xyz[2] = P->Z;
+      if ( distanceSq(xyz,eXYZ[0]) < MAdTOL ) {
+        P = (*eit)->p2;
+        xyz[0] = P->X; xyz[1] = P->Y; xyz[2] = P->Z;
+        if ( distanceSq(xyz,eXYZ[1]) < MAdTOL ) {
+          return (*eit);
+        }
+      }
+
+      P = (*eit)->p2;
+      xyz[0] = P->X; xyz[1] = P->Y; xyz[2] = P->Z;
+      if ( distanceSq(xyz,eXYZ[0]) < MAdTOL ) {
+        P = (*eit)->p1;
+        xyz[0] = P->X; xyz[1] = P->Y; xyz[2] = P->Z;
+        if ( distanceSq(xyz,eXYZ[1]) < MAdTOL ) {
+          return (*eit);
+        }
+      }
+    }
+    return NULL;
+  }
+
+  MDB_Triangle *MDB_Mesh::find_triangle(MDB_Edge * e1, MDB_Edge * e2,
+                                        MDB_Edge * e3)
+  {
+    int i;
+    for(i = 0; i < e1->numfaces(); i++) {
+      MDB_Triangle *t = e1->faces(i);
+      MDB_Edge *o1 = t->e1;
+      MDB_Edge *o2 = t->e2;
+      MDB_Edge *o3 = t->e3;
+      if((o1 == e1 && o2 == e2 && o3 == e3) ||
+         (o1 == e1 && o2 == e3 && o3 == e2) ||
+         (o1 == e2 && o2 == e1 && o3 == e3) ||
+         (o1 == e2 && o2 == e3 && o3 == e1) ||
+         (o1 == e3 && o2 == e1 && o3 == e2) ||
+         (o1 == e3 && o2 == e2 && o3 == e1))
+        return t;
+    }
+
+    return 0;
+  }
+
+
+  MDB_Quad *MDB_Mesh::find_quad(MDB_Edge * e1, MDB_Edge * e2,
+                                MDB_Edge * e3, MDB_Edge * e4)
+  {
+    MDB_Edge *eds[4] = {e1,e2,e3,e4};
+    std::sort(eds,eds+4);
+    for(int i = 0; i < e1->numquads(); i++) {
+      MDB_Quad *q = e1->quads(i);
+      MDB_Edge *edsb[4] = {q->e1,q->e2,q->e3,q->e4};
+      std::sort(edsb,edsb+4);
+      if (edsb[0] == eds[0] && edsb[1] == eds[1] && edsb[2] == eds[2] && edsb[3] == eds[3])
+        return q;
+    }
+    return 0;
+  }
+
+  MDB_Edge *MDB_Mesh::add_edge(int p1, int p2, pGEntity pg)
+  {
+    MDB_Edge *efound = find_edge(p1, p2);
+    if(efound)
+      {
+        if (efound->g == 0 || ( pg && GEN_type(pg) <  GEN_type(efound->g )))
+          {
+            efound->g = pg;
+          }
+        return efound;
+      }
+
+    MDB_Point *pp1 = find_point(p1);
+    MDB_Point *pp2 = find_point(p2);
+    if(!pp1 || !pp2)
+      throw;
+    return add_edge (pp1,pp2,pg);
+  }
+
+  /*MDB_Edge *MDB_Mesh::add_edge(int p1, int p2, int p3, pGEntity pg)
+    {
+    MDB_Edge *efound = find_edge(p1, p3);
+
+    if(efound)
+    return efound;
+    MDB_Point *pp1 = find_point(p1);
+    MDB_Point *pp2 = find_point(p2);
+    MDB_Point *pp3 = find_point(p3);
+
+    if(!pp1 || !pp2 || !pp3)
+    throw;
+    return add_edge (pp1,pp2,pp3,pg);
+    }*/
+
+  MDB_Edge *MDB_Mesh::add_edge(int numberOfPoints, pGEntity pg, int p1, ...)
+  {
+    va_list ap;
+    // va_start(ap,numberOfPoints);
+    va_start(ap,p1);
+
+    int p2=0;int p3=0;int p4=0;int p5=0;
+    if (numberOfPoints>=3){
+      p2 = va_arg(ap,int);
+      if (numberOfPoints>=4){
+        p3 = va_arg(ap,int);
+        if (numberOfPoints>=5){
+          p4 = va_arg(ap,int);
+          if (numberOfPoints>=6){
+            p5 = va_arg(ap,int);
+          }
+        }
+      }
+    }
+    int pend = va_arg(ap,int);
+    va_end(ap);
+
+    MDB_Edge *efound = find_edge(p1, pend);
+
+    if(efound)
+      return efound;
+    MDB_Point *pp1 = find_point(p1);
+    MDB_Point *pp2=NULL;
+    MDB_Point *pp3=NULL;
+    MDB_Point *pp4=NULL;
+    MDB_Point *pp5=NULL;// = find_point(p2);
+    MDB_Point *ppend = find_point(pend);
+    switch(numberOfPoints){
+    case 3:
+      pp2 = find_point(p2);
+      assert(pp1 && pp2 && ppend);
+      return add_edge (3,pg,pp1,pp2,ppend);
+    case 4:
+      pp2 = find_point(p2);
+      pp3 = find_point(p3);
+      assert(pp1 && pp2 && pp3 && ppend);
+      return add_edge (4,pg,pp1,pp2,pp3,ppend);
+    case 5:
+      pp2 = find_point(p2);
+      pp3 = find_point(p3);
+      pp4 = find_point(p4);
+      assert(pp1 && pp2 && pp3 && pp4 && ppend);
+      return add_edge (5,pg,pp1,pp2,pp3,pp4,ppend);
+    case 6:
+      pp2 = find_point(p2);
+      pp3 = find_point(p3);
+      pp4 = find_point(p4);
+      pp5 = find_point(p5);
+      assert(pp1 && pp2 && pp3 && pp4 && pp5 && ppend);
+      return add_edge (6,pg,pp1,pp2,pp3,pp4,pp5,ppend);
+    default:
+      Msg(MDB_FATAL,"add_edge only implemented up to order 5 (this edge has %d nodes)\n",numberOfPoints);
+    }
+    throw;
+  }
+
+  MDB_Edge *MDB_Mesh::add_edge(MDB_Point *pp1 , MDB_Point *pp2, pGEntity pg)
+  {
+    MDB_Edge *e = new MDB_Edge(pp1, pp2);
+    e->g = pg;
+    edges.push_back(e);
+    nbEdges++;
+    return e;
+  }
+
+  MDB_Edge *MDB_Mesh::add_edge(MDB_Point* pp1,MDB_Point *pp2,pGEntity pg,int order,MDB_Point** pp)
+  {
+    //   int numberOfPoints = order + 1;
+
+    MDB_Edge *e = NULL;
+    switch(order){
+    case 1:
+      e = new MDB_Edge(pp1,pp2);
+      break;
+    case 2:
+      e = new MDB_EdgeP2(pp1, pp[0], pp2);
+      break;
+    case 3:
+      e = new MDB_EdgeP3(pp1, pp[0], pp[1], pp2);
+      break;
+    case 4:
+      e = new MDB_EdgeP4(pp1, pp[0], pp[1], pp[2], pp2);
+      break;
+    case 5:
+      e = new MDB_EdgeP5(pp1, pp[0], pp[1], pp[2], pp[3] , pp2);
+      break;
+    default:
+      Msg(MDB_FATAL,"add_edge only implemented up to order 5\n");
+    }
+    e->g = pg;
+
+    for (int i=0;i<order-1;i++) {
+      if (pp[i]->g == NULL) pp[i]->g = pg;
+      std::set < MDB_Point *, PointLessThan >::iterator it = points.find(pp[i]);
+      deleteTheHighOrderPoint(it);
+    }
+
+    edges .push_back(e);
+    nbEdges++;
+    return e;
+  }
+
+
+
+  MDB_Edge *MDB_Mesh::add_edge(int numberOfPoints, pGEntity pg, MDB_Point *firstPoint, ...)
+  {
+    va_list ap;
+    // va_start(ap,numberOfPoints);
+    va_start(ap,firstPoint);
+
+    MDB_Point *pp2 = NULL;
+    MDB_Point *pp3 = NULL;
+    MDB_Point *pp4 = NULL;
+    MDB_Point *pp5 = NULL;
+
+    if (numberOfPoints>=3){
+      pp2 = va_arg(ap,MDB_Point*);
+      if (numberOfPoints>=4){
+        pp3 = va_arg(ap,MDB_Point*);
+        if (numberOfPoints>=5){
+          pp4 = va_arg(ap,MDB_Point*);
+          if (numberOfPoints>=6){
+            pp5 = va_arg(ap,MDB_Point*);
+          }
+        }
+      }
+    }
+    MDB_Point *ppend = va_arg(ap,MDB_Point*);
+    va_end(ap);
+
+    MDB_Edge *e = NULL;
+    switch(numberOfPoints){
+    case 2:
+      break;
+    case 3:
+      e = new MDB_EdgeP2(firstPoint, pp2, ppend);
+      break;
+    case 4:
+      e = new MDB_EdgeP3(firstPoint, pp2, pp3, ppend);
+      break;
+    case 5:
+      e = new MDB_EdgeP4(firstPoint, pp2, pp3, pp4, ppend);
+      break;
+    case 6:
+      e = new MDB_EdgeP5(firstPoint, pp2, pp3, pp4, pp5, ppend);
+      break;
+    default:
+      Msg(MDB_FATAL,"add_edge only implemented up to order 5\n");
+    }
+    e->g = pg;
+    edges.push_back(e);
+    nbEdges++;
+
+    if (numberOfPoints==2) return e;
+
+    std::set < MDB_Point *, PointLessThan >::iterator it1 = points.find(pp2);
+    deleteTheHighOrderPoint(it1);
+
+    std::set < MDB_Point *, PointLessThan >::iterator it2;
+    std::set < MDB_Point *, PointLessThan >::iterator it3;
+    std::set < MDB_Point *, PointLessThan >::iterator it4;
+    switch(numberOfPoints){
+    case 4:
+      it2 = points.find(pp3);
+      deleteTheHighOrderPoint(it2);
+      break;
+    case 5:
+      it2 = points.find(pp3);
+      it3 = points.find(pp4);
+      deleteTheHighOrderPoint(it2);
+      deleteTheHighOrderPoint(it3);
+      break;
+    case 6:
+      it2 = points.find(pp3);
+      it3 = points.find(pp4);
+      it4 = points.find(pp5);
+      deleteTheHighOrderPoint(it2);
+      deleteTheHighOrderPoint(it3);
+      deleteTheHighOrderPoint(it4);
+      break;
+    }
+    return e;
+  }
+
+  /*MDB_Edge *MDB_Mesh::add_edge(MDB_Point *pp1 , MDB_Point *pp2, MDB_Point *pp3, pGEntity pg)
+    {
+    MDB_Edge *e = new MDB_EdgeP2(pp1, pp2,pp3);
+    e->g = pg;
+    edges.push_back(e);
+    nbEdges++;
+
+    std::set < MDB_Point *, PointLessThan >::iterator it = points.find(pp2);
+    MDB_Point *pt;
+    if (it != points.end())
+    {
+    pt = *it;
+    points.erase(it);
+    nbPoints--;
+    }
+    else throw;
+    return e;
+    }*/
+
+  MDB_Triangle *MDB_Mesh::add_triangle(int p1, int p2, int p3, pGEntity pg)
+  {
+    MDB_Edge *e1 = add_edge(p1, p2);
+    MDB_Edge *e2 = add_edge(p2, p3);
+    MDB_Edge *e3 = add_edge(p3, p1);
+
+
+    MDB_Triangle *efound = find_triangle(e1, e2, e3);
+    if(efound)
+      {
+        if (efound->g == 0 || ( pg && GEN_type(pg) <  GEN_type(efound->g )))
+          {
+            efound->g = pg;
+          }
+        return efound;
+      }
+
+    return add_triangle(e1, e2, e3,pg);
+  }
+
+  /*MDB_Triangle *MDB_Mesh::add_triangle(int numberOfPoints, pGEntity pg, int p1, int p2, ...)
+    {
+    va_list ap;
+    // va_start(ap,numberOfPoints);
+    va_start(ap,p2);
+    int p3=0;int p4=0;int p5=0;
+    int p6=0;int p7=0;int p8=0;int p9=0;
+    int p10=0;int p11=0;int p12=0;int p13=0;
+    int p14=0;int p15=0;
+    if (numberOfPoints>=6){
+    p3 = va_arg(ap,int);
+    p4 = va_arg(ap,int);
+    p5 = va_arg(ap,int);
+    p6 = va_arg(ap,int);
+    if (numberOfPoints>=9){
+    p7 = va_arg(ap,int);
+    p8 = va_arg(ap,int);
+    p9 = va_arg(ap,int);
+    if (numberOfPoints>=12){
+    p10 = va_arg(ap,int);
+    p11 = va_arg(ap,int);
+    p12 = va_arg(ap,int);
+    if (numberOfPoints>=15){
+    p13 = va_arg(ap,int);
+    p14 = va_arg(ap,int);
+    p15 = va_arg(ap,int);
+    }
+    }
+    }
+    }
+    va_end(ap);
+
+    MDB_Edge *e1,*e2,*e3;
+    switch(numberOfPoints){
+    case 3:
+    e1 = add_edge(2,0,p1, p2);
+    e2 = add_edge(2,0,p2, p3);
+    e3 = add_edge(2,0,p3, p1);
+    break;
+    case 6:
+    e1 = add_edge(3,0,p1, p2, p3);
+    e2 = add_edge(3,0,p3, p4, p5);
+    e3 = add_edge(3,0,p5, p6, p1);
+    break;
+    case 9:
+    e1 = add_edge(4,0,p1, p2, p3, p4);
+    e2 = add_edge(4,0,p4, p5, p6, p7);
+    e3 = add_edge(4,0,p7, p8, p9, p1);
+    break;
+    case 12:
+    e1 = add_edge(5,0,p1, p2, p3, p4, p5);
+    e2 = add_edge(5,0,p5, p6, p7, p8, p9);
+    e3 = add_edge(5,0,p9, p10,p11,p12,p1);
+    break;
+    case 15:
+    e1 = add_edge(6,0,p1, p2, p3, p4, p5, p6);
+    e2 = add_edge(6,0,p6, p7, p8, p9, p10,p11);
+    e3 = add_edge(6,0,p11,p12,p13,p14,p15,p1);
+    break;
+    }
+
+    MDB_Triangle *efound = find_triangle(e1, e2, e3);
+    if(efound)
+    {
+    if (efound->g == 0 || ( pg && GEN_type(pg) <  GEN_type(efound->g )))
+    {
+    efound->g = pg;
+    }
+    return efound;
+    }
+    return add_triangle(e1, e2, e3,pg);
+    }*/
+
+  // high order triangle ...
+  // template is the following v0 ho[v0->v1] v1 ho[v1->v2] v2 ho[v2->v0]
+  MDB_Triangle *MDB_Mesh::add_triangle(int order, bool complete, pGEntity pg, int p1, int p2, ...)
+  {
+    // int numberOfPoints = complete ? (order+2)*(order+1)/2 : 3*order;
+    va_list ap;
+    // va_start(ap,numberOfPoints);
+    va_start(ap,p2);
+    int p3=0;int p4=0;int p5=0;
+    int p6=0;int p7=0;int p8=0;int p9=0;
+    int p10=0;int p11=0;int p12=0;int p13=0;
+    int p14=0;int p15=0;
+    if (order>=2){
+      p3 = va_arg(ap,int);
+      p4 = va_arg(ap,int);
+      p5 = va_arg(ap,int);
+      p6 = va_arg(ap,int);
+      if (order>=3){
+        p7 = va_arg(ap,int);
+        p8 = va_arg(ap,int);
+        p9 = va_arg(ap,int);
+        if (order>=4){
+          p10 = va_arg(ap,int);
+          p11 = va_arg(ap,int);
+          p12 = va_arg(ap,int);
+          if (order>=5){
+            p13 = va_arg(ap,int);
+            p14 = va_arg(ap,int);
+            p15 = va_arg(ap,int);
+          }
+        }
+      }
+    }
+    if (complete && order>2){
+      switch(order){
+      case 3:
+        p10 = va_arg(ap,int);
+        break;
+      case 4:
+        p13 = va_arg(ap,int);
+        p14 = va_arg(ap,int);
+        p15 = va_arg(ap,int);
+        break;
+      default:
+        Msg(MDB_FATAL,"Complete triangles not defined for order %d\n",order);
+      }
+    }
+    va_end(ap);
+
+    MDB_Edge *e1 = NULL;
+    MDB_Edge *e2 = NULL;
+    MDB_Edge *e3 = NULL;
+
+    switch(order){
+    case 1:
+      e1 = add_edge(2,0,p1, p2);
+      e2 = add_edge(2,0,p2, p3);
+      e3 = add_edge(2,0,p3, p1);
+      break;
+    case 2:
+      e1 = add_edge(3,0,p1, p2, p3);
+      e2 = add_edge(3,0,p3, p4, p5);
+      e3 = add_edge(3,0,p5, p6, p1);
+      break;
+    case 3:
+      e1 = add_edge(4,0,p1, p2, p3, p4);
+      e2 = add_edge(4,0,p4, p5, p6, p7);
+      e3 = add_edge(4,0,p7, p8, p9, p1);
+      break;
+    case 4:
+      e1 = add_edge(5,0,p1, p2, p3, p4, p5);
+      e2 = add_edge(5,0,p5, p6, p7, p8, p9);
+      e3 = add_edge(5,0,p9, p10,p11,p12,p1);
+      break;
+    case 5:
+      e1 = add_edge(6,0,p1, p2, p3, p4, p5, p6);
+      e2 = add_edge(6,0,p6, p7, p8, p9, p10,p11);
+      e3 = add_edge(6,0,p11,p12,p13,p14,p15,p1);
+      break;
+    }
+    MDB_Point** innerPoints = NULL;
+    if (complete && order>2){
+      int nbFacePoints = (order-1) * (order-2)/2;
+      innerPoints = new MDB_Point*[nbFacePoints];
+      switch (order){
+      case 3:
+        innerPoints[0] = find_point(p10);
+        break;
+      case 4:
+        innerPoints[0] = find_point(p13);
+        innerPoints[1] = find_point(p14);
+        innerPoints[2] = find_point(p15);
+        break;
+      default:
+        Msg(MDB_FATAL,"Complete triangles not defined for order %d\n",order);
+      }
+    }
+
+    MDB_Triangle *efound = find_triangle(e1, e2, e3);
+    if(efound)
+      {
+        if (efound->g == 0 || ( pg && GEN_type(pg) <  GEN_type(efound->g )))
+          {
+            efound->g = pg;
+          }
+        return efound;
+      }
+    return add_triangle(e1,e2,e3,pg,order,!complete,innerPoints);
+    //return add_triangle(e1, e2, e3,pg);
+  }
+
+  // template for higher order triangle, following gmsh template
+  // v0 v1 v2
+  // higher order points
+  // edges  loop following edge direction E0(V0-V1) E1(V1->V2) E2(V2->V0)
+  // face   loop (eta(ksi)), ksi=e0, eta=-e2
+
+  /*MDB_Triangle *MDB_Mesh::add_triangle(pGEntity pg,int order,bool serendip,int* p) {
+
+
+  int nbEdgePoints = (order-1);
+  int nbFacePoints = (order+1) * (order+2)/2 - (serendip ? std::max(0,(order-2)*(order-1)/2) : 0);
+
+  MDB_Point** point = new MDB_Point*[nbFacePoints];
+
+  for (int i=0;i<nbFacePoints;i++) point[i] = find_point(p[i]);
+
+  MDB_Point** pp = point + 3;
+
+  // create edges
+
+  MDB_Edge* e1 = add_edge(point[0],point[1],pg,order,pp);
+  pp += nbEdgePoints;
+
+  MDB_Edge* e2 = add_edge(point[1],point[2],pg,order,pp);
+  pp += nbEdgePoints;
+
+  MDB_Edge* e3 = add_edge(point[2],point[0],pg,order,pp);
+  pp += nbEdgePoints;
+
+  //
+
+  return add_triangle(e1,e2,e3,pg,order,serendip,pp);
+  }*/
+
+  MDB_Triangle *MDB_Mesh::add_triangle(MDB_Edge * e1, MDB_Edge * e2,
+                                       MDB_Edge * e3, pGEntity pg)
+  {
+    MDB_Triangle *t = new MDB_Triangle(e1, e2, e3);
+    t->g = pg;
+    triangles.push_back(t);
+    nbTriangles++;
+    return t;
+  }
+
+  MDB_Triangle *MDB_Mesh::add_triangle(MDB_Edge *e1,MDB_Edge* e2,
+                                       MDB_Edge *e3,pGEntity pg,
+                                       int order,bool serendip,
+                                       MDB_Point** point) {
+
+
+
+
+    MDB_Triangle *t = NULL;
+    if (serendip || order <= 2) t = new MDB_Triangle(e1,e2,e3);
+    else {
+      switch (order) {
+
+      case 3:
+        t = new MDB_CompleteTriangle<3>(e1,e2,e3,point);
+        break;
+      case 4:
+        t = new MDB_CompleteTriangle<4>(e1,e2,e3,point);
+        break;
+        /*    case 5:
+              t = new MDB_CompleteTriangle<5>(e1,e2,e3,point);
+              break;*/
+      default:
+        Msg(MDB_FATAL,"Complete triangle of order %d\n",order);
+      }
+
+      int nbPoints = (order-2)*(order-1)/2;
+
+      for (int i=0;i<nbPoints;i++) {
+        std::set<MDB_Point*,PointLessThan>::iterator it = points.find(point[i]);
+        deleteTheHighOrderPoint(it);
+      }
+    }
+
+    if (t) {
+      t->g = pg;
+      triangles.push_back(t);
+      nbTriangles++;
+    }
+    return t;
+  }
+
+
+
+  MDB_Quad *MDB_Mesh::add_quad(int p1, int p2, int p3, int p4, pGEntity pg)
+  {
+    MDB_Edge *e1 = add_edge(p1, p2);
+    MDB_Edge *e2 = add_edge(p2, p3);
+    MDB_Edge *e3 = add_edge(p3, p4);
+    MDB_Edge *e4 = add_edge(p4, p1);
+
+    MDB_Quad *efound = find_quad(e1, e2, e3, e4);
+    if(efound)
+      {
+        if (efound->g == 0 || ( pg && GEN_type(pg) <  GEN_type(efound->g )))
+          {
+            efound->g = pg;
+          }
+        return efound;
+      }
+
+    return add_quad(e1, e2, e3, e4,pg);
+  }
+
+  MDB_Quad *MDB_Mesh::add_quad(MDB_Edge * e1, MDB_Edge * e2,
+                               MDB_Edge * e3, MDB_Edge * e4, pGEntity pg)
+  {
+    MDB_Quad *q = new MDB_Quad(e1, e2, e3, e4);
+    q->g = pg;
+    quads.push_back(q);
+    nbQuads++;
+    return q;
+  }
+
+
+  static double VOLUME ( MDB_Tet *t )
+  {
+    pVertex v1 = R_vertex (t,0);
+    pVertex v2 = R_vertex (t,1);
+    pVertex v3 = R_vertex (t,2);
+    pVertex v4 = R_vertex (t,3);
+
+    double v12[3] = { v2->X - v1->X,  v2->Y - v1->Y,  v2->Z - v1->Z};
+    double v13[3] = { v3->X - v1->X,  v3->Y - v1->Y,  v3->Z - v1->Z};
+    double v14[3] = { v4->X - v1->X,  v4->Y - v1->Y,  v4->Z - v1->Z};
+
+    double pv[3] = { v12[1]*v13[2]-v12[2]*v13[1],
+                     v12[2]*v13[0]-v12[0]*v13[2],
+                     v12[0]*v13[1]-v12[1]*v13[0]};
+    double v =
+      pv[0] * v14[0]
+      + pv[1] * v14[1]
+      + pv[2] * v14[2];
+
+    return v/6;
+  }
+
+  static double VOLUME ( MDB_Hex *h )
+  {
+    pVertex v1 = R_vertex (h,0);
+    pVertex v2 = R_vertex (h,1);
+    pVertex v3 = R_vertex (h,2);
+    pVertex v4 = R_vertex (h,3);
+    pVertex v5 = R_vertex (h,4);
+    pVertex v6 = R_vertex (h,5);
+    pVertex v7 = R_vertex (h,6);
+    pVertex v8 = R_vertex (h,7);
+
+    double v21[3] = { v1->X - v2->X,  v1->Y - v2->Y,  v1->Z - v2->Z};
+    double v23[3] = { v3->X - v2->X,  v3->Y - v2->Y,  v3->Z - v2->Z};
+    double v24[3] = { v4->X - v2->X,  v4->Y - v2->Y,  v4->Z - v2->Z};
+    double v25[3] = { v5->X - v2->X,  v5->Y - v2->Y,  v5->Z - v2->Z};
+    double v26[3] = { v6->X - v2->X,  v6->Y - v2->Y,  v6->Z - v2->Z};
+    double v27[3] = { v7->X - v2->X,  v7->Y - v2->Y,  v7->Z - v2->Z};
+    double v28[3] = { v8->X - v2->X,  v8->Y - v2->Y,  v8->Z - v2->Z};
+
+    double pv248[3] = { v24[1]*v28[2]-v24[2]*v28[1], v24[2]*v28[0]-v24[0]*v28[2], v24[0]*v28[1]-v24[1]*v28[0]};
+    double pv258[3] = { v25[1]*v28[2]-v25[2]*v28[1], v25[2]*v28[0]-v25[0]*v28[2], v25[0]*v28[1]-v25[1]*v28[0]};
+    double pv278[3] = { v27[1]*v28[2]-v27[2]*v28[1], v27[2]*v28[0]-v27[0]*v28[2], v27[0]*v28[1]-v27[1]*v28[0]};
+
+    double vo1 = pv248[0] * v21[0] + pv248[1] * v21[1] + pv248[2] * v21[2];
+    double vo2 = pv258[0] * v21[0] + pv258[1] * v21[1] + pv258[2] * v21[2];
+    double vo3 = pv258[0] * v26[0] + pv258[1] * v26[1] + pv258[2] * v26[2];
+    double vo4 = pv248[0] * v23[0] + pv248[1] * v23[1] + pv248[2] * v23[2];
+    double vo5 = pv278[0] * v23[0] + pv278[1] * v23[1] + pv278[2] * v23[2];
+    double vo6 = pv278[0] * v26[0] + pv278[1] * v26[1] + pv278[2] * v26[2];
+
+    //NP The volume of hex was 0, I think there is an error in the tet volume formula.
+    //   I fix the problem by changing the following line.
+    //   return (vo1+vo2+vo3+vo4+vo5+vo6)/6;
+    return (-vo1+vo2-vo3+vo4-vo5+vo6)/6;
+  }
+
+
+  // -----------------------------------------------------------------------------
+  // template tet
+  // -----------------------------------------------------------------------------
+  //
+  // gmsh template
+  // V0 V1 V2 V3
+  // higher order points
+  //
+  // edges:
+  // ------
+  //
+  //   E0 : V0 V1
+  //   E1 : V1 V2
+  //   E2 : V2 V0
+  //   E3 : V0 V3
+  //   E5 : V2 V3
+  //   E4 : V1 V3
+  //
+  // faces:
+  // ------
+  //
+  // loop (eta(ksi)), ksi e0 (v0-v1) , eta -e2 (v0-v2)
+  // orientation such that rotation axis points inward
+  // face starts at vertex with corresponding index
+  //
+  //      |  e0  e1  e2 | v0 v1 v2 |
+  //   -----------------------------
+  //   F0 | +E0 +E1 +E2 | V0 V1 V2 |
+  //   F1 | -E0 +E3 -E4 | V1 V0 V3 |
+  //   F2 | +E5 -E3 -E2 | V2 V3 V0 |
+  //   F3 | -E5 -E1 +E4 | V3 V2 V1 |
+  //
+  //
+  // volume:
+  // -------
+  //
+  // loop (zeta(eta(ksi))), ksi (V0-V1), eta (V0-V2), zeta (V0-V3)
+  //
+  // -----------------------------------------------------------------------------
+
+
+
+  MDB_Tet *MDB_Mesh::add_tet(pGEntity pg,int order,bool serendip,int* pointID) {
+
+    int nbEdgePoints = order > 1 ? order - 1 : 0;
+    int nbFacePoints = order > 2 ? (order-2)*(order-1)/2 : 0;
+    int nbVolPoints = ((serendip || order < 4) ? 0 : (order-3)*(order-2)*(order-1)/6);
+
+    int nb = 4 + 6 * nbEdgePoints +  4 * nbFacePoints + nbVolPoints;
+
+    MDB_Point** point = new MDB_Point*[nb];
+    for (int i=0;i<nb;i++) point[i] = find_point(pointID[i]);
+
+    MDB_Point** pp = point + 4;
+
+    // create edges
+    // to be tested : ordering of higher order nodes ...
+
+    MDB_Edge *e1 = find_edge(point[0],point[1]);
+    if (!e1) e1 = add_edge(point[0], point[1],pg,order,pp);
+    pp += nbEdgePoints;
+
+    MDB_Edge *e2 = find_edge(point[1],point[2]);
+    if (!e2) e2 = add_edge(point[1], point[2],pg,order,pp);
+    pp += nbEdgePoints;
+
+    MDB_Edge *e3 = find_edge(point[2],point[0]);
+    if (!e3) e3 = add_edge(point[2], point[0],pg,order,pp);
+    pp += nbEdgePoints;
+
+    // KH: edges 4,5 and 6 have opposite orientation in gmsh
+
+    MDB_Edge *e4 = find_edge(point[0],point[3]);
+    if (!e4) e4 = add_edge(point[3], point[0],pg,order,pp);
+    pp += nbEdgePoints;
+
+    // KH: edges 5 and 6 switched wrt gmsh, opposite direction
+
+    MDB_Edge *e6 = find_edge(point[2],point[3]);
+    if (!e6) e6 = add_edge(point[3], point[2],pg,order,pp);
+    pp += nbEdgePoints;
+
+    MDB_Edge *e5 = find_edge(point[1],point[3]);
+    if (!e5) e5 = add_edge(point[3], point[1],pg,order,pp);
+    pp += nbEdgePoints;
+
+    // create faces - complete
+
+    // face 1 is face 1 in Gmsh, the latter is oriented as v0-v2-v1
+
+    MDB_Triangle *t1 = find_triangle(e1, e2, e3);
+    // if(!t1) t1 = add_triangle(e1, e2, e3,pg,order,false,pp);
+    if(!t1) t1 = add_triangle(e3, e2, e1,pg,order,false,pp);
+    pp += nbFacePoints;
+
+    // face 2 is the same as in Gmsh
+
+    MDB_Triangle *t2 = find_triangle(e1, e4, e5);
+    if(!t2) t2 = add_triangle(e1, e5, e4,pg,order,false,pp);
+    pp += nbFacePoints;
+
+    // face 4 is face 3 in gmsh, the latter is oriented as v0-v3-v2
+
+    MDB_Triangle *t4 = find_triangle(e3, e4, e6);
+    // if(!t4)t4 = add_triangle (e3, e4, e6,pg,order,false,pp);
+    if(!t4) t4 = add_triangle (e4, e6, e3,pg,order,false,pp);
+    pp += nbFacePoints;
+
+    // face 3 in mdb is  face 4 in gmsh, the latter is oriented as v3-v1-v2
+
+    MDB_Triangle *t3 = find_triangle(e2, e6, e5);
+    // if(!t3) t3 = add_triangle(e2, e6, e5,pg,order,false,pp);
+    if(!t3) t3 = add_triangle(e5, e2, e6,pg,order,false,pp);
+    pp += nbFacePoints;
+
+    // create tets
+
+    MDB_Tet* t = serendip ? add_tet(t1,t2,t3,t4,pg) : add_tet(t1,t2,t3,t4,pg,order,serendip,pp);
+
+    // clean up
+
+    delete [] point;
+    return t;
+  }
+
+
+
+
+  MDB_Tet *MDB_Mesh::add_tet(MDB_Triangle *t1,MDB_Triangle *t2,
+                             MDB_Triangle *t3,MDB_Triangle *t4,
+                             pGEntity pg,int order,bool serendip,MDB_Point** pp) {
+
+
+    MDB_Tet* t = NULL;
+
+    if (serendip || order <= 2)  {
+      t = new MDB_Tet(t1,t2,t3,t4);
+    }
+    else {
+      switch (order){
+
+      case 3:
+        t = new MDB_CompleteTet<3> (t1,t2,t3,t4,pp);
+        break;
+      case 4:
+        t = new MDB_CompleteTet<4> (t1,t2,t3,t4,pp);
+        break;
+      case 5:
+        t = new MDB_CompleteTet<5> (t1,t2,t3,t4,pp);
+        break;
+      default:
+        Msg(MDB_FATAL,"Complete tetrahedron of order %d not yet implemented ",order);
+        break;
+      }
+
+      int nbPoints = std::max(0,(order-3)*(order-2)*(order-1)/6);
+
+      for (int i=0;i<nbPoints;i++) {
+        std::set<MDB_Point*,PointLessThan>::iterator it = points.find(pp[i]);
+        deleteTheHighOrderPoint(it);
+      }
+    }
+
+    if (t) {
+      t->g = pg;
+      tets.push_back(t);
+      nbTets++;
+    }
+    return t;
+  }
+
+
+  MDB_Tet *MDB_Mesh::add_tet(MDB_Triangle *t1,
+                             MDB_Triangle *t2,
+                             MDB_Triangle *t3,
+                             MDB_Triangle *t4,
+                             pGEntity pg)
+  {
+    MDB_Tet *t = new MDB_Tet(t1, t2, t3, t4);
+
+    double v = VOLUME (t);
+    if (v < 0)
+      {
+        t->f1 = t2;
+        t->f2 = t1;
+        //      v = VOLUME (t);
+        //      if (v < 0)
+        //	throw;
+      }
+
+    t->g = pg;
+    tets.push_back(t);
+    nbTets++;
+    return t;
+  }
+
+  MDB_Tet *MDB_Mesh::add_tet(int p1, int p2, int p3, int p4, pGEntity pg)
+  {
+    MDB_Edge *e1 = add_edge(p1, p2);
+    MDB_Edge *e2 = add_edge(p2, p3);
+    MDB_Edge *e3 = add_edge(p3, p1);
+    MDB_Edge *e4 = add_edge(p1, p4);
+    MDB_Edge *e5 = add_edge(p2, p4);
+    MDB_Edge *e6 = add_edge(p3, p4);
+
+    MDB_Triangle *t1 = find_triangle(e1, e2, e3);
+    if(!t1)
+      t1 = add_triangle(e1, e2, e3);
+    MDB_Triangle *t2 = find_triangle(e1, e4, e5);
+    if(!t2)
+      t2 = add_triangle(e1, e4, e5);
+    MDB_Triangle *t3 = find_triangle(e2, e6, e5);
+    if(!t3)
+      t3 = add_triangle(e2, e6, e5);
+    MDB_Triangle *t4 = find_triangle(e3, e4, e6);
+    if(!t4)
+      t4 = add_triangle(e3, e4, e6);
+    return add_tet (t1, t2, t3, t4,pg);
+  }
+
+  MDB_Tet *MDB_Mesh::add_tet(MDB_Point *p1, MDB_Point *p2,MDB_Point *p3, MDB_Point *p4, pGEntity pg)
+  {
+    MDB_Edge *e1 = find_edge(p1,p2);
+    if (!e1) e1 = add_edge(p1, p2, pg);
+    MDB_Edge *e2 = find_edge(p2,p3);
+    if (!e2) e2 = add_edge(p2, p3, pg);
+    MDB_Edge *e3 = find_edge(p3,p1);
+    if (!e3) e3 = add_edge(p3, p1, pg);
+    MDB_Edge *e4 = find_edge(p1,p4);
+    if (!e4) e4 = add_edge(p1, p4, pg);
+    MDB_Edge *e5 = find_edge(p2,p4);
+    if (!e5) e5 = add_edge(p2, p4, pg);
+    MDB_Edge *e6 = find_edge(p3,p4);
+    if (!e6) e6 = add_edge(p3, p4, pg);
+
+    MDB_Triangle *t1 = find_triangle(e1, e2, e3);
+    if(!t1)t1 = add_triangle(e1, e2, e3, pg);
+    MDB_Triangle *t2 = find_triangle(e1, e4, e5);
+    if(!t2)t2 = add_triangle(e1, e4, e5, pg);
+    MDB_Triangle *t3 = find_triangle(e2, e6, e5);
+    if(!t3)t3 = add_triangle(e2, e6, e5, pg);
+    MDB_Triangle *t4 = find_triangle(e3, e4, e6);
+    if(!t4)t4 = add_triangle(e3, e4, e6, pg);
+    return add_tet (t1, t2, t3, t4, pg);
+  }
+
+  void MDB_Mesh::del_tet(MDB_Tet * t)
+  {
+    t->f1->del(t);
+    t->f2->del(t);
+    t->f3->del(t);
+    t->f4->del(t);
+    nbTets--;
+    t->deleted = true;
+  }
+
+
+  void MDB_Mesh::del_face(MDB_Face *f)
+  {
+    int nbE = f->getNbEdges();
+    if ( nbE == 3 ) {
+      del_triangle ( dynamic_cast<MDB_Triangle *>(f) ); return;
+    }
+    else if ( nbE == 4 ) {
+      del_quad ( dynamic_cast<MDB_Quad *>(f) ); return;
+    }
+    throw;
+  }
+
+  MDB_Hex *MDB_Mesh::add_hex(MDB_Quad *q1, MDB_Quad *q2, MDB_Quad *q3, MDB_Quad *q4, MDB_Quad *q5, MDB_Quad *q6, pGEntity pg)
+  {
+    MDB_Hex *h= new MDB_Hex(q1, q2, q3, q4, q5, q6);
+
+    double v = VOLUME (h);
+    if (v < 0)
+      {
+        printf("Hexahedron has a negative volume.");
+        throw;
+      }
+
+    h->g = pg;
+    hexes.push_back(h);
+    nbHexes++;
+
+    return h;
+  }
+
+  MDB_Hex *MDB_Mesh::add_hex(int p1, int p2, int p3, int p4,
+                             int p5, int p6, int p7, int p8, pGEntity pg)
+  {
+    MDB_Edge *e1 = add_edge(p1, p2);
+    MDB_Edge *e2 = add_edge(p2, p3);
+    MDB_Edge *e3 = add_edge(p3, p4);
+    MDB_Edge *e4 = add_edge(p4, p1);
+    MDB_Edge *e5 = add_edge(p1, p5);
+    MDB_Edge *e6 = add_edge(p2, p6);
+    MDB_Edge *e7= add_edge(p3, p7);
+    MDB_Edge *e8 = add_edge(p4, p8);
+    MDB_Edge *e9 = add_edge(p5, p6);
+    MDB_Edge *e10 = add_edge(p6, p7);
+    MDB_Edge *e11 = add_edge(p7, p8);
+    MDB_Edge *e12 = add_edge(p8, p5);
+
+    MDB_Quad *q1 = find_quad(e4, e3, e2, e1);
+    if(!q1) q1 = add_quad(e4, e3, e2, e1);
+    MDB_Quad *q2 = find_quad(e1, e6, e9, e5);
+    if(!q2) q2 = add_quad(e1, e6, e9, e5);
+    MDB_Quad *q3 = find_quad(e2, e7, e10, e6);
+    if(!q3) q3 = add_quad(e2, e7, e10, e6);
+    MDB_Quad *q4 = find_quad(e3, e8, e11, e7);
+    if(!q4) q4 = add_quad(e3, e8, e11, e7);
+    MDB_Quad *q5 = find_quad(e4, e5, e12, e8);
+    if(!q5) q5 = add_quad(e4, e5, e12, e8);
+    MDB_Quad *q6 = find_quad(e9, e10, e11, e12);
+    if(!q6) q6 = add_quad(e9, e10, e11, e12);
+    return add_hex (q1, q2, q3, q4, q5, q6, pg);
+  }
+
+  MDB_Hex *MDB_Mesh::add_hex(MDB_Point *p1, MDB_Point *p2,MDB_Point *p3, MDB_Point *p4,
+                             MDB_Point *p5, MDB_Point *p6,MDB_Point *p7, MDB_Point *p8, pGEntity pg)
+  {
+    MDB_Edge *e1 = find_edge(p1,p2);
+    if (!e1) e1 = add_edge(p1, p2);
+    MDB_Edge *e2 = find_edge(p2,p3);
+    if (!e2) e2 = add_edge(p2, p3);
+    MDB_Edge *e3 = find_edge(p3,p4);
+    if (!e3) e3 = add_edge(p3, p4);
+    MDB_Edge *e4 = find_edge(p4,p1);
+    if (!e4) e4 = add_edge(p4, p1);
+    MDB_Edge *e5 = find_edge(p1,p5);
+    if (!e5) e5 = add_edge(p1, p5);
+    MDB_Edge *e6 = find_edge(p2,p6);
+    if (!e6) e6 = add_edge(p2, p6);
+    MDB_Edge *e7 = find_edge(p3,p7);
+    if (!e7) e7 = add_edge(p3, p7);
+    MDB_Edge *e8 = find_edge(p4,p8);
+    if (!e8) e8 = add_edge(p4, p8);
+    MDB_Edge *e9 = find_edge(p5,p6);
+    if (!e9) e9 = add_edge(p5, p6);
+    MDB_Edge *e10 = find_edge(p6,p7);
+    if (!e10) e10 = add_edge(p6, p7);
+    MDB_Edge *e11 = find_edge(p7,p8);
+    if (!e11) e11 = add_edge(p7, p8);
+    MDB_Edge *e12 = find_edge(p8,p5);
+    if (!e12) e12 = add_edge(p8, p5);
+
+    MDB_Quad *q1 = find_quad(e4, e3, e2, e1);
+    if(!q1) q1 = add_quad(e4, e3, e2, e1);
+    MDB_Quad *q2 = find_quad(e1, e6, e9, e5);
+    if(!q2) q2 = add_quad(e1, e6, e9, e5);
+    MDB_Quad *q3 = find_quad(e2, e7, e10, e6);
+    if(!q3) q3 = add_quad(e2, e7, e10, e6);
+    MDB_Quad *q4 = find_quad(e3, e8, e11, e7);
+    if(!q4) q4 = add_quad(e3, e8, e11, e7);
+    MDB_Quad *q5 = find_quad(e4, e5, e12, e8);
+    if(!q5) q5 = add_quad(e4, e5, e12, e8);
+    MDB_Quad *q6 = find_quad(e9, e10, e11, e12);
+    if(!q6) q6 = add_quad(e9, e10, e11, e12);
+    return add_hex (q1, q2, q3, q4, q5, q6, pg);
+  }
+
+
+
+
+  MDB_Prism *MDB_Mesh::add_prism(MDB_Triangle *t1,MDB_Triangle *t2,
+                                 MDB_Quad *t3,MDB_Quad *t4,MDB_Quad *t5, pGEntity pg)
+  {
+    MDB_Prism *p = new MDB_Prism(t1, t2, t3, t4, t5);
+
+    //SL has not implemented the check on volume...
+    //double v = VOLUME (p);
+    //if (v < 0)
+    //  {
+    //   p->f1 = t2;
+    //   p->f2 = t1;
+    //  //      v = VOLUME (p);
+    //  //      if (v < 0)
+    //  //	throw;
+    //  }
+
+    p->g = pg;
+    prisms.push_back(p);
+    nbPrisms++;
+    return p;
+  }
+
+  MDB_Prism *MDB_Mesh::add_prism(int p1, int p2, int p3,
+                                 int p4, int p5, int p6, pGEntity pg)
+  {
+    MDB_Edge *e1 = add_edge(p1, p2);
+    MDB_Edge *e2 = add_edge(p1, p3);
+    MDB_Edge *e3 = add_edge(p2, p3);
+    MDB_Edge *e4 = add_edge(p4, p5);
+    MDB_Edge *e5 = add_edge(p4, p6);
+    MDB_Edge *e6 = add_edge(p5, p6);
+    MDB_Edge *e7= add_edge(p1, p4);
+    MDB_Edge *e8 = add_edge(p2, p5);
+    MDB_Edge *e9 = add_edge(p3, p6);
+
+    MDB_Triangle *q1 = find_triangle(e1, e2, e3);
+    if(!q1)
+      q1 = add_triangle(e1, e2, e3);
+    MDB_Triangle *q2 = find_triangle(e4, e6, e5);
+    if(!q2)
+      q2 = add_triangle(e4, e6, e5);
+    MDB_Quad *q3 = find_quad(e7, e4, e8, e1);
+    if(!q3)
+      q3 = add_quad(e7, e4, e8, e1);
+    MDB_Quad *q4 = find_quad(e8, e6, e9, e3);
+    if(!q4)
+      q4 = add_quad(e8, e6, e9, e3);
+    MDB_Quad *q5 = find_quad(e7, e2, e9, e5);
+    if(!q5)
+      q5 = add_quad(e7, e2, e9, e5);
+    return add_prism (q1, q2, q3, q4, q5, pg);
+  }
+
+  MDB_Prism *MDB_Mesh::add_prism(MDB_Point *p1, MDB_Point *p2,MDB_Point *p3,
+                                 MDB_Point *p4, MDB_Point *p5, MDB_Point *p6, pGEntity pg)
+  {
+    MDB_Edge *e1 = find_edge(p1,p2);
+    if (!e1) e1 = add_edge(p1, p2);
+    MDB_Edge *e2 = find_edge(p1,p3);
+    if (!e2) e2 = add_edge(p1, p3);
+    MDB_Edge *e3 = find_edge(p2,p3);
+    if (!e3) e3 = add_edge(p2, p3);
+    MDB_Edge *e4 = find_edge(p4,p5);
+    if (!e4) e4 = add_edge(p4, p5);
+    MDB_Edge *e5 = find_edge(p4,p6);
+    if (!e5) e5 = add_edge(p4, p6);
+    MDB_Edge *e6 = find_edge(p5,p6);
+    if (!e6) e6 = add_edge(p5, p6);
+    MDB_Edge *e7 = find_edge(p1,p4);
+    if (!e7) e7 = add_edge(p1, p4);
+    MDB_Edge *e8 = find_edge(p2,p5);
+    if (!e8) e8 = add_edge(p2, p5);
+    MDB_Edge *e9 = find_edge(p3,p6);
+    if (!e9) e9 = add_edge(p3, p6);
+
+    MDB_Triangle *q1 = find_triangle(e1, e2, e3);
+    if(!q1) q1 = add_triangle(e1, e2, e3);
+    MDB_Triangle *q2 = find_triangle(e4, e6, e5);
+    if(!q2) q2 = add_triangle(e4, e6, e5);
+    MDB_Quad *q3 = find_quad(e7, e4, e8, e1);
+    if(!q3) q3 = add_quad(e7, e4, e8, e1);
+    MDB_Quad *q4 = find_quad(e8, e6, e9, e3);
+    if(!q4) q4 = add_quad(e8, e6, e9, e3);
+    MDB_Quad *q5 = find_quad(e7, e2, e9, e5);
+    if(!q5) q5 = add_quad(e7, e2, e9, e5);
+    return add_prism (q1, q2, q3, q4, q5, pg);
+  }
+
+  void MDB_Mesh::del_hex(MDB_Hex * h)
+  {
+    h->f1->del(h);
+    h->f2->del(h);
+    h->f3->del(h);
+    h->f4->del(h);
+    h->f5->del(h);
+    h->f6->del(h);
+    nbHexes--;
+    h->deleted = true;
+  }
+
+  void MDB_Mesh::del_prism(MDB_Prism * p)
+  {
+    p->f1->del(p);
+    p->f2->del(p);
+    p->f3->del(p);
+    p->f4->del(p);
+    p->f5->del(p);
+    nbPrisms--;
+    p->deleted = true;
+  }
+
+  void MDB_Mesh::del_triangle(MDB_Triangle * t)
+  {
+    t->e1->del(t);
+    t->e2->del(t);
+    t->e3->del(t);
+    nbTriangles--;
+    t->deleted = true;
+    if (t->getNbRegions())throw;
+  }
+
+  void MDB_Mesh::del_quad(MDB_Quad * q)
+  {
+    q->e1->del(q);
+    q->e2->del(q);
+    q->e3->del(q);
+    q->e4->del(q);
+    nbQuads--;
+    q->deleted = true;
+    if (q->getNbRegions())throw;
+  }
+
+  void MDB_Mesh::del_edge(MDB_Edge * e)
+  {
+    e->p1->del(e);
+    e->p2->del(e);
+    nbEdges--;
+    e->deleted = true;
+
+    if (e->numfaces())throw;
+  }
+
+  void MDB_Mesh::del_point(MDB_Point * p)
+  {
+    if (p->deleted) { 
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "point already deleted");
+    }
+    p->deleted = true;
+    nbPoints--;
+    if (p->edges.size())throw;
+  }
+
+
+  void MDB_Edge::oppositeof(MDB_Point * oface[2]) const
+  {
+    oface[0] = oface[1] = 0;
+    if(faces(0)) {
+      MDB_Point *pts[3];
+      faces(0)->getNodes(pts);
+      if(pts[0] != p1 && pts[0] != p2)
+        oface[0] = pts[0];
+      else if(pts[1] != p1 && pts[1] != p2)
+        oface[0] = pts[1];
+      else
+        oface[0] = pts[2];
+    }
+    if(faces(1)) {
+      MDB_Point *pts[3];
+      faces(1)->getNodes(pts);
+      if(pts[0] != p1 && pts[0] != p2)
+        oface[1] = pts[0];
+      else if(pts[1] != p1 && pts[1] != p2)
+        oface[1] = pts[1];
+      else
+        oface[1] = pts[2];
+    }
+  }
+
+  template < class IT > void DESTROOOY(IT beg, IT end)
+  {
+    while(beg != end) {
+      delete *beg;
+      beg++;
+    }
+  }
+
+  MDB_Mesh ::~ MDB_Mesh ()
+  {
+    DESTROOOY ( points.begin(),points.end());
+    DESTROOOY ( edges.begin(),edges.end());
+    DESTROOOY ( triangles.begin(),triangles.end());
+    DESTROOOY ( quads.begin(),quads.end());
+    DESTROOOY ( tets.begin(),tets.end());
+    DESTROOOY ( hexes.begin(),hexes.end());
+    DESTROOOY ( prisms.begin(),prisms.end());
+  }
+
+  MDB_Edge::~MDB_Edge ()
+  {
+  }
+
+
+  MDB_Mesh::MDB_Mesh(const MDB_Mesh & other)
+  {
+    throw;
+  }
+
+  void MDB_Mesh :: load ( FILE *f )
+  {
+    _load (f);
+    shrinked = true;
+  }
+
+  void MDB_Mesh :: flush ( FILE *f ) const
+  {
+    _flush (f);
+  }
+
+  void MDB_Mesh :: shrink ()
+  {
+    VIter vit  = M_vertexIter ( this );
+    pVertex pv;
+    GEntity2Physical gentity2phys(geomFeatures_Tags);
+    coords = new double[3*nbPoints];
+    ids    = new int   [  nbPoints];
+    int i=0;
+    nbInfos = 0;
+
+    int SIZE_INFO_PT       = 4;
+    int SIZE_INFO_EDGE     = 5;
+    int SIZE_INFO_TRIANGLE = 6;
+    int SIZE_INFO_TET      = 7;
+
+    while ((pv = VIter_next (vit)))
+      {
+        int dim = EN_whatInType(pv);
+        if (dim == 0) nbInfos += SIZE_INFO_PT;
+        ids[i] = pv->iD;
+        pv->iD= i+1;
+        V_coord ( pv, &coords[3*i++]);
+      }
+    nbVertex = nbPoints;
+    EIter eit  = M_edgeIter ( this );
+    pEdge pe;
+    while ((pe = EIter_next (eit)))
+      {
+        int dim = EN_whatInType(pe);
+        if (dim == 1) nbInfos += SIZE_INFO_EDGE;
+      }
+    FIter fit  = M_faceIter ( this );
+    pFace pf;
+    while ((pf = FIter_next (fit)))
+      {
+        int dim = EN_whatInType(pf);
+        if (dim == 2) nbInfos += SIZE_INFO_TRIANGLE;
+      }
+    nbInfos += SIZE_INFO_TET * nbTets;
+
+    infos = new int [nbInfos];
+
+    VIter_reset(vit);
+    EIter_reset(eit);
+    FIter_reset(fit);
+
+    int K = 0;
+
+    while ((pv = VIter_next (vit)))
+      {
+        int dim = EN_whatInType(pv);
+        if (dim == 0)
+          {
+            pGEntity pg = EN_whatIn(pv);
+            int tag = GEN_tag ( pg );
+            int phys = gentity2phys.get_first_tag( pg );
+            infos[K++] = 15;
+            infos[K++] = phys;
+            infos[K++] = tag;
+            infos[K++] = EN_id(pv);
+          }
+      }
+
+    while ((pe = EIter_next (eit)))
+      {
+        int dim = EN_whatInType(pe);
+        if (dim == 1)
+          {
+            pGEntity pg = EN_whatIn(pe);
+            int tag = GEN_tag ( pg );
+            int phys = gentity2phys.get_first_tag( pg );
+            pVertex v1 = E_vertex ( pe, 0);
+            pVertex v2 = E_vertex ( pe, 1);
+            infos[K++] = 1;
+            infos[K++] = phys;
+            infos[K++] = tag;
+            infos[K++] = EN_id (v1);
+            infos[K++] = EN_id (v2);
+          }
+      }
+    while ((pf = FIter_next (fit)))
+      {
+        int dim = EN_whatInType(pf);
+        if (dim == 2)
+          {
+            pGEntity pg = EN_whatIn(pf);
+            int tag = GEN_tag ( pg );
+            int phys = gentity2phys.get_first_tag( pg );
+            pVertex v1 = F_vertex ( pf, 0);
+            pVertex v2 = F_vertex ( pf, 1);
+            pVertex v3 = F_vertex ( pf, 2);
+            infos[K++] = 2;
+            infos[K++] = phys;
+            infos[K++] = tag;
+            infos[K++] = EN_id (v1);
+            infos[K++] = EN_id (v2);
+            infos[K++] = EN_id (v3);
+          }
+      }
+
+    pRegion pr;
+    RIter rit  = M_regionIter ( this );
+    while ((pr = RIter_next (rit)))
+      {
+        pGEntity pg = EN_whatIn(pr);
+        int tag = GEN_tag ( pg );
+        int phys = gentity2phys.get_first_tag( pg );
+        pVertex v1 = R_vertex ( pr, 0);
+        pVertex v2 = R_vertex ( pr, 1);
+        pVertex v3 = R_vertex ( pr, 2);
+        pVertex v4 = R_vertex ( pr, 3);
+        infos[K++] = 4;
+        infos[K++] = phys;
+        infos[K++] = tag;
+        infos[K++] = EN_id (v1);
+        infos[K++] = EN_id (v2);
+        infos[K++] = EN_id (v3);
+        infos[K++] = EN_id (v4);
+      }
+
+    //  printf("%d %d\n",K,nbInfos);
+
+    VIter_delete(vit);
+    EIter_delete(eit);
+    FIter_delete(fit);
+    RIter_delete(rit);
+
+    DESTROOOY ( points.begin(),points.end());
+    DESTROOOY ( edges.begin(),edges.end());
+    DESTROOOY ( triangles.begin(),triangles.end());
+    DESTROOOY ( tets.begin(),tets.end());
+    DESTROOOY ( quads.begin(),quads.end());
+    DESTROOOY ( hexes.begin(),hexes.end());
+    DESTROOOY ( prisms.begin(),prisms.end());
+
+    points.clear();
+    edges.clear();
+    triangles.clear();
+    quads.clear();
+    tets.clear();
+    hexes.clear();
+    prisms.clear();
+
+    nbPoints = nbTriangles = nbEdges = nbTets = nbQuads = nbHexes = nbPrisms = 0;
+    maxId=0;
+
+    shrinked = true;
+  }
+  void MDB_Mesh :: classify_unclassified_entities ()
+  {
+    int nbV=0, nbE=0, nbF=0, nbR=0;
+
+    RIter rit = M_regionIter(this);
+    pRegion pr;
+    while ((pr = RIter_next(rit)))
+      {
+        if (pr->g)
+          {
+            pFace f1 = R_face (pr,0);
+            if (!f1->g) f1->g = pr->g;
+            pFace f2 = R_face (pr,1);
+            if (!f2->g) f2->g = pr->g;
+            pFace f3 = R_face (pr,2);
+            if (!f3->g) f3->g = pr->g;
+            pFace f4 = R_face (pr,3);
+            if (!f4->g) f4->g = pr->g;
+            pFace f5 = R_face (pr,4);
+            if (f5 && !f5->g) f5->g = pr->g;
+            pFace f6 = R_face (pr,5);
+            if (f6 && !f6->g) f6->g = pr->g;
+          }
+        else
+          {
+            nbR++;
+          }
+      }
+
+    RIter_delete(rit);
+
+    FIter fit = M_faceIter(this);
+    pFace pf;
+    while ((pf = FIter_next(fit)))
+      {
+        if (pf->g)
+          {
+            pEdge e1 = F_edge (pf,0);
+            if (!e1->g) e1->g = pf->g;
+            pEdge e2 = F_edge (pf,1);
+            if (!e2->g) e2->g = pf->g;
+            pEdge e3 = F_edge (pf,2);
+            if (!e3->g) e3->g = pf->g;
+            pEdge e4 = F_edge (pf,3);
+            if (e4 && !e4->g) e4->g = pf->g;
+          }
+        else
+          {
+            nbF++;
+          }
+      }
+    FIter_delete(fit);
+
+
+    EIter eit = M_edgeIter(this);
+    pEdge pe;
+    while ((pe = EIter_next(eit)))
+      {
+        if (pe->g)
+          {
+            pVertex v1 = E_vertex (pe,0);
+            if (!v1->g) v1->g = pe->g;
+            pVertex v2 = E_vertex (pe,1);
+            if (!v2->g) v2->g = pe->g;
+          }
+        else
+          {
+            nbE++;
+          }
+      }
+    EIter_delete(eit);
+
+    VIter vit = M_vertexIter(this);
+    pVertex pv;
+    while ((pv = VIter_next(vit)))
+      {
+        if (!pv->g)
+          {
+            nbV++;
+          }
+      }
+    VIter_delete(vit);
+
+    if ( !nbV || !nbE || !nbF || !nbR ) {
+      MAdMsgSgl::instance().info(__LINE__,__FILE__,
+                                 "There are unclassified entities: %d, regions, %d faces, %d edges, %d vertices\n",
+                                 nbR,nbF,nbE,nbV);
+    }
+  }
+
+  void MDB_Mesh :: destroyStandAloneEntities() {
+
+    // First build a list of entities < mesh dim and not to be deleted
+    // = those which are part of an entity of dimension = mesh dim
+    set<pVertex> usedV;
+    set<pEdge>   usedE;
+    set<pFace>   usedF;
+
+    // 3D case
+    if ( nbTets + nbHexes + nbPrisms != 0 ) {
+
+      RIter rit = M_regionIter(this);
+      pRegion pr;
+      while ((pr = RIter_next(rit)))
+        {
+          for (int i=0; i < pr->getNbFace(); i++) {
+            pFace f = R_face (pr,i);
+            usedF.insert(f);
+          }
+          for (int i=0; i < pr->getNbEdge(); i++) {
+            pEdge e = R_edge (pr,i);
+            usedE.insert(e);
+          }
+          for (int i=0; i < pr->getNbVertex(); i++) {
+            pVertex v = R_vertex (pr,i);
+            usedV.insert(v);
+          }
+        }
+      RIter_delete(rit);
+    }
+
+    // 2D case
+    else if ( nbTriangles + nbQuads != 0 ) {
+
+      FIter fit = M_faceIter(this);
+      pFace pf;
+      while ((pf = FIter_next(fit)))
+        {
+          usedF.insert(pf);
+          for (int i=0; i < pf->getNbEdges(); i++) {
+            pEdge e = F_edge (pf,i);
+            usedE.insert(e);
+          }
+          for (int i=0; i < pf->getNbNodes(); i++) {
+            pVertex v = F_vertex (pf,i);
+            usedV.insert(v);
+          }
+        }
+      FIter_delete(fit);
+    }
+
+    // 1D case
+    else if ( nbEdges != 0 ) {
+
+      EIter eit = M_edgeIter(this);
+      pEdge pe;
+      while ((pe = EIter_next(eit)))
+        {
+          usedE.insert(pe);
+          for (int i=0; i < 2; i++) {
+            pVertex v = E_vertex (pe,i);
+            usedV.insert(v);
+          }
+        }
+      EIter_delete(eit);
+    }
+
+    // 0D case
+    else {
+
+      VIter vit = M_vertexIter(this);
+      pVertex pv;
+      while ((pv = VIter_next(vit)))
+        {
+          usedV.insert(pv);
+        }
+      VIter_delete(vit);
+    }
+
+    // then delete the others
+    int delV = 0;
+    int delE = 0;
+    int delF = 0;
+
+    FIter fit = M_faceIter(this);
+    pFace pf;
+    while ((pf = FIter_next(fit)))
+      {
+        if (usedF.find(pf) == usedF.end() ) {
+          del_face(pf);
+          delF++;
+        }
+      }
+    FIter_delete(fit);
+
+    EIter eit = M_edgeIter(this);
+    pEdge pe;
+    while ((pe = EIter_next(eit)))
+      {
+        if (usedE.find(pe) == usedE.end() ) {
+// #warning "debug"
+//           printf("Looking for a clone...");
+//           pEdge peClone = find_clone_edge(pe);
+//           if (peClone) printf("found one\n");
+//           else         printf("no clone\n");
+//           if (peClone) {
+//             printf("This edge will be deleted:\n");
+//             E_info(pe);
+//             printf("This edge is its clone:\n");
+//             E_info(peClone);
+//           }
+//           if ( (peClone) && ( GEN_type(peClone->g) > GEN_type(pe->g) ) ) {
+//             peClone->g = pe->g;
+//           }
+
+          del_edge(pe);
+          delE++;
+        }
+      }
+    EIter_delete(eit);
+
+    VIter vit = M_vertexIter(this);
+    pVertex pv;
+    while ((pv = VIter_next(vit)))
+      {
+        if (usedV.find(pv) == usedV.end() ) {
+          del_point(pv);
+          delV++;
+        }
+      }
+    VIter_delete(vit);
+
+    if ( delV != 0 || delE != 0 || delF != 0 ) {
+      cout <<"WARNING: deleted stand alone entities: "
+           << delV <<" vertices, "
+           << delE <<" edges, "
+           << delF <<" faces\n";
+    }
+  }
+
+  // void MDB_Mesh :: checkGeomTagsCoherence () const
+  // {
+  //   std::set<int> volumeTags;
+  //   std::multimap<int, pGEntity >::const_iterator tagIt = geomFeatures_Tags.begin();
+  //   for (; tagIt != geomFeatures_Tags.end(); tagIt++)
+  //     if (GEN_type(tagIt->second) == 3)
+  //       volumeTags.insert(tagIt->first);
+
+  //   tagIt = geomFeatures_Tags.begin();
+  //   for (; tagIt != geomFeatures_Tags.end(); tagIt++)
+  //     if (GEN_type(tagIt->second) == 2)
+  //       if ( volumeTags.find(tagIt->first) != volumeTags.end() ) {
+  // 	printf("Wrong input geometry: the geometric ID \'%d\' is used for both a volume and a surface\n",tagIt->first);
+  // 	exit(0);
+  //       }
+  // }
+
+  void MDB_Mesh :: expand ()
+  {
+    initializeIdData();
+
+    pVertex *vs = new pVertex[nbVertex];
+
+    for (int i=0;i<nbVertex;i++)
+      {
+        //       vs[i] = add_point (i+1,coords[3*i],coords[3*i+1],coords[3*i+2]);
+        vs[i] = add_point (ids[i],coords[3*i],coords[3*i+1],coords[3*i+2]);
+      }
+
+
+    nbVertex = 0;
+    delete [] coords;
+
+    int i=0;
+    while (i<nbInfos)
+      {
+        int type = infos[i++];
+        int physicalTag  = infos[i++];
+        int elementaryTag = infos[i++];
+        pGEntity g=NULL;
+
+        if (type == 15)
+          {
+            pVertex p = vs[infos[i++]-1];
+            g = GM_entityByTag(model, 0, elementaryTag);
+            p->g = g;
+          }
+        else if (type == 1)
+          {
+            pVertex v1 = vs[infos[i++]-1];
+            pVertex v2 = vs[infos[i++]-1];
+            g = GM_entityByTag(model, 1, elementaryTag);
+            add_edge(v1,v2,g);
+          }
+        else if (type == 2)
+          {
+            int v1 = ids[infos[i++]-1];
+            int v2 = ids[infos[i++]-1];
+            int v3 = ids[infos[i++]-1];
+            g = GM_entityByTag(model, 2, elementaryTag);
+            add_triangle(v1,v2,v3,g);
+          }
+        else if (type == 4)
+          {
+            pVertex v1 = vs[infos[i++]-1];
+            pVertex v2 = vs[infos[i++]-1];
+            pVertex v3 = vs[infos[i++]-1];
+            pVertex v4 = vs[infos[i++]-1];
+            g = GM_entityByTag(model, 3, elementaryTag);
+            add_tet(v1,v2,v3,v4,g);
+          }
+	if (g)
+	  {
+	    bool find = false;
+	    for (std::multimap<int, pGEntity>::iterator it = geomFeatures_Tags.lower_bound(physicalTag);
+		 it != geomFeatures_Tags.upper_bound(physicalTag);++it)
+	      if (it->second == g)find = true;
+	    if (!find)
+	      geomFeatures_Tags.insert(std::pair<int,pGEntity>(physicalTag, g));
+	  }
+      }
+    delete [] infos; infos = NULL;
+    delete [] ids;   ids   = NULL;
+    delete [] vs;    vs    = NULL;
+    nbInfos = 0;
+    classify_unclassified_entities();
+    shrinked = false;
+  }
+
+  int MDB_Tet::face_vtx[4][3] = {{0,1,2},{0,1,3},{1,2,3},{0,2,3}};
+
+  // return 1 if the face direction points to outside of the tet
+  // return 0                                 inside
+  int MDB_Tet::getFaceDir (int n) const
+  {
+    int tetfacedir [] = {1,0,0,1};
+    int corr = tetfacedir[n];
+    pFace f  = getFace(n);
+    pVertex v1f, v2f;
+    v1f = F_vertex (f,0);
+    v2f = F_vertex (f,1);
+
+    pVertex v[3];
+    switch (n)
+      {
+      case 0 : //inside
+        v[0] = getVertex(0);
+        v[1] = getVertex(1);
+        v[2] = getVertex(2);
+        break;
+      case 1 : // outside
+        v[0] = getVertex(0);
+        v[1] = getVertex(1);
+        v[2] = getVertex(3);
+        break;
+      case 2 : // outside
+        v[0] = getVertex(1);
+        v[1] = getVertex(2);
+        v[2] = getVertex(3);
+        break;
+      case 3 : //inside
+        v[0] = getVertex(0);
+        v[1] = getVertex(2);
+        v[2] = getVertex(3);
+        break;
+      default :
+        throw;
+      }
+
+
+    for(int j=0;j<3;j++)
+      {
+        if (v[j] == v1f)
+          {
+            pVertex vtest = v[(j+1)%3];
+            if (vtest == v2f) return 1-corr;
+            vtest = v[(j+2)%3];
+            if (vtest == v2f) return corr;
+            throw;
+          }
+      }
+    throw;
+  }
+
+  int MDB_Tet::getFaceOrientation (int n) const {
+
+    pFace   f  = getFace(n);
+    pVertex v0 = getVertex(face_vtx[n][0]);
+    pVertex v1 = getVertex(face_vtx[n][1]);
+
+    int orientation = 0;
+
+    for (int j=0;j<3;j++) if (F_vertex(f,j) == v0) orientation = j;
+
+    int direction = 1;
+    if (v1 == F_vertex(f,(orientation+2)%3)) direction = -1;
+
+    return direction * (orientation + 1);
+  }
+
+
+  int MDB_Hex::getFaceDir (int n) const {  return 0;}
+
+  // -----------------------------------------------------------------------------
+  /*! \brief Compute orientation wrt face given by a list of principal nodes \ingroup internal  */
+  /*! abs(rot) - 1 = the index of the node in the current element corresponding to node 0 in the remote element */
+  /*! sgn(rot)     = 1 if the element is oriented in the same fashion, -1 if inverted */
+
+  int MDB_Face::orientation(MDB_Point* v0,
+                            MDB_Point* v1,
+                            MDB_Point* v2,
+                            MDB_Point* v3) const {
+
+    if ((getNbNodes() == 4) && (v3 == NULL)) return 0;
+
+    int rot = 0;
+    for (int j=0;j<getNbNodes();j++) {
+      if (getNode(j) == v0) rot = j+1;
+    }
+
+    if (getNode(rot%getNbNodes()) != v1)  {
+      if (getNode((rot-2+getNbNodes())%getNbNodes()) == v1) rot *= -1;
+    }
+    return rot;
+  }
+
+  // -----------------------------------------------------------------------------
+  /*! \brief Realign the edge with the direction given by a set of two nodes \ingroup internal  */
+  /*! returns 1 if already aligned, -1 if inversely aligned, 0 if failed  */
+
+  int MDB_Edge::align(MDB_Point* po1,MDB_Point* po2)
+  {
+    if ((p1 == po1) && (p2 == po2)) return 1;
+    if ((p2 == po1) && (p1 == po2)) {
+      std::swap(p1,p2);
+      swapHONodes();
+      return -1;
+    }
+    return 0;
+  }
+
+  // -----------------------------------------------------------------------------
+  /*! \brief Realign the triangle with the direction given by a set of three nodes \ingroup internal */
+  /*! Returns 0 if failed, otherwise
+    abs(rot) = index of node corresponding to v0
+    sng(rot) = 1 if same orientation, -1 if inverted orientation */
+
+  int MDB_Triangle::align(MDB_Point* v0,MDB_Point* v1,MDB_Point* v2,MDB_Point* v3) {
+
+    int rot = orientation(v0,v1,v2,v3);
+
+    if (rot != 1 && rot != 0) {
+
+      MDB_Edge* tmpEdge[3];
+      for (int i=0;i<3;i++) tmpEdge[i] = getEdge((i+abs(rot)-1)%3);
+      
+      if (rot < 0) {
+        MDB_Edge* tmp = tmpEdge[0];
+        tmpEdge[0] = tmpEdge[2];
+        tmpEdge[2] = tmp;
+      }
+
+      e1 = tmpEdge[0];
+      e2 = tmpEdge[1];
+      e3 = tmpEdge[2];
+    }
+    return rot;
+  }
+
+  // -----------------------------------------------------------------------------
+  /*! \brief Realign the quadrilateral with the direction given by a set of four nodes \ingroup internal */
+  /*! Returns 0 if failed, otherwise
+    abs(rot) = index of node corresponding to v0
+    sng(rot) = 1 if same orientation, -1 if inverted orientation */
+
+  int MDB_Quad::align(MDB_Point* v0,MDB_Point* v1,MDB_Point* v2,MDB_Point* v3) {
+
+    int rot = orientation(v0,v1,v2,v3);
+    if (rot != 1 && rot != 0) {
+
+      MDB_Edge* tmpEdge[4];
+      for (int i=0;i<getNbEdges();i++) tmpEdge[i] = getEdge((i+abs(rot)-1)%getNbEdges());
+
+      if (rot < 0) {
+        MDB_Edge* tmp = tmpEdge[0];
+        tmpEdge[0] = tmpEdge[3];
+        tmpEdge[3] = tmp;
+        tmp = tmpEdge[1];
+        tmpEdge[1] = tmpEdge[2];
+        tmpEdge[2] = tmp;
+      }
+
+      e1 = tmpEdge[0];
+      e2 = tmpEdge[1];
+      e3 = tmpEdge[2];
+      e4 = tmpEdge[3];
+    }
+
+    return rot;
+
+  }
+
+} // End of namespace MAd
+
diff --git a/Mesh/MeshDataBase.h b/Mesh/MeshDataBase.h
new file mode 100644
index 0000000..575e4d3
--- /dev/null
+++ b/Mesh/MeshDataBase.h
@@ -0,0 +1,1191 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere, Koen Hillewaert
+// -------------------------------------------------------------------
+
+#ifndef H_MESHDATABASE
+#define H_MESHDATABASE
+#include <set>
+#include <vector>
+#include <algorithm>
+#include <list>
+#include <map>
+#include <cmath>
+#include <assert.h>
+#include <cstdarg>
+#include <string.h>
+#include <iostream>
+#include "ModelInterface.h"
+#include "MeshDataBaseIterators.h"
+#include "MeshDataBaseAttachable.h"
+#include "MeshDataBaseMiniMesh.h"
+#include "MeshDataBaseMessage.h"
+
+namespace MAd {
+
+  class MDB_Region;
+  class MDB_Tet;
+  class MDB_Hex;
+  class MDB_Prism;
+  class MDB_Quad;
+  class MDB_Face;
+  class MDB_Edge;
+  class MDB_EdgeP2;
+  class MDB_Triangle;
+  class MDB_Mesh;
+  class MDB_Point;
+
+  typedef std::list<MDB_Point *>      MDB_ListP ;
+  typedef std::list<MDB_Edge *>       MDB_ListE ;
+  typedef std::list<MDB_Triangle *>   MDB_ListF ;
+  typedef std::list<MDB_Quad*>        MDB_ListQ ;
+  typedef std::list<MDB_Face*>        MDB_ListFace;
+  typedef std::list<MDB_Tet *>        MDB_ListT ;
+  typedef std::list<MDB_Hex *>        MDB_ListH ;
+  typedef std::list<MDB_Prism *>      MDB_ListPr;
+  typedef std::list<MDB_Region *>     MDB_ListR ;
+  typedef std::vector<MDB_Triangle *> MDB_VectorF ;
+  typedef std::vector<MDB_Quad *>     MDB_VectorQ ;
+  typedef std::vector<MDB_Edge *>     MDB_VectorE ;
+  typedef std::vector<MDB_Tet *>      MDB_VectorT ;
+  typedef std::vector<MDB_Hex *>      MDB_VectorH ;
+  typedef std::vector<MDB_Prism *>    MDB_VectorPr;
+
+  class MDB_MeshEntity : public mAttachableDataContainer  
+  {
+  public :
+    int iD;
+    bool deleted;
+    pGEntity g;
+    virtual int getDim()   const = 0;
+    virtual int getOrder() const = 0;
+    MDB_MeshEntity ( int _ID = 0, pGEntity _g = 0) : iD(_ID), deleted (false), g(_g) {}    
+    virtual ~MDB_MeshEntity() {}
+  };
+
+  /*! \brief Vertex */ 
+
+  class MDB_Point : public MDB_MeshEntity
+  {
+  public:
+    // SHOULD BE PRIVATE, 2B DONE
+    double X,Y,Z;
+    MDB_VectorE edges;
+
+    virtual int getDim()   const {return 0;}
+    virtual int getOrder() const {return 0;}
+    virtual bool isParametric() const { return false; }
+    virtual bool getParams(double * u, double * v) const { return false; }
+
+    inline bool operator < (const MDB_Point & other) const
+    {
+      return iD < other.iD;
+    }
+    inline void del(MDB_Edge *e)
+    {
+      MDB_VectorE::iterator it  = edges.begin();
+      MDB_VectorE::iterator ite = edges.end();
+      while(it!=ite){
+        if(*it == e){
+          edges.erase(it);
+          break;
+        }
+        ++it;
+      }
+    }
+    void getTriangles(MDB_ListF &) const; 	
+    void getTets(MDB_ListT &) const; 
+    void getQuads(MDB_ListQ &) const; 	
+    void getHexes(MDB_ListH &) const;
+  
+    //void getHexs     (MDB_ListH &) const;
+
+    MDB_Point(int id, double x=0, double y=0, double z=0) 
+      : MDB_MeshEntity(id),X(x),Y(y),Z(z)
+    {	    
+      //    edges.reserve(12);
+    }
+    virtual ~MDB_Point() {}
+  };
+
+  /*! \brief Parametric vertex */ 
+
+  class MDB_PointParam : public MDB_Point
+  {
+  public:
+
+    MDB_PointParam(int id, double x=0, double y=0, double z=0, double u=0, double v=0)
+      :  MDB_Point(id,x,y,z),U(u),V(v)
+    {}
+    ~MDB_PointParam() {}
+
+    bool isParametric() const { return true; }
+    bool getParams(double * u, double * v) const { *u=U; *v=V; return true; }
+
+  private:
+
+    double U,V;
+  };
+
+  /*! \brief Straight edge or base class for higher order edges */ 
+
+  class MDB_Edge: public MDB_MeshEntity
+  {
+    std::vector<MDB_Triangle *> _faces;
+//     MDB_VectorF _faces;
+    MDB_VectorQ _quads;
+  public:
+
+    MDB_Point *p1,*p2;
+
+    virtual int getDim()   const {return 1;}
+    virtual int getOrder() const {return 1;}
+
+    inline MDB_Triangle* faces(int i) const
+    {
+      if ( _faces.size() == 0 ) return NULL;
+      if ( _faces.size() == 1 && i == 1 ) return NULL;
+      return _faces [i];
+    }
+
+    inline MDB_Quad* quads(int i) const
+    {
+      if ( _quads.size() == 0 ) return NULL;
+      if ( _quads.size() == 1 && i == 1 ) return NULL;
+      return _quads [i];
+    }
+
+    inline double length() const
+    {
+      return sqrt((p1->X-p2->X)*(p1->X-p2->X)+(p1->Y-p2->Y)*(p1->Y-p2->Y)+(p1->Z-p2->Z)*(p1->Z-p2->Z));
+    }
+
+    inline int numfaces() const
+    {
+      return _faces.size();
+    }
+
+    inline int numquads() const 
+    {
+      return _quads.size();
+    }
+
+    inline MDB_Point * commonvertex(const MDB_Edge *other) const
+    {
+      if(p1 == other->p1 || p1 == other->p2) return p1;
+      if(p2 == other->p1 || p2 == other->p2) return p2;
+      printf("two edges %d %d -- %d %d without common vertex\n",p1->iD,p2->iD, other->p1->iD, other->p2->iD);
+      throw;
+    }
+
+    inline MDB_Point * othervertex(const MDB_Point *p) const
+    {
+      if(p1 == p) return p2;
+      if(p2 == p) return p1;
+      return 0;
+    }
+
+    inline void addface(MDB_Triangle *f)
+    {
+      _faces.push_back(f);
+    }
+
+    inline void addface(MDB_Quad *q)
+    {
+      _quads.push_back(q);
+    }
+
+    inline MDB_Triangle * otherFace(const MDB_Triangle *f) const
+    {
+      if(numfaces()!=2) return NULL;
+      if(f == _faces[0]) return _faces[1];
+      if(f == _faces[1]) return _faces[0];
+      throw;
+    }
+
+    inline void del( MDB_Triangle *t )
+    {
+      _faces.erase(std::remove_if(_faces.begin(),_faces.end() , std::bind2nd(std::equal_to<MDB_Triangle*>(), t)) , 
+                   _faces.end());
+    }
+  
+    inline void del( MDB_Quad *t )
+    {
+      _quads.erase(std::remove_if(_quads.begin(),_quads.end() , std::bind2nd(std::equal_to<MDB_Quad*>(), t)) , 
+                   _quads.end());
+    }
+  
+    inline void oppositeof(MDB_Point * oface[2]) const; 
+  
+    virtual int getNbHighOrderPoints () const {return 0;}
+    virtual MDB_Point *getHighOrderPoint (int i) {throw;}
+
+    MDB_Edge(MDB_Point *A, MDB_Point *B)
+      : p1(A),p2(B)
+    {
+//       _faces.reserve(2);
+//       _quads.reserve(1);
+      p1->edges.push_back(this);
+      p2->edges.push_back(this);
+    }
+
+    virtual void swapHONodes() {}
+    virtual int align(MDB_Point* po1,MDB_Point* po2);
+    virtual ~MDB_Edge();
+  };
+
+  /*! \brief 2nd order equidistant Lagrange edge */
+
+  class MDB_EdgeP2: public MDB_Edge
+  {
+    MDB_Point *secondOrderPt;
+  public :
+    virtual int getOrder() const {return 2;}
+    virtual int getNbHighOrderPoints() const {return 1;}
+    virtual MDB_Point *getHighOrderPoint (int i) {assert (i==0);return secondOrderPt;}
+    MDB_EdgeP2(MDB_Point *A, MDB_Point *B, MDB_Point *C)
+      : MDB_Edge ( A, C ), secondOrderPt(B)
+    {
+    }
+    virtual ~MDB_EdgeP2() {delete secondOrderPt;}
+  };
+
+  /*! \brief 3rd order equidistant Lagrange edge */
+
+  class MDB_EdgeP3: public MDB_Edge
+  {
+    MDB_Point *Pt1,*Pt2;//third order points
+  public :
+    virtual int getOrder() const {return 3;}
+    virtual int getNbHighOrderPoints() const {return 2;}
+    virtual MDB_Point *getHighOrderPoint (int i) {
+      switch (i){
+      case 0:
+        return Pt1;
+      case 1:
+        return Pt2;
+      default:
+        std::cout << "Point " << i << "not defined for third order edges\n"; throw;
+      }
+    }
+    MDB_EdgeP3(MDB_Point *A, MDB_Point *B1, MDB_Point *B2, MDB_Point *C)
+      : MDB_Edge ( A, C ), Pt1(B1), Pt2(B2)
+    {
+    }
+    virtual ~MDB_EdgeP3() {delete Pt1;delete Pt2;}
+
+    virtual void swapHONodes() {
+
+      MDB_Point* tmp = Pt2;
+      Pt2 = Pt1;
+      Pt1 = tmp;
+    }
+  };
+
+  /*! \brief 4th order equidistant Lagrange edge */
+
+  class MDB_EdgeP4: public MDB_Edge
+  {
+    MDB_Point *Pt1,*Pt2,*Pt3;//fourth order points
+  public :
+    virtual int getOrder() const {return 4;}
+    virtual int getNbHighOrderPoints() const {return 3;}
+    virtual MDB_Point *getHighOrderPoint (int i) {
+      switch (i){
+      case 0:
+        return Pt1;
+      case 1:
+        return Pt2;
+      case 2:
+        return Pt3;
+      default:
+        std::cout << "Point " << i << "not defined for fourth order edges\n"; throw;
+      }
+    }
+    MDB_EdgeP4(MDB_Point *A, MDB_Point *B1, MDB_Point *B2, MDB_Point *B3, MDB_Point *C)
+      : MDB_Edge ( A, C ), Pt1(B1), Pt2(B2), Pt3(B3)
+    {
+    }
+    virtual ~MDB_EdgeP4() {delete Pt1;delete Pt2;delete Pt3;}
+
+  protected:
+  
+    virtual void swapHONodes() 
+    {
+      MDB_Point* tmp = Pt1;
+      Pt1 = Pt3;
+      Pt3 = tmp;
+    }
+  };
+
+  /*! \brief 5th order equidistant Lagrange edge */
+
+  class MDB_EdgeP5: public MDB_Edge
+  {
+    MDB_Point *Pt1,*Pt2,*Pt3, *Pt4;//fifth order points
+  public :
+    virtual int getOrder() const {return 5;}
+    virtual int getNbHighOrderPoints() const {return 4;}
+    virtual MDB_Point *getHighOrderPoint (int i) {
+      switch (i){
+      case 0:
+        return Pt1;
+      case 1:
+        return Pt2;
+      case 2:
+        return Pt3;
+      case 3:
+        return Pt4;
+      default:
+        std::cout << "Point " << i << "not defined for fifth order edges\n"; throw;
+      }
+    }
+    MDB_EdgeP5(MDB_Point *A, MDB_Point *B1, MDB_Point *B2, MDB_Point *B3, MDB_Point *B4, MDB_Point *C)
+      : MDB_Edge ( A, C ), Pt1(B1), Pt2(B2), Pt3(B3), Pt4(B4)
+    {
+    }
+    virtual ~MDB_EdgeP5() {delete Pt1;delete Pt2;delete Pt3;delete Pt4;}
+
+  protected:
+    virtual void swapHONodes() 
+    {
+      MDB_Point* tmp = Pt1;
+      Pt1 = Pt4;
+      Pt4 = tmp;
+
+      tmp = Pt2;
+      Pt2 = Pt3;
+      Pt3 = tmp;
+    }  
+  };
+
+  class MDB_Face: public MDB_MeshEntity
+  {
+  protected:
+    std::vector<MDB_Region *> _regions;
+  public :
+    virtual int        getNbEdges ()  const = 0;
+    virtual int        getNbNodes ()  const = 0;
+    virtual MDB_Edge * getEdge  (int) const = 0;
+    virtual int getDim() const {return 2;}
+
+    inline MDB_Region* getRegion (int i) const
+    {
+      if (getNbRegions()==0)return 0;
+      if (getNbRegions()==1 && i == 1)return 0;
+      return _regions[i];
+    }
+
+    inline MDB_Region * opposite_region(MDB_Region *t)
+    {
+      if(t == getRegion(0))return getRegion(1);
+      if(t == getRegion(1))return getRegion(0);
+      throw;
+    }
+
+    inline int getNbRegions() const 
+    {
+      return (_regions.size());
+    }
+  
+    inline void addregion(MDB_Region *t)
+    {
+      _regions.push_back(t);
+    }
+
+    inline void del( MDB_Region *t )
+    {
+      _regions.erase(std::remove_if(_regions.begin(),_regions.end() , std::bind2nd(std::equal_to<MDB_Region*>(), t)) , 
+                     _regions.end());
+    }
+
+    inline MDB_Edge * commonedge(const MDB_Face *other) const
+    {
+      for (int i=0;i<getNbEdges ();i++)
+        for (int j=0;j<other->getNbEdges ();j++)
+          {
+            MDB_Edge *e = getEdge(i);
+            if (e == other->getEdge(j)) return  e;
+          }
+      throw;
+    }
+
+    inline MDB_Point *getNode(int i) const
+    {
+      if (!i)
+        {
+          int nbe = getNbEdges ();
+          return getEdge(0)->commonvertex(getEdge(nbe-1));
+        }
+      return getEdge(i)->commonvertex(getEdge(i-1));        
+    }
+
+    inline void getNodes(MDB_Point **n) const
+    {
+      for (int i=0;i<getNbEdges ();i++)n[i] = getNode(i);
+    }
+
+    MDB_Face() /*: r1(0), r2(0) */{};
+    virtual MDB_Point *getHighOrderPoint (int i) {throw;}
+    virtual int getNbHighOrderPoints() const {return 0;}
+  
+    virtual int align(MDB_Point* v0,MDB_Point* v1,MDB_Point* v2,MDB_Point* v3) = 0;
+
+  protected:
+  
+    virtual int orientation(MDB_Point* v0,MDB_Point* v1,MDB_Point* v2,MDB_Point* v3) const;
+  
+  };
+
+  /*! \brief Straight edged triangle and base class for higher order versions */ 
+
+  class MDB_Triangle: public MDB_Face
+  {
+  public:
+    MDB_Edge *e1,*e2,*e3;
+    
+    virtual int        getOrder()     const {return 1;}
+    virtual int        getNbEdges ()  const {return 3;}
+    virtual int        getNbNodes ()  const {return 3;}
+    virtual int        align(MDB_Point*,MDB_Point*,MDB_Point*,MDB_Point*);
+    virtual MDB_Edge * getEdge  (int i) const 
+    {
+      switch (i){
+      case 0 : return e1;
+      case 1 : return e2;
+      case 2 : return e3;
+      case 3 : return (MDB_Edge *)  NULL;
+      }
+      throw;
+    }
+  
+    MDB_Triangle(MDB_Edge *A, MDB_Edge *B, MDB_Edge *C)
+      : e1(A),e2(B),e3(C)
+    {	
+      e1->addface(this);
+      e2->addface(this);
+      e3->addface(this);
+    }
+    virtual ~MDB_Triangle() {}
+
+    virtual int getNbHighOrderPoints() const { return 0;}
+
+  };
+
+
+  /*! \brief Generic order equidistant Lagrange triangle with complete interpolation */ 
+  template <int order>
+  class MDB_CompleteTriangle : public MDB_Triangle {
+
+  public:
+  
+    MDB_CompleteTriangle(MDB_Edge *A, MDB_Edge *B, MDB_Edge *C,MDB_Point** P):
+      MDB_Triangle(A,B,C),nbPoints(std::max(0,(order-2)*(order-1)/2)),point(NULL) {
+      point = nbPoints > 0 ? new MDB_Point*[nbPoints] : NULL;
+      for (int i=0;i<nbPoints;i++) point[i] = P[i];  
+    }
+    
+    ~MDB_CompleteTriangle() {if (point) delete [] point;}
+    
+    virtual int getOrder()     const {return order;}
+    int getNbHighOrderPoints() const {return nbPoints;}
+    MDB_Point* getHighOrderPoint(int i) {return (i<nbPoints) ?  point[i] : NULL;}
+
+  protected:
+    
+    int nbPoints;
+    MDB_Point** point;
+
+
+  protected:
+
+
+    virtual int align(MDB_Point* v0,MDB_Point* v1,MDB_Point* v2,MDB_Point* v3) {
+
+
+      if (v3 != NULL) Msg(MDB_FATAL,"Aligning a triangle with a quadrilateral is not allowed\n");
+    
+      int rot = MDB_Triangle::align(v0,v1,v2,NULL);
+
+
+      /* we only store the internal points (the higher order nodes on the edges are stored elsewhere)
+         this means that this corresponds to a triangle of order = order - 3 */ 
+      rotateHOPoints(rot,point,order-3);
+    
+      return rot;
+    }
+
+  
+    /*! rotate a triangular set of points such that the node on position abs(rot) - 1
+      is migrated to node 0; swap if rot < 0 */
+
+    void rotateHOPoints(int rot,MDB_Point** op,int recursiveOrder) {
+    
+      if (recursiveOrder <= 0) return; // only one node needs no further reorientation 
+      if (rot   == 1) return; // already aligned 
+  
+      int nbRecursivePoints = (recursiveOrder+1)*(recursiveOrder+2)/2;
+      int nbEdgePoints  = (recursiveOrder - 1);
+  
+      MDB_Point** np = new MDB_Point*[nbRecursivePoints];
+  
+      // first rearrange principal vertices
+  
+      memcpy(np,op,nbRecursivePoints*sizeof(MDB_Point*));
+  
+      for (int i=0;i<3;i++) np[i] = op[(i + abs(rot) - 1)%3];
+      if (rot < 0) std::swap(np[1],np[2]);
+  
+  
+      if (recursiveOrder > 1)  {
+    
+        // then edge nodes
+      
+        if (rot > 0) {
+          for (int i=0;i<3;i++) {
+            MDB_Point** nb = np + 3 + i * nbEdgePoints;
+            MDB_Point** ob = op + 3 + (i + rot - 1) % 3 * nbEdgePoints;
+            for (int j=0;j<nbEdgePoints;j++) memcpy(nb,ob,nbEdgePoints * sizeof(MDB_Point*));
+          }
+        }
+      
+        if (rot < 0) {
+          for (int i=0;i<3;i++) {
+            MDB_Point** nb = np + 2 + ((abs(rot) - i + 1) % 3 + 1)  * nbEdgePoints;      
+            MDB_Point** ob = op + 3 + i * nbEdgePoints;
+            for (int j=0;j<nbEdgePoints;j++) *nb-- = *ob++;
+          }
+        }
+      
+        rotateHOPoints(rot,np + 3 * (nbEdgePoints+1) , recursiveOrder - 3);
+      }
+    
+      memcpy(op,np,nbRecursivePoints * sizeof(MDB_Point*));
+      delete [] np;
+    } 
+
+   
+  };
+
+  class MDB_Quad : public MDB_Face
+  {
+  public:
+    MDB_Edge *e1,*e2,*e3,*e4;
+  
+    
+    virtual int        getOrder()     const {return 2;}
+    virtual int        getNbEdges ()  const {return 4;}
+    virtual int        getNbNodes ()  const {return 4;}
+    virtual int        align(MDB_Point*,MDB_Point*,MDB_Point*,MDB_Point*);
+    virtual MDB_Edge * getEdge  (int i) const 
+    {
+      switch (i){
+      case 0 : return e1;
+      case 1 : return e2;
+      case 2 : return e3;
+      case 3 : return e4;
+      }
+      throw;
+    }
+  
+    MDB_Quad(MDB_Edge *A, MDB_Edge *B, MDB_Edge *C, MDB_Edge *D)
+      : e1(A),e2(B),e3(C),e4(D)
+    {	
+      e1->addface(this);
+      e2->addface(this);
+      e3->addface(this);
+      e4->addface(this);
+    }
+    virtual ~MDB_Quad() {}
+  };
+
+
+  class MDB_Region: public MDB_MeshEntity
+  {
+  public:
+    virtual MDB_Face *getFace (int i) const = 0;
+    virtual MDB_Edge *getEdge (int i) const = 0;
+    virtual MDB_Point *getVertex (int i) const = 0;
+    virtual MDB_Point *getHighOrderPoint (int i) {throw;}
+    virtual int getNbHighOrderPoints() const {return 0;}
+    virtual void      getNodes(MDB_Point **n) const = 0;
+    virtual int       getNbFace () const = 0;
+    virtual int       getNbEdge () const = 0;
+    virtual int       getNbVertex () const = 0;
+    virtual int       getFaceDir (int) const = 0;
+    virtual int       getFaceOrientation(int) const {throw;}
+  
+  };
+
+  class MDB_Hex: public MDB_Region
+  {
+  public:
+    MDB_Quad  *f1,*f2,*f3,*f4,*f5,*f6;
+  
+    virtual int getOrder() const {return 3;}
+    virtual int getDim()   const {return 3;}
+
+    virtual int       getNbFace () const {return 6;}
+    virtual int       getNbEdge () const {return 12;}
+    virtual int       getNbVertex () const{return 8;}
+    virtual MDB_Face *getFace (int i) const
+    {
+      switch(i){
+      case 0:return f1;
+      case 1:return f2;
+      case 2:return f3;
+      case 3:return f4;
+      case 4:return f5;
+      case 5:return f6;
+      }
+      throw;
+    }
+    virtual MDB_Edge *getEdge (int n) const
+    {
+      switch (n){
+      case 0  : return f1->commonedge ( f2 );
+      case 1  : return f1->commonedge ( f3 );
+      case 2  : return f1->commonedge ( f4 );
+      case 3  : return f1->commonedge ( f5 );
+      case 4  : return f2->commonedge ( f5 );
+      case 5  : return f2->commonedge ( f3 );    
+      case 6  : return f3->commonedge ( f4 );    
+      case 7  : return f4->commonedge ( f5 );    
+      case 8  : return f2->commonedge ( f6 );    
+      case 9  : return f3->commonedge ( f6 );    
+      case 10 : return f4->commonedge ( f6 );    
+      case 11 : return f5->commonedge ( f6 );    
+      }
+      throw;    
+    }
+
+    virtual MDB_Point *getVertex (int n) const /*SL OK*/
+    {
+      MDB_Edge *e1=0,*e2=0; 
+      switch (n){
+      case 0 : e1 = getEdge(0);e2 = getEdge(3);break;
+      case 1 : e1 = getEdge(0);e2 = getEdge(1);break;
+      case 2 : e1 = getEdge(1);e2 = getEdge(2);break;
+      case 3 : e1 = getEdge(2);e2 = getEdge(3);break;
+      case 4 : e1 = getEdge(4);e2 = getEdge(8);break;
+      case 5 : e1 = getEdge(5);e2 = getEdge(9);break;
+      case 6 : e1 = getEdge(6);e2 = getEdge(10);break;
+      case 7 : e1 = getEdge(7);e2 = getEdge(11);break;
+      default: throw;
+      }
+
+      return e1->commonvertex ( e2 );
+    }
+
+    virtual int getFaceDir (int n) const;
+
+
+    virtual void getNodes(MDB_Point **n) const
+    {
+      MDB_Point *o[4];
+      f1->getNodes(n);
+      f2->getNodes(o);
+      for(int i=0;i<4;i++) n[i+4]=o[i];
+    }
+  
+    MDB_Hex(MDB_Quad *A, MDB_Quad *B, MDB_Quad *C, MDB_Quad *D, MDB_Quad *E,  MDB_Quad *F)
+      : f1(A),f2(B),f3(C),f4(D),f5(E),f6(F)
+    { 
+      f1->addregion(this);
+      f2->addregion(this);
+      f3->addregion(this);
+      f4->addregion(this);
+      f5->addregion(this);
+      f6->addregion(this);
+    }
+    virtual ~MDB_Hex() {}
+
+  };
+
+  class MDB_Tet: public MDB_Region
+  {
+  public:
+    MDB_Triangle  *f1,*f2,*f3,*f4;
+  
+    virtual int getOrder() const {return 1;}
+    virtual int getDim()   const {return 3;}
+
+    virtual int       getNbFace () const {return 4;}
+    virtual int       getNbEdge () const {return 6;}
+    virtual int       getNbVertex () const{return 4;}
+    virtual MDB_Face *getFace (int i) const
+    {
+      switch(i){
+      case 0:return f1;
+      case 1:return f2;
+      case 2:return f3;
+      case 3:return f4;
+        // NP default NULL added to avoid call to throw 
+        //    in classify_unclassified_entities
+      default: return (MDB_Face *)  NULL;
+      }
+      throw;
+    }
+    virtual MDB_Edge *getEdge (int n) const
+    {
+      switch (n){
+      case 0 : return f1->commonedge ( f2 );
+      case 1 : return f1->commonedge ( f3 );
+      case 2 : return f1->commonedge ( f4 );
+      case 3 : return f2->commonedge ( f4 );
+      case 4 : return f2->commonedge ( f3 );
+      case 5 : return f3->commonedge ( f4 );    
+      }
+      throw;    
+    }
+
+    virtual MDB_Point *getVertex (int n) const
+    {
+      MDB_Edge *e1=0,*e2=0; 
+      switch (n){
+      case 0 : e1 = getEdge(0);e2 = getEdge(2);break;
+      case 1 : e1 = getEdge(0);e2 = getEdge(1);break;
+      case 2 : e1 = getEdge(1);e2 = getEdge(2);break;
+      case 3 : e1 = getEdge(3);e2 = getEdge(5);break;
+      default: throw;
+      }
+      return e1->commonvertex ( e2 );
+    }
+
+    // return 1 if the face direction points to outside of the tet
+    // return 0                                 inside
+    virtual int getFaceDir (int n) const;
+    // return number of times we need to rotate the element to make
+    // the principal node coincide with that of the tetrahedron (before normal inversion)
+    virtual int getFaceOrientation (int n) const;
+
+    virtual void getNodes(MDB_Point **n) const
+    {
+      MDB_Point *o[3];
+      f1->getNodes(n);
+      f2->getNodes(o);	  
+      n[3] = 0; //for stupid gcc warning
+      if(o[0] != n[0] && o[0] != n[1] &&o[0] != n[2])n[3] = o[0];
+      if(o[1] != n[0] && o[1] != n[1] &&o[1] != n[2])n[3] = o[1];
+      if(o[2] != n[0] && o[2] != n[1] &&o[2] != n[2])n[3] = o[2];
+    }
+  
+    MDB_Tet(MDB_Triangle *A, MDB_Triangle *B, MDB_Triangle *C, MDB_Triangle *D)
+      : f1(A),f2(B),f3(C),f4(D)
+    {	
+      f1->addregion(this);
+      f2->addregion(this);
+      f3->addregion(this);
+      f4->addregion(this);
+    }
+    virtual ~MDB_Tet() {}
+
+  protected:
+
+    static int face_vtx[4][3];
+  
+  };
+
+  // 2 be done
+  class MDB_Prism: public MDB_Region
+  {
+  public:
+    MDB_Triangle  *f1,*f2;
+    MDB_Quad      *f3,*f4,*f5;
+  
+    virtual int getOrder() const {return 2;}
+    virtual int getDim()   const {return 3;} /*SL OK*/
+
+    virtual int       getNbFace () const {return 5;} /*SL OK*/ 
+    virtual int       getNbEdge () const {return 9;} /*SL OK*/
+    virtual int       getNbVertex () const{return 6;} /*SL OK*/
+    virtual MDB_Face *getFace (int i) const /*SL OK*/
+    {
+      switch(i){
+      case 0:return f1;
+      case 1:return f2;
+      case 2:return f3;
+      case 3:return f4;
+      case 4:return f5;
+      case 5:return (MDB_Face *) NULL;
+      }
+      throw;
+    }
+    virtual MDB_Edge *getEdge (int n) const /*SL OK*/
+    {
+      switch (n){
+      case 0  : return f1->commonedge ( f3 );
+      case 1  : return f1->commonedge ( f5 );
+      case 2  : return f1->commonedge ( f4 );
+      case 3  : return f2->commonedge ( f3 );
+      case 4  : return f2->commonedge ( f5 );
+      case 5  : return f2->commonedge ( f4 );    
+      case 6  : return f3->commonedge ( f5 );    
+      case 7  : return f3->commonedge ( f4 );    
+      case 8  : return f4->commonedge ( f5 );       
+      }
+      throw;    
+    }
+  
+    virtual MDB_Point *getVertex (int n) const /*SL OK*/
+    {
+      MDB_Edge *e1=0,*e2=0; 
+      switch (n){
+      case 0 : e1 = getEdge(0);e2 = getEdge(1);break;
+      case 1 : e1 = getEdge(0);e2 = getEdge(2);break;
+      case 2 : e1 = getEdge(1);e2 = getEdge(2);break;
+      case 3 : e1 = getEdge(4);e2 = getEdge(3);break;
+      case 4 : e1 = getEdge(3);e2 = getEdge(5);break;
+      case 5 : e1 = getEdge(4);e2 = getEdge(5);break;
+      default: throw;
+      }
+      return e1->commonvertex ( e2 );
+    }
+
+    virtual int getFaceDir (int n) const
+    { std::cerr << "not yet implemented\n"; abort(); return 0;}
+
+
+    virtual void getNodes(MDB_Point **n) const
+    {
+      std::cerr << "not yet implemented\n"; abort();
+      /*    MDB_Point *o[3];
+            f1->getNodes(n);
+            f2->getNodes(o);    
+            n[3] = 0; //for stupid gcc warning
+            if(o[0] != n[0] && o[0] != n[1] &&o[0] != n[2])n[3] = o[0];
+            if(o[1] != n[0] && o[1] != n[1] &&o[1] != n[2])n[3] = o[1];
+            if(o[2] != n[0] && o[2] != n[1] &&o[2] != n[2])n[3] = o[2];*/
+    }
+  
+    MDB_Prism(MDB_Triangle *A, MDB_Triangle *B, MDB_Quad *C, 
+              MDB_Quad *D, MDB_Quad *E) /*SL OK*/
+      : f1(A),f2(B),f3(C),f4(D),f5(E)
+    { 
+      f1->addregion(this);
+      f2->addregion(this);
+      f3->addregion(this);
+      f4->addregion(this);
+      f5->addregion(this);
+    }
+    virtual ~MDB_Prism() {} /*SL OK*/
+  };
+
+  /*! \brief Generic order equidistant Lagrange tetrahedron */ 
+
+  template <int order>
+  class MDB_CompleteTet : public MDB_Tet {
+
+  public:
+
+    MDB_CompleteTet(MDB_Triangle *A, MDB_Triangle *B,
+                    MDB_Triangle *C, MDB_Triangle *D,MDB_Point** pp):
+    
+      MDB_Tet(A,B,C,D),nbPoints(std::max(0,(order-3)*(order-2)*(order-1)/6))
+    {
+      point = nbPoints ? new MDB_Point*[nbPoints] : NULL;
+      for (size_t i=0;i<(unsigned int)nbPoints;i++) point[i] = pp[i];
+    }
+    
+    int getNbHighOrderPoints() const {return nbPoints;}
+    MDB_Point* getHighOrderPoint(int i) {return (i<nbPoints) ? point[i] : NULL;}
+    int getOrder() {return order;}
+    
+    
+  protected:
+    int nbPoints;
+    MDB_Point** point;
+  };
+
+  class PointLessThan
+  {
+  public:
+    bool operator()(const MDB_Point* ent1, const MDB_Point* ent2) const
+    {
+      return *ent1 < *ent2;
+    }
+  };
+
+
+  class MDB_Mesh : public MDB_MiniMesh
+  {        
+    // no copies allowed
+    MDB_Mesh(const MDB_Mesh &other);
+
+  private:
+    bool parametric;
+
+  public:
+
+    // this is an add on to the classical interface
+    // one can build lists of geometrical "features" that
+    // encompass more than one geometrical entities
+    std::multimap<int, pGEntity > geomFeatures_Tags;
+    // sometimes, features have names
+    std::map<std::string, int >         geomFeatures_Names;
+
+    bool shrinked;
+
+    // constructor of an empty mesh
+    MDB_Mesh(int _MAXX = 1); 
+    // the destructor
+    ~MDB_Mesh();
+    // initialize first vertex id and increments
+    void initializeIdData();
+    // load the mini mesh into the binary file f, mesh is still empty
+    bool isParametric() const { return parametric; }
+    void load   ( FILE *f );
+    // expand the mini mesh in the bi directional data structure
+    // then, delete the mini mesh. Mesh adaptation can be performed
+    // only when the mesh is expanded 
+    void expand ( );
+    // shrink the mini mesh from the bi-directional data structure
+    // then, delete the bi-directional data structure. The mesh
+    // is "idle", i.e. is shrinked in memory, allowing the solver 
+    // to take the whole memory space
+    void shrink ( );
+    bool isShrinked() const { return shrinked; };
+    // flush the mini mesh
+    void flush ( FILE *f ) const;
+    // data about vertex ids (globally unique ids in parallel)
+    int maxId;       // max vertex id
+    int idIncrement; // id increment size (=nbProcs)
+    // the geometric model on which the mesh entities are classified
+    pGModel model; 
+    // bounding boxes
+    double Min[3],Max[3],LC;
+    // the datas
+    int nbPoints, nbEdgePoints, nbEdges, nbTriangles, nbQuads, nbTets, nbHexes, nbPrisms;
+    std::set<MDB_Point*,PointLessThan>     points; 
+    MDB_ListE edges; 
+    MDB_ListF triangles; 
+    MDB_ListQ quads; 
+    MDB_ListT tets; 
+    MDB_ListH hexes; 
+    MDB_ListPr prisms; 
+    // Points operations
+    MDB_Point * add_point(int num , double x, double y,double z, pGEntity=0);
+    MDB_PointParam * add_pointParam(int num , double x, double y, double z, 
+                                    double u, double v, pGEntity=0);
+    void del_point(MDB_Point *p);  
+    MDB_Point *find_point(int num);
+    void deleteTheHighOrderPoint(std::set < MDB_Point *, PointLessThan >::iterator it);
+    // Edges operations
+    /*! straight edge from point id's */
+    MDB_Edge  * add_edge(int p1, int p2, pGEntity=0);
+    //  MDB_Edge  * add_edge(int p1, int p2, int p3, pGEntity=0);
+    /*! straight edge from points */ 
+    MDB_Edge  * add_edge(MDB_Point *p1, MDB_Point *p2, pGEntity=0);
+    //  MDB_Edge  * add_edge(MDB_Point *p1, MDB_Point *p2, MDB_Point *p3, pGEntity=0);
+    /*! straight/curved edge from point id's */
+    MDB_Edge  * add_edge(int numberOfPoints, pGEntity pg, int p1, ...);
+    /*! straight/curved edge from points */
+    MDB_Edge  * add_edge(int numberOfPoints, pGEntity pg, MDB_Point *firstPoint, ...);
+    /*! straight/curved edge from points (gmsh order) */
+    MDB_Edge  * add_edge(MDB_Point* p1,MDB_Point*p2,pGEntity,int o,MDB_Point** iP);
+    void del_edge(MDB_Edge *e);
+    MDB_Edge  *find_edge(int p1, int p2);
+    MDB_Edge  *find_edge(MDB_Point *p1, MDB_Point *p2)const;
+    MDB_Edge  *find_edge(MDB_Point *p1, MDB_Point *p2, MDB_Triangle *t)const;
+    MDB_Edge  *find_clone_edge(MDB_Edge *edge)const;
+    // Faces operations
+    void del_face(MDB_Face *f);
+    // Triangles operations
+    /*! straight triangle from vertex id's */ 
+    MDB_Triangle *add_triangle(int p1, int p2, int p3, pGEntity=0); 
+    /* curvilinear triangle */
+    //  MDB_Triangle *add_triangle(int p1, int p2, int p3, int p4, int p5, int p6, pGEntity=0);
+    /*! straight/serendipity triangle from edges */
+    MDB_Triangle *add_triangle(MDB_Edge *e1,MDB_Edge *e2,MDB_Edge *e3, pGEntity=0);
+    /*! straight/complete triangle triangle from edges and internal points */
+    MDB_Triangle *add_triangle(MDB_Edge *e1,MDB_Edge *e2,MDB_Edge *e3, pGEntity,int order,
+                               bool serendip=true,MDB_Point** iP=NULL);
+    /*! straight/complete triangle triangle from point id's*/
+    //MDB_Triangle *add_triangle(pGEntity,int order,bool serendip=true,int* pp=NULL);
+    /*! straight/serendipity triangle from point id's */ 
+    MDB_Triangle *add_triangle(int order, bool complete, pGEntity pg, int p1, int p2, ...);
+    void del_triangle(MDB_Triangle *t);
+    MDB_Triangle  *find_triangle(MDB_Edge *e1,MDB_Edge *e2,MDB_Edge *e3);
+    // Quad operations
+    MDB_Quad *add_quad(int p1, int p2, int p3, int p4, pGEntity=0); 
+    MDB_Quad *add_quad(MDB_Edge *e1,MDB_Edge *e2,MDB_Edge *e3,MDB_Edge *e4, pGEntity=0);
+    void del_quad(MDB_Quad *q);
+    MDB_Quad  *find_quad(MDB_Edge *e1,MDB_Edge *e2,MDB_Edge *e3,MDB_Edge *e4);
+    // Tets operations
+    /*! straight tet from point id's */
+    MDB_Tet *add_tet(int p1, int p2, int p3,int p4, pGEntity=0);
+    /*! straight/serendipity/complete triangle from point id's (in gmsh order) */
+    MDB_Tet *add_tet(pGEntity,int order,bool serendip,int* points);
+    /*! straight tet from points */ 
+    MDB_Tet *add_tet(MDB_Point *p1, MDB_Point *p2,MDB_Point *p3, MDB_Point *p4, pGEntity=0);
+    /*! straight/serendipity tetrahedron from faces */
+    MDB_Tet *add_tet(MDB_Triangle  *,MDB_Triangle  *,MDB_Triangle  *,MDB_Triangle  *, pGEntity=0);
+    /*! straight/complete tetrahedron from faces and points */
+    MDB_Tet *add_tet(MDB_Triangle  *,MDB_Triangle  *,MDB_Triangle  *,MDB_Triangle  *, pGEntity,
+                     int order,bool serendip=true,MDB_Point** iP=NULL);
+  
+    /*! straight/complete tet from faces and internal point id's */
+    MDB_Tet *find_tet(MDB_Triangle * t1, MDB_Triangle * t2, MDB_Triangle * t3,  MDB_Triangle * t4);
+    void del_tet(MDB_Tet *);
+    // Hexes operations
+    MDB_Hex *add_hex(int p1, int p2, int p3,int p4,int p5, int p6, int p7, int p8, pGEntity=0);
+    MDB_Hex *add_hex(MDB_Point *p1, MDB_Point *p2,MDB_Point *p3, MDB_Point *p4,
+                     MDB_Point *p5, MDB_Point *p6,MDB_Point *p7, MDB_Point *p8, pGEntity=0);
+    MDB_Hex *add_hex(MDB_Quad  *,MDB_Quad  *,MDB_Quad  *,MDB_Quad  *,MDB_Quad  *,MDB_Quad  *, pGEntity=0);
+    MDB_Hex *find_hex(MDB_Quad  *,MDB_Quad  *,MDB_Quad  *,MDB_Quad  *,MDB_Quad  *,MDB_Quad  *);
+    void del_hex(MDB_Hex *);
+    // Prisms operations
+    MDB_Prism *add_prism(int p1, int p2, int p3,int p4,int p5, int p6, pGEntity=0);
+    MDB_Prism *add_prism(MDB_Point *p1, MDB_Point *p2,MDB_Point *p3, 
+                         MDB_Point *p4, MDB_Point *p5, MDB_Point *p6, pGEntity=0);
+    MDB_Prism *add_prism(MDB_Triangle  *,MDB_Triangle  *,MDB_Quad  *,MDB_Quad  *,MDB_Quad  *, pGEntity=0);
+    MDB_Prism *find_prism(MDB_Triangle  *,MDB_Triangle  *,MDB_Quad  *,MDB_Quad  *,MDB_Quad  *);
+    void del_prism(MDB_Prism *);
+    // classify entities that are not classified
+    void classify_unclassified_entities();
+    void destroyStandAloneEntities();
+
+// #ifdef PARALLEL
+//     void bdryLinkRemotePoint();
+// #endif  
+    
+    // check if there is no identical geometrical tags between regions and faces
+    /*   void checkGeomTagsCoherence () const; */
+  };
+
+  typedef std::set<MDB_Point*,PointLessThan> MDB_SetV;
+
+  class MDB_RIter : public MDB_Iter < MDB_ListR , MDB_Region , pGEntity>
+  {
+  public:
+    MDB_RIter (MDB_ListR*_l): MDB_Iter< MDB_ListR , MDB_Region , pGEntity > (_l){}
+    MDB_RIter (MDB_ListR*_l,pGEntity _g): MDB_Iter< MDB_ListR , MDB_Region , pGEntity > (_l,_g){}
+  };
+  class MDB_TIter : public MDB_Iter < MDB_ListT , MDB_Tet , pGEntity>
+  {
+  public:
+    MDB_TIter (MDB_ListT*_l): MDB_Iter< MDB_ListT , MDB_Tet , pGEntity > (_l){}
+    MDB_TIter (MDB_ListT*_l,pGEntity _g): MDB_Iter< MDB_ListT , MDB_Tet , pGEntity > (_l,_g){}
+  };
+  class MDB_HIter : public MDB_Iter < MDB_ListH , MDB_Hex , pGEntity>
+  {
+  public:
+    MDB_HIter (MDB_ListH*_l): MDB_Iter< MDB_ListH , MDB_Hex , pGEntity > (_l){}
+    MDB_HIter (MDB_ListH*_l,pGEntity _g): MDB_Iter< MDB_ListH , MDB_Hex , pGEntity > (_l,_g){}
+  };
+  class MDB_PIter : public MDB_Iter < MDB_ListPr , MDB_Prism , pGEntity>
+  {
+  public:
+    MDB_PIter (MDB_ListPr*_l): MDB_Iter< MDB_ListPr , MDB_Prism , pGEntity > (_l){}
+    MDB_PIter (MDB_ListPr*_l,pGEntity _g): MDB_Iter< MDB_ListPr , MDB_Prism , pGEntity > (_l,_g){}
+  };
+  class MDB_EIter : public MDB_Iter < MDB_ListE , MDB_Edge , pGEntity >
+  {
+  public:
+    MDB_EIter (MDB_ListE*_l): MDB_Iter< MDB_ListE , MDB_Edge, pGEntity > (_l){}
+    MDB_EIter (MDB_ListE*_l,pGEntity _g,int _c): MDB_Iter< MDB_ListE , MDB_Edge, pGEntity > (_l,_g,_c){}
+  };
+  class MDB_FIter : public MDB_Iter < MDB_ListF , MDB_Triangle , pGEntity >
+  {
+  public:
+    MDB_FIter (MDB_ListF*_l): MDB_Iter <MDB_ListF , MDB_Triangle ,pGEntity> (_l){}
+    MDB_FIter (MDB_ListF*_l,pGEntity _g,int _c): MDB_Iter <MDB_ListF , MDB_Triangle ,pGEntity> (_l,_g,_c){}
+  };
+  class MDB_QIter : public MDB_Iter < MDB_ListQ , MDB_Quad , pGEntity>
+  {
+  public:
+    MDB_QIter (MDB_ListQ*_l): MDB_Iter <MDB_ListQ , MDB_Quad , pGEntity> (_l){}
+    MDB_QIter (MDB_ListQ*_l,pGEntity _g,int _c): MDB_Iter <MDB_ListQ , MDB_Quad ,pGEntity> (_l,_g,_c){}
+  };
+  class MDB_VIter : public MDB_Iter < MDB_SetV , MDB_Point ,pGEntity >
+  {
+  public:
+    MDB_VIter (MDB_SetV *_l): MDB_Iter < MDB_SetV , MDB_Point , pGEntity > (_l){}
+    MDB_VIter (MDB_SetV *_l,pGEntity _g,int _c): MDB_Iter < MDB_SetV , MDB_Point , pGEntity > (_l,_g,_c){}
+  };
+
+  class MDB_FaceIter
+  {
+  public:
+    MDB_FIter itf;
+    MDB_QIter itq;
+
+    MDB_Triangle *t;
+    MDB_Quad *q;
+  public:
+    MDB_FaceIter ( MDB_ListF* _t , MDB_ListQ* _q):itf(_t),itq(_q),t(0),q(0){}
+    MDB_FaceIter ( MDB_ListF* _t , MDB_ListQ* _q, pGEntity _g,int _c):itf(_t,_g,_c),itq(_q,_g,_c),t(0),q(0){}
+    inline MDB_Face * next ()
+    {
+      t = itf.next();
+      if (t) return (MDB_Face*)t;
+      q = itq.next();
+      return (MDB_Face*)q;
+    }
+    inline void reset()
+    {
+      itf.reset();
+      itq.reset();
+    }
+    inline void cleanup()
+    {
+      itf.cleanup();
+      itq.cleanup();
+    }
+
+  };
+
+  class MDB_RegionIter
+  {
+  public:
+    MDB_TIter itt;
+    MDB_HIter ith;
+    MDB_PIter itp;
+
+    MDB_Tet *t;
+    MDB_Hex *h;
+    MDB_Prism *p;
+  public:
+    MDB_RegionIter ( MDB_ListT* _t , MDB_ListH* _h, MDB_ListPr* _p ):itt(_t),ith(_h),itp(_p),t(0),h(0),p(0){}
+    MDB_RegionIter ( MDB_ListT* _t , MDB_ListH* _h, MDB_ListPr* _p, pGEntity _g):itt(_t,_g),ith(_h,_g),itp(_p,_g),t(0),h(0),p(0){}
+    inline MDB_Region * next ()
+    {
+      t = itt.next();
+      if (t) return (MDB_Region*)t;
+      h = ith.next();
+      if (h) return (MDB_Region*)h;
+      p = itp.next();
+      return (MDB_Region*)p;
+    }
+    inline void reset()
+    {
+      itt.reset();
+      ith.reset();
+      itp.reset();
+    }
+    inline void cleanup()
+    {
+      itt.cleanup();
+      ith.cleanup();
+      itp.cleanup();
+    }
+
+  };
+
+} // End of namespace MAd
+
+#endif
+
+
+
+
+
+
diff --git a/Mesh/MeshDataBaseAttachable.h b/Mesh/MeshDataBaseAttachable.h
new file mode 100644
index 0000000..10271a8
--- /dev/null
+++ b/Mesh/MeshDataBaseAttachable.h
@@ -0,0 +1,176 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _MATTACHABLEDATACONTAINER_H_
+#define _MATTACHABLEDATACONTAINER_H_
+
+#include <algorithm>
+#include <vector>
+
+namespace MAd {
+
+  /**
+     Base class for attachable data's
+  */
+  class mAttachableData
+  {
+  public :
+    virtual ~mAttachableData(){};
+  };
+
+  class mAttachableVoid : public mAttachableData
+  {
+  public :
+    ~mAttachableVoid(){}
+    void *veryNastyPointer;
+  };
+
+  /**
+     Int as attachable data
+  */
+  class mAttachableInt : public mAttachableData
+  {
+  public :
+    ~mAttachableInt(){}
+    int i;
+  };
+
+  /**
+     Double as attachable data
+  */
+  class mAttachableDouble : public mAttachableData
+  {
+  public :  
+    ~mAttachableDouble(){}
+    double d;
+  };
+
+  /**
+     Container for attachable data's Internal, mEntity and mMesh provides interfaces.
+  */
+
+  class mAttachableDataContainer  
+  {
+  public :
+    typedef std::pair <unsigned int, mAttachableData *> info;
+    typedef std::vector< info > container;
+    typedef container::iterator iter_attachdata;
+    typedef container::const_iterator citer_attachdata;
+  private :
+    container *tab;
+  public:
+    mAttachableDataContainer():tab(0){}
+    ~mAttachableDataContainer();
+    inline void attachData(unsigned int, mAttachableData *);
+    inline void deleteData(unsigned int);
+    inline mAttachableData * getData(unsigned int) ;
+    inline citer_attachdata begin_attachdata() const {return tab->begin();};
+    inline citer_attachdata end_attachdata() const {return tab->end();};	
+    /// specific data types for int
+    inline void attachInt(unsigned int, int);
+    /// specific data types for int
+    inline int getAttachedInt(unsigned int);
+    /// specific data types for double
+    inline void attachDouble(unsigned int, double);
+    /// specific data types for double
+    inline double getAttachedDouble(unsigned int);
+  };
+
+  class equalInfoPred
+  {
+    const unsigned int c;
+  public:
+    equalInfoPred ( unsigned int i ) :c(i) {}
+    inline bool operator () (const mAttachableDataContainer::info &i) const
+    {
+      return (i.first == c);
+    }
+  };
+
+  inline mAttachableDataContainer::~mAttachableDataContainer()
+  {
+    if(!tab)return;
+    citer_attachdata it = begin_attachdata();
+    citer_attachdata itEnd = end_attachdata();
+    for(;it!=itEnd;++it)
+      {
+        mAttachableData *a = (*it).second;
+        delete a;
+      }
+    delete tab;
+  }
+
+  inline mAttachableData *mAttachableDataContainer::getData(unsigned int c) 
+  {
+    if (!tab)return 0;
+    iter_attachdata it = std::find_if (tab->begin(),tab->end(),equalInfoPred(c));
+    if(it == tab->end())return 0;
+    return (*it).second;
+  }
+
+  inline void mAttachableDataContainer::attachData(unsigned int c, mAttachableData *v)
+  {
+    if (!tab) tab = new container;
+    tab->push_back(mAttachableDataContainer::info(c,v));
+  }
+
+  inline void mAttachableDataContainer::deleteData(unsigned int c)
+  {
+    mAttachableData *data = getData (c);
+    if (data)
+      {
+        delete data;
+        tab->erase ( std::remove_if (tab->begin(),tab->end(),equalInfoPred(c)) , 
+                     tab->end () );
+      }
+  }
+
+  inline void mAttachableDataContainer::attachInt(unsigned int c, int i)
+  {
+    mAttachableInt *ai = (mAttachableInt *)getData(c);
+    if(!ai)
+      {
+        ai = new mAttachableInt;
+        attachData(c,ai);
+      }
+    ai->i = i;
+  }
+
+  inline int mAttachableDataContainer::getAttachedInt (unsigned int c)
+  {
+    mAttachableInt *ai = (mAttachableInt *)getData(c);
+    if(!ai)return 0;
+    return ai->i;
+  }
+
+  inline void mAttachableDataContainer::attachDouble(unsigned int c, double d)
+  {
+    mAttachableDouble *ai = (mAttachableDouble *)getData(c);
+    if(!ai)
+      {
+        ai = new mAttachableDouble;
+        attachData(c,ai);
+      }
+    ai->d = d;
+  }
+
+  inline double mAttachableDataContainer::getAttachedDouble (unsigned int c)
+  {
+    mAttachableDouble *ai = (mAttachableDouble *)getData(c);
+    if(!ai)return 0;
+    return ai->d;
+  }
+
+} // End of namespace MAd
+
+#endif
diff --git a/Mesh/MeshDataBaseComm.cc b/Mesh/MeshDataBaseComm.cc
new file mode 100644
index 0000000..5cce89c
--- /dev/null
+++ b/Mesh/MeshDataBaseComm.cc
@@ -0,0 +1,899 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "MSops.h"
+#include "MeshDataBase.h"
+#ifdef PARALLEL
+#include "MeshDataBaseParallelInterface.h"
+#endif
+// #include "NullModel.h"
+#include "MeshDataBaseComm.h"
+
+
+#include "assert.h"
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+#endif
+
+// for memcpy  (gcc 4.3) 
+#include <cstring>
+
+namespace MAd {
+
+  void exchangeDataOnVertices (pMesh m, MDB_DataExchanger &de )
+  { 
+  
+    int mysize = 1;
+    int myrank = 0;
+
+#ifdef PARALLEL
+    MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank); 
+#endif    
+    
+    int *sendcounts = new int[mysize];
+    for(int i=0;i<mysize;i++)sendcounts[i]=0;
+  
+    pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+    VIter vit = M_vertexIter(m);
+    pVertex pv;  
+    while ((pv = VIter_next(vit))) {
+      void *temp_ptr; 
+      int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+      
+      if(isInterface) {
+        const std::vector<std::pair<int , pVertex> > *recup = 
+          (const std::vector<std::pair<int , pVertex> > *) temp_ptr;
+        
+        for(unsigned int j=0 ; j<(*recup).size() ; j++) {    
+          
+          
+          
+          int sizebuf;      
+          int iProc = (*recup)[j].first;
+          pVertex remote = (*recup)[j].second;
+    
+          void *buf = de.sendData ((pEntity) pv, iProc, sizebuf );
+          if (buf)
+          {
+            if (iProc == myrank)
+            {
+              de.receiveData ((pEntity) remote, myrank,buf);
+              free(buf);
+            }
+            else
+            {
+#ifdef PARALLEL
+              char *msg = (char*)AP_alloc(iProc,de.tag(),sizeof(pEntity*)+sizebuf);
+              memcpy(msg,&remote,sizeof(pEntity*));
+              memcpy(&msg[sizeof(pEntity*)],buf,sizebuf);
+              free(buf);
+              AP_send(msg);
+              sendcounts[iProc] ++;
+#else
+              throw;
+#endif
+            }
+          } 
+        }
+      }
+    }      
+    VIter_delete(vit);  
+#ifdef PARALLEL 
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+  
+    int message=0;
+    int count;
+  
+    while (!AP_recv_count(&count) || message<count) 
+      {
+        void *msg;
+        int from;
+        int tag;
+        int size;
+        int rc;
+        rc=AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+                   &msg, &size, &from, &tag);
+        if (rc) 
+          {
+            message++;
+            char * tmp = (char *) msg;
+            pEntity * pv = (pEntity *) &tmp[0];
+#ifdef DEBUG	  
+            assert(*pv);
+#endif
+            de.receiveData (*pv,from, &tmp[sizeof(pEntity*)]);
+            AP_free(msg);
+          }
+      }    
+
+    AP_check_sends(AP_WAITALL); 
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+
+    delete [] sendcounts;
+  }
+
+  // ----------------------------------------------------------------------------
+  
+  void exchangeDataOnEdges (pMesh m, MDB_DataExchanger &de )
+  { 
+    int mysize = 1;
+    int myrank = 0;
+
+#ifdef PARALLEL
+    MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+#endif    
+  
+    int *sendcounts = new int[mysize];
+    for(int i=0;i<mysize;i++)sendcounts[i]=0;
+    
+    pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+    EIter eit = M_edgeIter(m);
+    pEdge pe;  
+    while (pe = EIter_next(eit)) {
+
+      void* tmpptr = NULL;
+      if (EN_getDataPtr(pe,tagData,&tmpptr)) {
+        
+        std::multimap<int,pEdge>* connections = (std::multimap<int,pEdge>*) tmpptr;
+        std::multimap<int,pEdge>::iterator cIter = connections->begin();
+        
+        
+        for (;cIter!=connections->end();++cIter) {
+          
+          int iProc = cIter->first;
+          pEdge remote = cIter->second;
+          int sizebuf = 0;
+          void *buf = de.sendData ((pEntity) pe, iProc, sizebuf );
+          size_t sendSize = sizebuf + sizeof(pEntity*);
+  
+          if (iProc == myrank) de.receiveData ((pEntity) cIter->second,myrank,buf);
+          else {
+#ifdef PARALLEL
+            char *msg = (char*)AP_alloc(iProc,de.tag(),sendSize);
+            memcpy(&msg[0],&remote,sizeof(pEntity));
+            memcpy(&msg[sizeof(pEntity)],buf,sizebuf);
+            AP_send(msg);
+            sendcounts[iProc] ++;
+#else
+            throw;
+#endif
+          }
+          free(buf); 
+        }
+      }
+    }
+
+    EIter_delete(eit);
+              
+
+#ifdef PARALLEL 
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+  
+    int message=0;
+    int count;
+  
+    while (!AP_recv_count(&count) || message<count) 
+      {
+        void *msg;
+        int from;
+        int tag;
+        int size;
+        int rc;
+        rc=AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+                   &msg, &size, &from, &tag);
+        if (rc) 
+          {
+            message++;
+            char * tmp = (char *) msg;
+            pEdge pe;
+            memcpy(&pe,&tmp[0],sizeof(pEntity));
+            de.receiveData ((pEntity) pe,from, &tmp[sizeof(pEntity*)]);
+            AP_free(msg);
+          }
+      }    
+    AP_check_sends(AP_WAITALL); 
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+    delete [] sendcounts;
+  }
+
+  // ----------------------------------------------------------------------------
+
+  void exchangeDataOnFaces (pMesh m, MDB_DataExchanger &de )
+  { 
+    
+    int mysize = 1;
+    int myrank = 0;
+
+#ifdef PARALLEL
+    MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+#endif    
+  
+    int *sendcounts = new int[mysize];
+    for(int i=0;i<mysize;i++)sendcounts[i]=0;
+    
+    pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+    FIter fit = M_faceIter(m);
+    pFace pf;  
+    while (pf = FIter_next(fit)) {
+
+      void* tmpptr = NULL;
+      if (EN_getDataPtr((pEntity) pf,tagData,&tmpptr)) {
+        
+        std::multimap<int,pFace>* connections = (std::multimap<int,pFace>*) tmpptr;
+        std::multimap<int,pFace>::iterator cIter = connections->begin();
+        
+        
+        for (;cIter!=connections->end();++cIter) {
+          
+          int iProc = cIter->first;
+          pFace remote = cIter->second;
+          int sizebuf = 0;
+          void *buf = de.sendData ((pEntity) pf, iProc, sizebuf );
+          size_t sendSize = sizebuf + sizeof(pEntity*);
+  
+          if (iProc == myrank) de.receiveData ((pEntity) cIter->second,myrank,buf);
+          else {
+            
+#ifdef PARALLEL
+            char *msg = (char*)AP_alloc(iProc,de.tag(),sendSize);
+            memcpy(&msg[0],&remote,sizeof(pEntity));
+            memcpy(&msg[sizeof(pEntity)],buf,sizebuf);
+            AP_send(msg);
+            sendcounts[iProc] ++;
+#else
+            throw;
+#endif
+          }
+          free(buf); 
+        }
+      }
+    }
+    FIter_delete(fit);
+
+#ifdef PARALLEL 
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+  
+    int message=0;
+    int count;
+  
+    while (!AP_recv_count(&count) || message<count) 
+      {
+        void *msg;
+        int from;
+        int tag;
+        int size;
+        int rc;
+        rc=AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+                   &msg, &size, &from, &tag);
+        if (rc) 
+          {
+            message++;
+            char * tmp = (char *) msg;
+            pEdge pe;
+            memcpy(&pe,&tmp[0],sizeof(pEntity));
+            de.receiveData ((pEntity) pe,from, &tmp[sizeof(pEntity*)]);
+            AP_free(msg);
+          }
+      }    
+    AP_check_sends(AP_WAITALL); 
+    MPI_Barrier(MPI_COMM_WORLD);
+#endif
+    delete [] sendcounts;
+  }
+
+
+//   void exchangeDataOnEdges_old (pMesh m, MDB_DataExchanger &de )
+//   { 
+
+//     int mysize = 1;
+//     int myrank = 0;
+// #ifdef PARALLEL
+//     MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+//     MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+// #endif    
+  
+//     int *sendcounts = new int[mysize];
+//     for(int i=0;i<mysize;i++)sendcounts[i]=0;
+  
+//     pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+//     EIter eit = M_edgeIter(m);
+//     pEdge pe;  
+//     while ((pe = EIter_next(eit))) {
+// #ifdef PARALLEL
+//       int distProc = -1;
+//       std::vector<pVertex> distVt;
+
+//       /// E_isInterface should be replaced by correct version or by direct use of the remotePoint
+//         if ( E_isInterface(m,pe,&distProc,&distVt) ) {
+     
+//           //		void * tmp_ptr;
+//           //    if( EN_getDataPtr((pEntity) pe, tagData, &tmp_ptr) ){
+// #endif
+//           pVertex p1 = pe->p1;
+//           pVertex p2 = pe->p2;
+//           assert(p1); assert(p2);
+//           void *temp_ptr1,*temp_ptr2; 
+//           EN_getDataPtr((pEntity) p1 , tagData, &temp_ptr1);
+//           EN_getDataPtr((pEntity) p2 , tagData, &temp_ptr2);       
+//           const std::vector<std::pair<int , pVertex> > *recup1 = 
+//             (const std::vector<std::pair<int , pVertex> > *) temp_ptr1;
+//           const std::vector<std::pair<int , pVertex> > *recup2 = 
+//             (const std::vector<std::pair<int , pVertex> > *) temp_ptr2;
+//           int size = (*recup1).size();
+//           assert(size);
+//           int tab[1024];
+//           for(int i=0 ; i< size ; i++) tab[i] = (*recup1)[i].first;
+	
+//           for(unsigned int j=0 ; j<(*recup2).size() ; j++) {    
+//             int iProc = (*recup2)[j].first;
+//             int i;
+//             for(i=0 ; i<size ; i++) {
+//               if(iProc == tab[i]) break;
+//             }
+//             if(i < size) {
+//               assert(iProc == tab[i]);
+	    
+//               int sizebuf;
+//               pVertex remote1 = (*recup1)[i].second;
+//               pVertex remote2 = (*recup2)[j].second;
+//               void *buf = de.sendData ((pEntity) pe, iProc, sizebuf );
+//               if (buf)
+//                 {
+//                   if (iProc == myrank)
+//                     {
+//                       puts("*****************************pas parallele");
+//                       char *msg = (char*)malloc(2*sizeof(pEntity)+sizebuf);
+//                       memcpy(msg,&remote1,sizeof(pEntity));
+//                       memcpy(&msg[sizeof(pEntity)],&remote2,sizeof(pEntity));
+//                       memcpy(&msg[2*sizeof(pEntity)],buf,sizebuf);
+//                       free(buf);
+//                       MDB_VectorE ve = remote1->edges;
+//                       MDB_VectorE::iterator it  = ve.begin();
+//                       MDB_VectorE::iterator ite = ve.end();
+//                       while(it!=ite){
+//                         if((*it)->p1 == remote1 && (*it)->p2 == remote2)break;
+//                         else if ((*it)->p2 == remote1 && (*it)->p1 == remote2) break;
+//                         ++it;
+//                       }
+//                       assert(it!=ite);
+//                       pEdge pe = *it;
+//                       de.receiveData ((pEntity) pe, 
+//                                       myrank,
+//                                       msg);
+//                       free(msg);
+//                     }
+//                   else
+//                     {
+// #ifdef PARALLEL
+//                       char *msg = (char*)AP_alloc(iProc, 
+//                                                   de.tag() , 
+//                                                   2*sizeof(pEntity*)+sizebuf);			   
+//                       memcpy(&msg[0],&remote1,sizeof(pEntity));
+//                       memcpy(&msg[sizeof(pEntity)],&remote2,sizeof(pEntity));
+//                       memcpy(&msg[2*sizeof(pEntity)],buf,sizebuf);
+//                       free(buf);
+//                       AP_send(msg);
+//                       sendcounts[iProc] ++;
+// #else
+//                       throw;
+// #endif
+//                     } 
+//                 } 
+//             }
+//           }
+// #ifdef PARALLEL
+//         }
+// #endif
+//     }      
+//     EIter_delete(eit);  
+
+// #ifdef PARALLEL 
+//     AP_check_sends(AP_NOFLAGS);
+//     AP_reduce_nsends(sendcounts);
+  
+//     int message=0;
+//     int count;
+  
+//     while (!AP_recv_count(&count) || message<count) 
+//       {
+//         void *msg;
+//         int from;
+//         int tag;
+//         int size;
+//         int rc;
+//         rc=AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+//                    &msg, &size, &from, &tag);
+//         if (rc) 
+//           {
+//             message++;
+//             char * tmp = (char *) msg;
+//             pVertex v1;
+//             pVertex v2;
+//             memcpy(&v1,&tmp[0],sizeof(pEntity));
+//             memcpy(&v2,&tmp[sizeof(pEntity)],sizeof(pEntity));
+
+//             MDB_VectorE &ve = v1->edges;
+//             MDB_VectorE::iterator it  = ve.begin();
+//             MDB_VectorE::iterator ite = ve.end();
+//             while(it!=ite){
+//               if((*it)->p2 == (v2) || (*it)->p1 == (v2)) 
+//                 {
+//                   assert((*it)->p2 == (v1) || (*it)->p1 == (v1));
+//                   break;
+//                 }    
+//               ++it;
+//             }
+//             // MISTAKE HERE, CECILE, YOU SHOULD VERIFY THAT !!
+//             if(it==ite)
+//               {
+//                 // 	    printf("the edge does not exist here...\n");
+//                 //	    throw;
+//               }
+//             else
+//               {
+//                 pEdge pe = *it;
+	      
+//                 /*
+//                   Little test : if edges are reversed on the
+//                   different sides of the interface then reverse
+//                   the ones on the smallest processor
+//                 */		
+//                 if (v1 == pe->p2 && from < myrank)
+//                   {
+//                     pe->p1 = v1;
+//                     pe->p2 = v2;
+//                   } 
+//                 // ------- END OF TEST ------------------------
+
+
+//                 de.receiveData ((pEntity) pe,from, &tmp[2*sizeof(pEntity*)]);
+//               }
+//             AP_free(msg);
+//           }
+//       }    
+//     AP_check_sends(AP_WAITALL); 
+//     MPI_Barrier(MPI_COMM_WORLD);
+// #endif
+//     delete [] sendcounts;
+//   }
+
+
+  // ---------------------------------------------------------------------
+  /*
+    The parallel faces are supposed to be classified on a geometric entity 
+    of dimension 2 with the same tag as the unique volume entity which 
+    supports the face on this partition. This is done when a mesh is 
+    partitioned with japp.
+  */
+//   void exchangeDataOnFaces_old (pMesh m, MDB_DataExchanger &de )
+//   {
+//     exchangeDataOnTriangles(m, de);
+//     exchangeDataOnQuads(m, de);
+//   }
+
+//   void exchangeDataOnTriangles (pMesh m, MDB_DataExchanger &de )
+//   { 
+//     int mysize = 1;
+//     int myrank = 0;
+    
+// #ifdef PARALLEL
+//     MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+//     MPI_Comm_rank(MPI_COMM_WORLD, &myrank); 
+// #endif    
+  
+//     // --------------------------------------------------------
+//     // --- SEND -----------------------------------------------
+//     // --------------------------------------------------------
+  
+//     int *sendcounts = new int[mysize];
+//     for(int i=0;i<mysize;i++) sendcounts[i]=0;
+  
+//     pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+//     //  FIter fit = M_faceIter(m);
+//     MDB_FIter fit(&m->triangles);
+//     pFace pface;  
+//     //  while ((pface = FIter_next(fit))) {
+//     while (( pface = fit.next() )) {
+//       pVertex nod[3];
+//       pface->getNodes(nod);
+//       pVertex p1 = nod[0];
+//       pVertex p2 = nod[1];
+//       pVertex p3 = nod[2];
+//       void *temp_ptr1,*temp_ptr2,*temp_ptr3; 
+//       int isInterface1 = EN_getDataPtr((pEntity) p1 , tagData, &temp_ptr1);
+//       int isInterface2 = EN_getDataPtr((pEntity) p2 , tagData, &temp_ptr2);
+//       int isInterface3 = EN_getDataPtr((pEntity) p3 , tagData, &temp_ptr3);
+//       if(isInterface1 && isInterface2 && isInterface3) {
+//         const std::vector<std::pair<int , pVertex> > *recup1 = 
+//           (const std::vector<std::pair<int , pVertex> > *) temp_ptr1;
+//         const std::vector<std::pair<int , pVertex> > *recup2 = 
+//           (const std::vector<std::pair<int , pVertex> > *) temp_ptr2;
+//         const std::vector<std::pair<int , pVertex> > *recup3 = 
+//           (const std::vector<std::pair<int , pVertex> > *) temp_ptr3;
+//         int size = (*recup1).size();
+//         int *tab=new int[size];
+//         for(int i=0 ; i< size ; i++) tab[i] = (*recup1)[i].first;
+      
+//         int size2 = (*recup2).size();
+//         int *tab2=new int[size2];
+//         for(int i=0 ; i< size2 ; i++) tab2[i] = (*recup2)[i].first;
+      
+//         for(unsigned int k=0 ; k<(*recup3).size() ; k++) {  
+//           // the 3 vertices could belong to 3 identical procs at the same time and the face 
+//           // belongs to only 2 of those. In this case 2 packets are sent. We have to 
+//           // ignore the 'wrong' packet at reception. (Done)
+//           int iProc = (*recup3)[k].first;
+//           int i;
+//           for(i=0 ; i<size ; i++) {
+//             if(iProc == tab[i]) break;
+//           }
+//           int j;
+//           for(j=0 ; j<size2 ; j++) {
+//             if(iProc == tab2[j]) break;
+//           }
+//           if(i < size && j < size2) {
+//             assert(tab[i]==iProc);
+//             assert(tab2[j]==iProc);
+	      
+//             int sizebuf;
+          
+//             pVertex remote1 = (*recup1)[i].second;
+//             pVertex remote2 = (*recup2)[j].second;
+//             pVertex remote3 = (*recup3)[k].second;
+	  
+//             void *buf = de.sendData ((pEntity) pface, iProc, sizebuf );
+//             if (buf) {
+//               if (iProc == myrank) {
+//                 puts("*****************************pas parallele");
+//                 char *msg = (char*)malloc(3*sizeof(pEntity*)+sizebuf);
+//                 memcpy(msg,&remote1,sizeof(pEntity*));
+//                 memcpy(&msg[sizeof(pEntity*)],&remote2,sizeof(pEntity*));
+//                 memcpy(&msg[2*sizeof(pEntity*)],&remote3,sizeof(pEntity*));
+//                 memcpy(&msg[3*sizeof(pEntity*)],buf,sizebuf);
+//                 free(buf);
+//                 MDB_ListF vf;
+//                 remote1->getTriangles(vf);
+//                 MDB_ListF::iterator it  = vf.begin();
+//                 MDB_ListF::iterator ite = vf.end();
+//                 while(it!=ite){
+//                   pVertex nod[3];
+//                   (*it)->getNodes(nod);
+//                   if((nod[0] == remote1 || nod[1] == remote1 || nod[2] == remote1)&& 
+//                      (nod[0] == remote2 || nod[1] == remote2 || nod[2] == remote2)&&
+//                      (nod[0] == remote3 || nod[1] == remote3 || nod[2] == remote3))break;
+//                   ++it;
+//                 }
+//                 assert(it!=ite);
+//                 pFace pface = *it;
+//                 de.receiveData ((pEntity) pface, 
+//                                 myrank,
+//                                 msg);
+//                 free(msg); 
+//               }
+//               else {
+// #ifdef PARALLEL
+//                 char *msg = (char*)AP_alloc(iProc, 
+//                                             de.tag() , 
+//                                             3*sizeof(pEntity*)+sizebuf);
+//                 memcpy(&msg[0],&remote1,sizeof(pEntity*));
+//                 memcpy(&msg[sizeof(pEntity*)],&remote2,sizeof(pEntity*));
+//                 memcpy(&msg[2*sizeof(pEntity*)],&remote3,sizeof(pEntity*));
+//                 memcpy(&msg[3*sizeof(pEntity*)],buf,sizebuf);
+//                 free(buf);
+//                 AP_send(msg);
+//                 sendcounts[iProc]++;
+// #else
+//                 throw;
+// #endif
+//               } 
+//             }
+//           }
+//         }
+//         delete []tab;
+//         delete []tab2;
+//       }
+//     }      
+//     //  FIter_delete(fit);  
+// #ifdef PARALLEL
+//     // #ifdef MDB_DEBUG
+//     //   MPI_Barrier( MPI_COMM_WORLD );
+//     //   AP_check_sends(AP_WAITDEFER);
+//     // #else
+//     AP_check_sends(AP_NOFLAGS);
+//     // #endif
+//     AP_reduce_nsends(sendcounts);
+  
+//     // --------------------------------------------------------
+//     // --- RECEIVE --------------------------------------------
+//     // --------------------------------------------------------
+  
+//     int message=0;
+//     int count;
+
+//     while (!AP_recv_count(&count) || message<count) 
+//       {
+//         void *msg;
+//         int from;
+//         int tag;
+//         int size;
+//         int rc;
+//         rc=AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+//                    &msg, &size, &from, &tag);
+//         if (rc) 
+//           {
+//             message++;
+//             char * tmp = (char *) msg;
+//             pVertex * pv1 = (pVertex *) &tmp[0];
+//             pVertex * pv2 = (pVertex *) &tmp[sizeof(pEntity*)];
+//             pVertex * pv3 = (pVertex *) &tmp[2*sizeof(pEntity*)];
+//             MDB_ListF vf;
+//             (*pv1)->getTriangles(vf);
+//             MDB_ListF::iterator it  = vf.begin();
+//             MDB_ListF::iterator ite = vf.end();
+//             while(it!=ite){
+//               pVertex nod[3];
+//               (*it)->getNodes(nod);
+//               if((nod[0] == (*pv2) || nod[1] == (*pv2) || nod[2] == (*pv2))&&
+//                  (nod[0] == (*pv3) || nod[1] == (*pv3) || nod[2] == (*pv3))) {
+//                 assert((nod[0] == (*pv1) || nod[1] == (*pv1) || nod[2] == (*pv1)));
+//                 break;
+//               }
+//               ++it;
+//             }
+//             // this can happen: see the comment above in the send part.
+//             if ( it == ite ){
+//               AP_free(msg);
+//             }
+//             else {
+//               pFace pface = *it;
+//               de.receiveData ((pEntity) pface,from, &tmp[3*sizeof(pEntity*)]);
+//               AP_free(msg);
+//             }
+//           }
+//       }    
+//     AP_check_sends(AP_WAITALL); 
+//     MPI_Barrier(MPI_COMM_WORLD);
+// #endif
+//     delete [] sendcounts;
+//   }
+
+//   void exchangeDataOnQuads (pMesh m, MDB_DataExchanger &de )
+//   { 
+//     int mysize = 1;
+//     int myrank = 0;
+    
+// #ifdef PARALLEL
+//     MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+//     MPI_Comm_rank(MPI_COMM_WORLD, &myrank); 
+ 
+// #endif    
+  
+//     // --------------------------------------------------------
+//     // --- SEND -----------------------------------------------
+//     // --------------------------------------------------------
+  
+//     int *sendcounts = new int[mysize];
+//     for(int i=0;i<mysize;i++) sendcounts[i]=0;
+  
+//     pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+//     //  FIter fit = M_faceIter(m);
+//     MDB_QIter fit(&m->quads);
+//     pFace pface;  
+//     //  while ((pface = FIter_next(fit))) {
+//     while ((pface = fit.next())) {
+//       pVertex nod[4];
+//       pface->getNodes(nod);
+//       pVertex p1 = nod[0];
+//       pVertex p2 = nod[1];
+//       pVertex p3 = nod[2];
+//       pVertex p4 = nod[3];
+//       void *temp_ptr1,*temp_ptr2,*temp_ptr3,*temp_ptr4; 
+//       int isInterface1 = EN_getDataPtr((pEntity) p1 , tagData, &temp_ptr1);
+//       int isInterface2 = EN_getDataPtr((pEntity) p2 , tagData, &temp_ptr2);
+//       int isInterface3 = EN_getDataPtr((pEntity) p3 , tagData, &temp_ptr3);
+//       int isInterface4 = EN_getDataPtr((pEntity) p4 , tagData, &temp_ptr4);
+//       if(isInterface1 && isInterface2 && isInterface3 && isInterface4) {
+//         const std::vector<std::pair<int , pVertex> > *recup1 = 
+//           (const std::vector<std::pair<int , pVertex> > *) temp_ptr1;
+//         const std::vector<std::pair<int , pVertex> > *recup2 = 
+//           (const std::vector<std::pair<int , pVertex> > *) temp_ptr2;
+//         const std::vector<std::pair<int , pVertex> > *recup3 = 
+//           (const std::vector<std::pair<int , pVertex> > *) temp_ptr3;
+//         const std::vector<std::pair<int , pVertex> > *recup4 = 
+//           (const std::vector<std::pair<int , pVertex> > *) temp_ptr4;
+//         int size = (*recup1).size();
+//         int *tab=new int[size];
+//         for(int i=0 ; i< size ; i++) tab[i] = (*recup1)[i].first;
+      
+//         int size2 = (*recup2).size();
+//         int *tab2=new int[size2];
+//         for(int i=0 ; i< size2 ; i++) tab2[i] = (*recup2)[i].first;
+
+//         int size3 = (*recup3).size();
+//         int *tab3=new int[size3];
+//         for(int i=0 ; i< size3 ; i++) tab3[i] = (*recup3)[i].first;
+      
+//         for(int l=0 ; l<(int)((*recup4).size()) ; l++) {  
+//           // this test is not robust: the 4 vertices could belong to 4 identical procs at the same
+//           // time and the face belongs to only 2 of those. In this case 2 packets are sent. We have to 
+//           // ignore the 'wrong' packet at reception. (Done)
+//           int iProc = (*recup4)[l].first;
+//           int i;
+//           for(i=0 ; i<size ; i++) {
+//             if(iProc == tab[i]) break;
+//           }
+//           int j;
+//           for(j=0 ; j<size2 ; j++) {
+//             if(iProc == tab2[j]) break;
+//           } 
+//           int k;
+//           for(k=0 ; k<size3 ; k++) {
+//             if(iProc == tab3[k]) break;
+//           } 
+//           if(i < size && j < size2 && k < size3) {
+//             assert(tab[i]==iProc);
+//             assert(tab2[j]==iProc);
+//             assert(tab3[k]==iProc);
+
+//             int dimGeomFace = GEN_type(pface->g);
+//             if (dimGeomFace == 2) {
+//               int tagFace = GEN_tag(pface->g); //std::cout <<"tagFace: "<<tagFace<<std::endl;
+//               if (F_numRegions(pface)!=1) continue; //SL assert(F_numRegions(pface)==1);
+//               int tagVol = GEN_tag(F_region(pface,0)->g); //std::cout <<"tagVol: "<<tagVol<<std::endl;
+//               if ( tagFace == tagVol ) {
+        
+//                 int sizebuf;
+        
+//                 pVertex remote1 = (*recup1)[i].second;
+//                 pVertex remote2 = (*recup2)[j].second;
+//                 pVertex remote3 = (*recup3)[k].second;
+//                 pVertex remote4 = (*recup4)[l].second;
+        
+//                 void *buf = de.sendData ((pEntity) pface, iProc, sizebuf );
+//                 if (buf)
+//                   {
+//                     if (iProc == myrank)
+//                       {
+//                         puts("*****************************pas parallele");
+//                         char *msg = (char*)malloc(4*sizeof(pEntity*)+sizebuf);
+//                         memcpy(msg,&remote1,sizeof(pEntity*));
+//                         memcpy(&msg[sizeof(pEntity*)],&remote2,sizeof(pEntity*));
+//                         memcpy(&msg[2*sizeof(pEntity*)],&remote3,sizeof(pEntity*));
+//                         memcpy(&msg[3*sizeof(pEntity*)],&remote4,sizeof(pEntity*));
+//                         memcpy(&msg[4*sizeof(pEntity*)],buf,sizebuf);
+//                         free(buf);
+//                         MDB_ListF vf;
+//                         remote1->getTriangles(vf);
+//                         MDB_ListF::iterator it  = vf.begin();
+//                         MDB_ListF::iterator ite = vf.end();
+//                         while(it!=ite){
+//                           pVertex nod[4];
+//                           (*it)->getNodes(nod);
+//                           if((nod[0] == remote1 || nod[1] == remote1 || nod[2] == remote1 || nod[3] == remote1)&& 
+//                              (nod[0] == remote2 || nod[1] == remote2 || nod[2] == remote2 || nod[3] == remote2)&&
+//                              (nod[0] == remote3 || nod[1] == remote3 || nod[2] == remote3 || nod[3] == remote3)&&
+//                              (nod[0] == remote4 || nod[1] == remote4 || nod[2] == remote4 || nod[3] == remote4))break;
+//                           ++it;
+//                         }
+//                         assert(it!=ite);
+//                         pFace pface = *it;
+//                         de.receiveData ((pEntity) pface, 
+//                                         myrank,
+//                                         msg);
+//                         free(msg); 
+//                       }
+//                     else
+//                       {
+// #ifdef PARALLEL
+//                         char *msg = (char*)AP_alloc(iProc, 
+//                                                     de.tag() , 
+//                                                     4*sizeof(pEntity*)+sizebuf);
+//                         memcpy(&msg[0],&remote1,sizeof(pEntity*));
+//                         memcpy(&msg[sizeof(pEntity*)],&remote2,sizeof(pEntity*));
+//                         memcpy(&msg[2*sizeof(pEntity*)],&remote3,sizeof(pEntity*));
+//                         memcpy(&msg[3*sizeof(pEntity*)],&remote4,sizeof(pEntity*));
+//                         memcpy(&msg[4*sizeof(pEntity*)],buf,sizebuf);
+//                         free(buf);
+//                         AP_send(msg);
+//                         sendcounts[iProc]++;
+// #else
+//                         throw;
+// #endif
+//                       } 
+//                   }
+//               }
+//             } 
+//           }
+//         }
+//         delete []tab;
+//         delete []tab2;
+//         delete []tab3;
+//       }
+//     }      
+//     //  FIter_delete(fit);  
+// #ifdef PARALLEL
+//     // #ifdef MDB_DEBUG
+//     //   //MPI_Waitall();
+//     //   MPI_Barrier( MPI_COMM_WORLD );
+//     //   AP_check_sends(AP_WAITALL);
+//     // #else
+//     AP_check_sends(AP_NOFLAGS);
+//     // #endif
+//     AP_reduce_nsends(sendcounts);
+  
+//     // --------------------------------------------------------
+//     // --- RECEIVE --------------------------------------------
+//     // --------------------------------------------------------
+  
+//     int message=0;
+//     int count;
+  
+//     while (!AP_recv_count(&count) || message<count) 
+//       {
+//         void *msg;
+//         int from;
+//         int tag;
+//         int size;
+//         int rc;
+//         rc=AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+//                    &msg, &size, &from, &tag);
+//         if (rc) 
+//           {
+//             message++;
+//             char * tmp = (char *) msg;
+//             pVertex * pv1 = (pVertex *) &tmp[0];
+//             pVertex * pv2 = (pVertex *) &tmp[sizeof(pEntity*)];
+//             pVertex * pv3 = (pVertex *) &tmp[2*sizeof(pEntity*)];
+//             pVertex * pv4 = (pVertex *) &tmp[3*sizeof(pEntity*)];
+//             MDB_ListF vf;
+//             (*pv1)->getTriangles(vf);
+//             MDB_ListF::iterator it  = vf.begin();
+//             MDB_ListF::iterator ite = vf.end();
+//             while(it!=ite){
+//               pVertex nod[4];
+//               (*it)->getNodes(nod);
+//               if((nod[0] == (*pv2) || nod[1] == (*pv2) || nod[2] == (*pv2) || nod[3] == (*pv2))&&
+//                  (nod[0] == (*pv3) || nod[1] == (*pv3) || nod[2] == (*pv3) || nod[3] == (*pv3))&&
+//                  (nod[0] == (*pv4) || nod[1] == (*pv4) || nod[2] == (*pv4) || nod[3] == (*pv4))) {
+//                 assert((nod[0] == (*pv1) || nod[1] == (*pv1) || nod[2] == (*pv1) || nod[3] == (*pv1) ));
+//                 break;
+//               }
+//               ++it;
+//             }
+//             // this can happen: see the comment above in the send part.
+//             if ( it == ite ){
+//               AP_free(msg);
+//             }
+//             else {
+//               pFace pface = *it;
+//               de.receiveData ((pEntity) pface,from, &tmp[4*sizeof(pEntity*)]);
+//               AP_free(msg);
+//             }
+//           }
+//       }    
+//     AP_check_sends(AP_WAITALL); 
+//     MPI_Barrier(MPI_COMM_WORLD);
+// #endif
+//     delete [] sendcounts;
+//   }
+
+} // End of namespace MAd
diff --git a/Mesh/MeshDataBaseComm.h b/Mesh/MeshDataBaseComm.h
new file mode 100644
index 0000000..ccffdba
--- /dev/null
+++ b/Mesh/MeshDataBaseComm.h
@@ -0,0 +1,61 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _MeshDataBaseCOMM_H
+#define _MeshDataBaseCOMM_H
+
+#include "MeshDataBase.h"
+
+/*
+  MDB_DataExchanger is a class that allow user to exchange
+  data's between partitions and/or periodic boundaries. User
+  has to provide a tag for non synchronous communications. 
+  Basically, choose a tag that is higher that 200 for being
+  sure that it does not interact with internal messages.
+  User has to allocate buffers using malloc.
+
+  User will receive its datas.
+*/
+
+namespace MAd {
+
+  class MDB_DataExchanger
+  {
+  private:
+    int tagComm;
+  public :
+    // get a tag for the communication
+    int tag() const { return tagComm; }
+    // user allocates sends a message of _size size related to mesh entity pe to proc iProc
+    virtual void * sendData (MDB_MeshEntity * pe, // in
+                             int    iProcDest , // in
+                             int &_size ) = 0; // out
+    // mesh entity pe recieves data *buf form proc iProc.
+    // The user shall NOT delete the message !!
+    virtual void receiveData (MDB_MeshEntity * pe, //in
+                              int iProcSender ,//in
+                              void *buf ) = 0;  //in
+    // In case the user has to delete a data when 'pe' is deleted
+    virtual void deleteExternalData (MDB_MeshEntity * pe) const {}
+    MDB_DataExchanger(int _tag): tagComm(_tag) {}
+    virtual ~MDB_DataExchanger() {}
+  };
+  void exchangeDataOnVertices (MDB_Mesh * m, MDB_DataExchanger &de );
+  void exchangeDataOnEdges    (MDB_Mesh * m, MDB_DataExchanger &de );
+  void exchangeDataOnFaces    (MDB_Mesh * m, MDB_DataExchanger &de );
+  void exchangeDataOnTriangles(MDB_Mesh * m, MDB_DataExchanger &de );
+  void exchangeDataOnQuads    (MDB_Mesh * m, MDB_DataExchanger &de );
+
+}
+
+#endif
diff --git a/Mesh/MeshDataBaseCommCheck.cc b/Mesh/MeshDataBaseCommCheck.cc
new file mode 100644
index 0000000..2a0584a
--- /dev/null
+++ b/Mesh/MeshDataBaseCommCheck.cc
@@ -0,0 +1,235 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Koen Hillewaert
+// -------------------------------------------------------------------
+
+#include "MeshDataBaseCommCheck.h"
+#include "MeshDataBaseMessage.h"
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseParallelInterface.h"
+
+#include <sstream>
+using std::ostringstream;
+using std::ostream;
+using std::cout;
+using std::endl;
+#include <iostream>
+
+#ifdef PARALLEL
+#include "mpi.h"
+#endif
+
+namespace MAd {
+
+  // -----------------------------------------------------------------------------
+
+  MDB_CommCheck::MDB_CommCheck():
+    MDB_DataExchanger(1354),numRecvs(0),numSends(0),numErrors(0) {}
+
+  // -----------------------------------------------------------------------------
+
+  void MDB_CommCheck::printStatus(ostream& out) const {
+
+    out << "Number of sends " << numSends
+        << ", number of receives " << numRecvs
+        << ", number of errors " << numErrors << std::endl;
+  }
+
+
+  // -----------------------------------------------------------------------------
+
+  void* MDB_CommCheck::sendData(pEntity pe,int iProc,int& size) {  
+  
+    int type = EN_type(pe);
+
+    void* buf = NULL;
+    size = sizeof(pEntity);
+  
+    switch (type) {
+    
+    case 0:
+      {
+        size += 2*sizeof(int);
+        buf = malloc(size);
+
+        int* ibuf = reinterpret_cast<int*>(buf);
+
+        *(ibuf++) = 1;
+        *(ibuf++) = EN_id(pe);
+        
+        pEntity* ebuf = reinterpret_cast<pEntity*>(ibuf);
+        *ebuf = pe;
+        
+        return buf;
+      
+        break;
+      }
+    case 1:
+      {
+        pEdge pl = (pEdge) pe;
+        size += 3 * sizeof(int);
+        buf = malloc(size);
+
+        int *ibuf = reinterpret_cast<int*>(buf);
+
+        *(ibuf++) = 2;
+        *(ibuf++) = EN_id((pEntity) E_vertex(pl,0));
+        *(ibuf++) = EN_id((pEntity) E_vertex(pl,1));      
+        
+        pEntity* ebuf = reinterpret_cast<pEntity*>(ibuf);
+        *ebuf = pl;
+        
+        break;
+      }
+    case 2:
+      {
+        pFace pf = (pFace) pe;
+        size += (1 + F_numVertices(pf)) * sizeof(int);
+        buf  = malloc(size);
+        
+        int *ibuf = reinterpret_cast<int*>(buf);
+        
+        *(ibuf++) = F_numVertices(pf);
+        for (int i=0;i<F_numVertices(pf);i++) *(ibuf++) = EN_id((pEntity) F_vertex(pf,i));
+        
+        pEntity* ebuf = reinterpret_cast<pEntity*>(ibuf);
+        *ebuf = pf;
+        
+        break;
+      }
+    }
+    return buf;
+  }
+
+  // -----------------------------------------------------------------------------
+
+  void MDB_CommCheck::receiveData(pEntity pe,int from,void* buf) {
+  
+    int myrank = 0;
+#ifdef PARALLEL
+    MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
+#endif
+
+    int type = EN_type(pe);
+
+    int* ibuf = reinterpret_cast<int*>(buf);
+    int  np   = *(ibuf++);
+    
+
+    switch (type) {
+
+    case 0: 
+      {
+        int id = *(ibuf++);
+        
+        if (!V_corresponds((pVertex) pe,id)) {
+          
+          Msg_char(MDB_FATAL,
+                   "Non-corresponding communication vertex from proc %d : %d vs %d\n",
+                   from,EN_id(pe),id);
+        }
+        
+        pEntity* pbuf = reinterpret_cast<pEntity*>(ibuf);
+        pEntity  corr = *pbuf;
+        
+        std::pair<int,pEntity> comm = std::make_pair(from,corr);
+        
+        if (communications[pe].find(comm) != communications[pe].end()) {
+          Msg_char(MDB_FATAL,
+                   "Multiple identical communications for vertex %d on %d from %d",
+                   EN_id(pe),myrank,from);
+          
+        }
+        communications[pe].insert(comm);
+        break;
+      }
+    case 1:
+      {
+        pEdge pl = (pEdge) pe;
+        bool check = true;
+      
+        int idSend[2];
+      
+        for (int i=0;i<2;i++){
+          idSend[i] = *(ibuf++);
+          check = check && V_corresponds(E_vertex(pl,i),idSend[i]);
+        }
+        
+        if (!check) {        
+          
+          Msg_char(MDB_FATAL,
+                   "Non-corresponding edge from proc %d on proc %d : (%d,%d) vs (%d,%d)\n",
+                   from,myrank,
+                   idSend[0],
+                   idSend[1],
+                   EN_id(E_vertex(pl,0)),
+                   EN_id(E_vertex(pl,1)));
+        }
+
+        
+        pEntity* pbuf = reinterpret_cast<pEntity*>(ibuf);
+        pEntity  corr = *pbuf;
+        
+        std::pair<int,pEntity> comm = std::make_pair(from,corr);
+
+        if (communications[pe].find(comm) != communications[pe].end()) {
+          Msg_char(MDB_FATAL,
+                   "Multiple identical communications for edge %d-%d on %d from %d",
+                   EN_id((pEntity) E_vertex(pl,0)),
+                   EN_id((pEntity) E_vertex(pl,1))
+                   ,myrank,from);
+        }
+        communications[pe].insert(comm);
+        break;
+      }
+    case 2:
+      {
+        pFace pf = (pFace) pe;
+        bool check = (np == F_numVertices(pf));
+        
+        int idSend[4];
+      
+        for (int i=0;i<np ;i++){
+          idSend[i] = *(ibuf++);
+          check = check && V_corresponds(F_vertex(pf,i),idSend[i]);
+        }
+        
+        if (!check) {
+          
+          ostringstream recv;
+          for (int i=0;i<np;i++) recv << " " << idSend[i];
+          ostringstream send;
+          for (int i=0;i<F_numVertices(pf);i++) send << " " << EN_id((pEntity) F_vertex(pf,i));
+        
+          Msg_char(MDB_FATAL,
+                   "Non-corresponding face from proc %d - (%s) vs (%s)\n",
+                   recv.str().c_str(),send.str().c_str());
+        }
+
+        
+        pEntity* pbuf = reinterpret_cast<pEntity*>(ibuf);
+        pEntity  corr = *pbuf;
+        
+        std::pair<int,pEntity> comm = std::make_pair(from,corr);
+
+        if (communications[pe].find(comm) != communications[pe].end()) {
+          Msg_char(MDB_FATAL,
+                   "Multiple identical communications for face %d-%d-%d on %d from %d",
+                   EN_id((pEntity) F_vertex(pf,0)),
+                   EN_id((pEntity) F_vertex(pf,1)),
+                   EN_id((pEntity) F_vertex(pf,2)),
+                   myrank,from);
+        }
+        communications[pe].insert(comm);
+        break;
+      } 
+    }
+  }
+}
diff --git a/Mesh/MeshDataBaseCommCheck.h b/Mesh/MeshDataBaseCommCheck.h
new file mode 100644
index 0000000..43ee0ec
--- /dev/null
+++ b/Mesh/MeshDataBaseCommCheck.h
@@ -0,0 +1,53 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Koen Hillewaert
+// -------------------------------------------------------------------
+
+#ifndef MESHDATABASEPARALLELCHECK_H
+#define MESHDATABASEPARALLELCHECK_H
+
+#include "MeshDataBaseComm.h"
+#include "MeshDataBaseInterface.h"
+
+#include <iostream>
+#include <map>
+#include <set>
+
+
+namespace MAd {
+
+  /*! \brief Class for checking orientation of corresponding entities \ingroup parallel */
+
+  class MDB_CommCheck : public MDB_DataExchanger {
+
+  public:
+
+    MDB_CommCheck();
+
+    void printStatus(std::ostream&) const;
+  
+    virtual void* sendData(MDB_MeshEntity *,int,int&);
+    virtual void  receiveData(MDB_MeshEntity *,int,void*);
+
+  private:
+
+    int numRecvs;
+    int numSends;
+    int numErrors;
+
+    std::map<pEntity,std::set<std::pair<int,pEntity> > > communications;
+    
+  
+  };
+
+}
+
+#endif
diff --git a/Mesh/MeshDataBaseCommPeriodic.h b/Mesh/MeshDataBaseCommPeriodic.h
new file mode 100644
index 0000000..1de3f97
--- /dev/null
+++ b/Mesh/MeshDataBaseCommPeriodic.h
@@ -0,0 +1,41 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _MeshDataBaseCommPerio_H
+#define _MeshDataBaseCommPerio_H
+
+/*
+  MDB_DataExchangerPeriodic is a class that allow user to define function for
+  periodic boundaries.
+*/
+
+namespace MAd {
+
+  class MDB_DataExchangerPeriodic
+  {
+  public :
+    virtual int nbRefPeriodic() const = 0;
+    virtual void   fperiodic (const int inv,
+                              const double X, 
+                              const double Y,
+                              const double Z,
+                              int numref,      // number of the transformation
+                              double *Xnew,
+                              double *Ynew,
+                              double *Znew) = 0;
+    virtual ~MDB_DataExchangerPeriodic() {};			    
+  };
+
+}
+
+#endif
diff --git a/Mesh/MeshDataBaseGEntity2Physical.cc b/Mesh/MeshDataBaseGEntity2Physical.cc
new file mode 100644
index 0000000..4b8cef5
--- /dev/null
+++ b/Mesh/MeshDataBaseGEntity2Physical.cc
@@ -0,0 +1,36 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "MeshDataBaseGEntity2Physical.h"
+
+namespace MAd {
+
+GEntity2Physical::GEntity2Physical(std::multimap<int,pGEntity> &inmap){
+  for(std::multimap<int,pGEntity>::iterator it=inmap.begin(); it!=inmap.end(); it++){
+    insert(std::pair<pGEntity,int>(it->second,it->first));
+  }
+}
+
+int GEntity2Physical::get_first_tag(const pGEntity g){
+  iterator first_it,end_it;
+  first_it=lower_bound(g);
+  end_it=upper_bound(g);
+  if(first_it==end_it){
+    // This entity doesn't have physical tag
+    // I don't think this could happen but who knows...
+    return 0;
+  }
+  return first_it->second;
+}
+
+}
+
diff --git a/Mesh/MeshDataBaseGEntity2Physical.h b/Mesh/MeshDataBaseGEntity2Physical.h
new file mode 100644
index 0000000..49efaa9
--- /dev/null
+++ b/Mesh/MeshDataBaseGEntity2Physical.h
@@ -0,0 +1,32 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef H_MESHDATABASEGENTITY2PHYSICAL
+#define H_MESHDATABASEGENTITY2PHYSICAL
+#include <map>
+#include "ModelInterface.h"
+// build a reverse map of geomFeatures_Tags
+// (a map would be enough as we read only one physical tag for now,
+// but a multimap is used in prevision...)
+
+namespace MAd {
+
+  class GEntity2Physical:private std::multimap<pGEntity,int>{
+  public:
+    GEntity2Physical(std::multimap<int,pGEntity> &inmap);
+    int get_first_tag(pGEntity g);
+  };
+  
+}
+
+#endif
diff --git a/Mesh/MeshDataBaseIO.cc b/Mesh/MeshDataBaseIO.cc
new file mode 100644
index 0000000..53c4fc6
--- /dev/null
+++ b/Mesh/MeshDataBaseIO.cc
@@ -0,0 +1,1829 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere, Cecile Dobrzynski
+// -------------------------------------------------------------------
+
+#include "MeshDataBase.h"
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseIO.h"
+#include "MeshDataBaseMessage.h"
+#include "MeshDataBaseGEntity2Physical.h"
+#include <assert.h>
+#include "MeshDataBaseCommPeriodic.h"
+#include "MshTags.h"
+
+#include <cstdlib>
+#include <cstring>
+#include <set>
+#include <map>
+#include <utility>
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+#endif
+
+#include "MeshDataBaseParallelInterface.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  // ------------- Load a Gmsh mesh ------------------------------------
+  // -------------------------------------------------------------------
+
+  void LoadGmshMesh (pMesh m,const char *filename)
+  {  
+    FILE *fp = fopen(filename, "r");
+    if(!fp) {
+      Msg(MDB_FATAL,"Unknown File %s\n",filename);
+    }
+
+#ifdef PARALLEL 
+    int myRank = 0, nbProc = 0;
+    MPI_Comm_size(MPI_COMM_WORLD, &nbProc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
+#endif
+
+    char String[256];
+
+    if (!m->model) {
+      pGModel model = NULL;
+      GM_create(&model,"");
+      m->model = model; 
+    }
+
+    // ----------------------------------------------
+    // ------ Reading format
+    // ----------------------------------------------
+
+    int version = -1;
+    do {
+      if(!fgets(String, sizeof(String),fp))
+        break;
+      if(feof(fp))
+        break;
+    } while(String[0] != '$' ||
+            strncmp(&String[1], "MeshFormat",10));
+  
+    if(feof(fp)) {
+      version = 1;
+    }
+    else {
+      int a, b, c;
+      fscanf(fp, "%d %d %d", &a, &b, &c);
+      version = a;
+    }
+
+    rewind(fp);
+
+#ifdef PARALLEL
+    if ( version == 1 && nbProc > 1 ) {
+      Msg(MDB_FATAL,"Cannot load Gmsh mesh from file %s: parallel loading not implemented for file format msh1\n",filename);
+    }
+#endif
+
+    // -----------------------------------------------
+    // ------ Reading elements to find local nodes
+    // -----------------------------------------------
+
+    std::set<int> localNodeIds;
+
+    do {
+      if(!fgets(String, sizeof(String), fp))
+        break;
+      if(feof(fp))
+        break;
+    } while(String[0] != '$' ||
+            ( strncmp(&String[1], "ELM",      3) &&
+              strncmp(&String[1], "Elements", 8)    ) );
+
+    if(!feof(fp)) {
+
+      int nbElems_world, NbTags, verts[256], Tag;
+      int Num, Type, Physical, Elementary, Nbr_Nodes, Partition;
+      fscanf(fp, "%d", &nbElems_world);
+
+      for(int i_Element = 0; i_Element < nbElems_world; i_Element++) {
+	
+        if(version == 1){
+          fscanf(fp, "%d %d %d %d %d",
+                 &Num, &Type, &Physical, &Elementary, &Nbr_Nodes);
+          Partition = -1;
+        }
+        else{
+          fscanf(fp, "%d %d %d", &Num, &Type, &NbTags);
+          Elementary = Physical = Partition = -1;
+          for(int j = 0; j < NbTags; j++){
+            fscanf(fp, "%d", &Tag);	    
+            if(j == 0)
+              Physical = Tag;
+            else if(j == 1)
+              Elementary = Tag;
+            else if(j == 2)
+              Partition = Tag - 1;
+            // ignore any other tags for now
+          }
+          Nbr_Nodes = getNumVerticesForElementTypeMSH(Type);
+        }
+
+        for(int j = 0; j < Nbr_Nodes; j++) {
+          fscanf(fp, "%d", &verts[j]);
+        }
+
+#ifdef PARALLEL 
+        if ( nbProc == 1 || Partition == myRank ) {
+#endif
+          for(int j = 0; j < Nbr_Nodes; j++) {
+            localNodeIds.insert(verts[j]);
+          }
+#ifdef PARALLEL
+        }
+#endif
+      }
+    }
+
+    rewind(fp);
+
+
+    // ----------------------------------------------
+    // ------ Reading nodes
+    // ----------------------------------------------
+
+    do {
+      if(!fgets(String, sizeof(String), fp))
+        break;
+      if(feof(fp))
+        break;
+    } while(String[0] != '$' ||
+            (strncmp(&String[1], "NOD", 3) &&
+             strncmp(&String[1], "NOE", 3) &&
+             strncmp(&String[1], "Nodes", 5)  ) );
+    
+    if(!feof(fp)) {
+      int nbNodes_world;
+      fscanf(fp, "%d", &nbNodes_world);
+      for(int i_Node = 0; i_Node < nbNodes_world; i_Node++) {
+        int id;
+        double x,y,z;
+        fscanf(fp, "%d %lf %lf %lf", &id, &x, &y, &z);
+        if ( localNodeIds.find(id) != localNodeIds.end() ) {
+          m->add_point(id,x,y,z);
+        }
+      }
+    }
+
+    rewind(fp);
+
+    // ----------------------------------------------
+    // ------ Reading parametric nodes
+    // ----------------------------------------------
+
+    if ( version == 2 ) {
+      do {
+        if(!fgets(String, sizeof(String), fp)) break;
+        if(feof(fp)) break;
+      } while(String[0] != '$' ||
+              strncmp(&String[1], "ParametricNodes", 15)  );
+    
+      if(!feof(fp)) {
+        int nbNodes_world;
+        fscanf(fp, "%d", &nbNodes_world);
+        for(int i_Node = 0; i_Node < nbNodes_world; i_Node++) {
+          int id, gDim, gTag;
+          double x,y,z;
+          fscanf(fp, "%d %lf %lf %lf %d %d", &id, &x, &y, &z, &gDim, &gTag);
+          if ( gDim == 3 ) {
+            if ( localNodeIds.find(id) != localNodeIds.end() ) {
+              m->add_point(id,x,y,z);
+            }
+          }
+          else {
+            double u,v;
+            if ( gDim == 0 ) {
+              u = v = 0.;
+            }
+            if ( gDim == 1 ) {
+              fscanf(fp, "%lf", &u);
+              v = 0.;
+            } 
+            if ( gDim == 2 ) {
+              fscanf(fp, "%lf %lf", &u, &v);
+            }
+            m->add_pointParam(id,x,y,z,u,v);
+          }
+        }
+      }
+
+      rewind(fp);
+    }
+
+    // ----------------------------------------------
+    // ------ Reading elements
+    // ----------------------------------------------
+
+    do {
+      if(!fgets(String, sizeof(String), fp))
+        break;
+      if(feof(fp))
+        break;
+    } while(String[0] != '$' ||
+            ( strncmp(&String[1], "ELM",      3) &&
+              strncmp(&String[1], "Elements", 8)    ) );
+
+    if(!feof(fp)) {
+
+      int nbElems_world, NbTags, verts[256], Tag;
+      int Num, Type, Physical, Elementary, Nbr_Nodes, Partition;
+      fscanf(fp, "%d", &nbElems_world);
+
+      for(int i_Element = 0; i_Element < nbElems_world; i_Element++) {
+	
+        if(version == 1){
+          fscanf(fp, "%d %d %d %d %d",
+                 &Num, &Type, &Physical, &Elementary, &Nbr_Nodes);
+          Partition = -1;
+        }
+        else{
+          fscanf(fp, "%d %d %d", &Num, &Type, &NbTags);
+          Elementary = Physical = Partition = -1;
+          for(int j = 0; j < NbTags; j++){
+            fscanf(fp, "%d", &Tag);
+            if(j == 0)
+              Physical = Tag;
+            else if(j == 1)
+              Elementary = Tag;
+            else if(j == 2)
+              Partition = Tag - 1;
+            // ignore any other tags for now
+          }
+          Nbr_Nodes = getNumVerticesForElementTypeMSH(Type);
+        }
+
+        for(int j = 0; j < Nbr_Nodes; j++) {
+          fscanf(fp, "%d", &verts[j]);
+        }
+
+#ifdef PARALLEL 
+        if ( nbProc == 1 || Partition == myRank ) {
+#endif
+
+          pGEntity geom = 0;
+	
+          switch (Type) {
+          case MSH_LIN_2:
+            {
+              geom = (pGEntity) GM_edgeByTag(m->model,Elementary);
+              m->add_edge(verts[0],verts[1],geom);
+            }
+            break;
+          case MSH_LIN_3:
+            {
+              geom = (pGEntity) GM_edgeByTag(m->model,Elementary);
+              //m->add_edge(verts[0],verts[2],verts[1],geom);
+              m->add_edge(3,geom,verts[0],verts[2],verts[1]);
+              //m->add_edge(verts[0],verts[1],ge);
+            }
+            break;
+          case MSH_LIN_4:
+            {
+              geom = (pGEntity) GM_edgeByTag(m->model,Elementary);
+              m->add_edge(4,geom, verts[0],verts[2],verts[3],verts[1]);
+            }
+            break;
+          case MSH_LIN_5:
+            {
+              geom = (pGEntity) GM_edgeByTag(m->model,Elementary);
+              m->add_edge(5,geom, verts[0],verts[2],verts[3],verts[4],verts[1]);
+            }
+            break;
+          case MSH_LIN_6:
+            {
+              geom = (pGEntity) GM_edgeByTag(m->model,Elementary);
+              m->add_edge(6,geom, verts[0],verts[2],verts[3],verts[4],verts[5],verts[1]);
+            }
+            break;
+          case MSH_TRI_3:
+            {
+              geom = (pGEntity) GM_faceByTag(m->model,Elementary);
+              m->add_triangle(verts[0],verts[1],verts[2],geom); 
+            }
+            break;
+            // 6 nodes triangle
+          case MSH_TRI_6:
+            {
+              geom = (pGEntity) GM_faceByTag(m->model,Elementary);
+              //	    printf ("adding a second order triangle %d %d %d %d %d %d\n",verts[0],verts[1],verts[2],verts[3],verts[4],verts[5]);
+              m->add_triangle(2,0,geom,verts[0],verts[3],verts[1],verts[4],verts[2],verts[5]); 
+              //m->add_triangle(verts[0],verts[3],verts[1],verts[4],verts[2],verts[5],geom); 
+              //m->add_triangle(verts[0],verts[1],verts[2],gf); 
+            }
+            break;
+            // 9 nodes triangle (SERENDIP !)
+          case MSH_TRI_9:
+            {
+              geom = (pGEntity) GM_faceByTag(m->model,Elementary);
+              m->add_triangle(3,0,geom,verts[0],verts[3],verts[4],verts[1],verts[5],verts[6],verts[2],verts[7],verts[8]); 
+              //m->add_triangle(verts[0],verts[3],verts[1],verts[4],verts[2],verts[5],geom); 
+            }
+            break;
+            // 10 nodes triangle (LAGRANGE !)
+          case MSH_TRI_10:
+            {
+              geom = (pGEntity) GM_faceByTag(m->model,Elementary);
+              m->add_triangle(3,1,geom,verts[0],verts[3],verts[4],verts[1],verts[5],verts[6],verts[2],verts[7],verts[8],verts[9]); 
+            }
+            break;
+            // 12 nodes triangle (SERENDIP !)
+          case MSH_TRI_12:
+            {
+              geom = (pGEntity) GM_faceByTag(m->model,Elementary);
+              m->add_triangle(4,0,geom,verts[0],verts[3],verts[4],verts[5],verts[1],verts[6],verts[7],verts[8],verts[2],verts[9],verts[10],verts[11]); 
+            }
+            break;
+            // 15 nodes triangle (LAGRANGE !)
+          case MSH_TRI_15:
+            {
+              geom = (pGEntity) GM_faceByTag(m->model,Elementary);
+              m->add_triangle(4,1,geom,verts[0],verts[3],verts[4],verts[5],verts[1],verts[6],verts[7],verts[8],verts[2],verts[9],verts[10],verts[11],verts[12],verts[13],verts[14]); 
+            }
+            break;
+            // 15 nodes triangle (SERENDIP !)
+          case MSH_TRI_15I:
+            {
+              geom = (pGEntity) GM_faceByTag(m->model,Elementary);
+              m->add_triangle(5,0,geom,verts[0],verts[3],verts[4],verts[5],verts[6],verts[1],verts[7],verts[8],verts[9],verts[10],verts[2],verts[11],verts[12],verts[13],verts[14]); 
+            }
+            break;
+          case MSH_QUA_4:
+            {
+              geom = (pGEntity) GM_faceByTag(m->model,Elementary);
+              m->add_quad(verts[0],verts[1],verts[2],verts[3],geom); 
+            }
+            break;
+          case MSH_TET_4:
+            {
+              geom = (pGEntity) GM_regionByTag(m->model,Elementary);
+              if( !geom ) 
+                {
+                  printf("READ MESH : no classification for  Region\n");
+                }
+              m->add_tet(verts[0],verts[1],verts[2],verts[3],geom); 
+            }
+            break;
+          case MSH_PRI_6:
+            {
+              geom = (pGEntity) GM_regionByTag(m->model,Elementary);
+              m->add_prism(verts[0],verts[1],verts[2],
+                           verts[3],verts[4],verts[5],geom); 
+            }
+            break;
+          case MSH_PNT:
+            {
+              geom = (pGEntity) GM_vertexByTag(m->model,Elementary);
+              MDB_Point *p = m->find_point(verts[0]);
+              p->g = geom;
+            }
+            break;
+            // 8 nodes hexahedron
+          case MSH_HEX_8:
+            {
+              geom = (pGEntity) GM_regionByTag(m->model,Elementary); 
+              m->add_hex(verts[0],verts[1],verts[2],verts[3],verts[4],verts[5],verts[6],verts[7],geom); 
+            }
+            break;
+            // 10 node tetrahedron, 2nd order
+          case MSH_TET_10:
+            {
+              geom = (pGEntity) GM_regionByTag(m->model,Elementary);
+              m->add_tet(geom,2,false,verts);
+              break;
+            }
+          case MSH_TET_20:
+            {
+              geom = (pGEntity) GM_regionByTag(m->model,Elementary);
+              m->add_tet(geom,3,false,verts);
+              break;
+            }
+          case MSH_TET_35:
+            {
+              geom = (pGEntity) GM_regionByTag(m->model,Elementary);
+              m->add_tet(geom,4,false,verts);
+              break;
+            }
+          case MSH_TET_34:
+            {
+              geom = (pGEntity) GM_regionByTag(m->model,Elementary);
+              m->add_tet(geom,4,true,verts);
+              break;
+            }
+          default:
+            throw;
+            break;
+          }
+          if (geom)
+            {
+              bool find = false;
+              for (std::multimap<int, pGEntity>::iterator it = m->geomFeatures_Tags.lower_bound(Elementary);
+                   it != m->geomFeatures_Tags.upper_bound(Elementary);++it)
+                if (it->second == geom)find = true;
+              if (!find)
+                m->geomFeatures_Tags.insert(std::pair<int,pGEntity>(Elementary, geom));
+            }
+#ifdef PARALLEL
+        }
+#endif
+      }
+    }
+
+    m->classify_unclassified_entities();
+
+    m->destroyStandAloneEntities();
+
+    rewind(fp);
+
+
+    // ----------------------------------------------
+    // ------ Reading periodicity properties
+    // ----------------------------------------------
+
+    int isPeriodic = 0;
+    while(1) {
+      do {
+        if(!fgets(String, sizeof(String), fp))
+          break;
+        if(feof(fp))
+          break;
+      } while(String[0] != '$');
+    
+      if(feof(fp))
+        break;
+
+      else if(!strncmp(&String[1], "PERIODICNOD", 11)) {
+        isPeriodic = 1;
+      } 
+      else if(!strncmp(&String[1], "TRA", 3)) {
+        isPeriodic = 2;
+      }
+      else if (!strncmp(&String[1],"PeriodicNodes",13)) {
+        isPeriodic = 2;
+      }
+      else if (!strncmp(&String[1],"PER", 3)) {
+        isPeriodic = 2;
+      }
+
+      do {
+        if(!fgets(String, sizeof(String), fp))
+          throw;
+        if(feof(fp))
+          throw;
+      } while(String[0] != '$');
+    }
+
+    rewind(fp);
+
+    // ----------------------------------------------
+    // ------ Reading periodic data
+    // ----------------------------------------------
+
+    if(isPeriodic) {
+      pMeshDataId tagPeriodic = MD_newMeshDataId("PeriodicPoint");
+      if(isPeriodic==1) {
+        fseek(fp,0,SEEK_SET);
+        while(1) {
+          do {
+            if(!fgets(String, sizeof(String), fp))
+              break;
+            if(feof(fp))
+              break;
+          } while(String[0] != '$');
+    
+          if(feof(fp))
+            break;
+          if(!strncmp(&String[1], "PERIODICNOD", 11)) {
+            int nPeriod,nRefPeriod;
+            fscanf(fp, "%d %d", &nPeriod,&nRefPeriod);
+            printf("%d Ref Periodic\n",nRefPeriod);
+            int *t=new int[nRefPeriod];
+            for(int ip = 0; ip < nPeriod; ip++) {
+              int Num,v1,v2;
+              fscanf(fp, "%d ", &Num);
+              std::vector<int> transfo;
+              std::vector<int> invtransfo;
+              for(int k=0 ; k<nRefPeriod ; k++) {
+                fscanf(fp, "%d ", &t[k]);
+                transfo.push_back(t[k]);
+                invtransfo.push_back(-t[k]);
+              } 
+              fscanf(fp, "%d %d",&v1, &v2);
+              pVertex vt1 = m->find_point(v1);
+              pVertex vt2 = m->find_point(v2);
+              //printf("point %d %d\n",EN_id((pEntity) vt1),EN_id((pEntity) vt2));
+              void *temp_ptr; 
+              int isPeriodic = EN_getDataPtr((pEntity) vt1 , tagPeriodic, &temp_ptr);
+              if(isPeriodic) {
+                std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+                unsigned int i=0;
+                for(i=0 ; i<(*recup).size() ; i++) {
+                  unsigned int j=0;
+                  for(j=0 ; j<(*recup)[i].first.size() ; j++) {
+                    if((*recup)[i].first[j] != transfo[j]) break;
+                  }
+                  if(j==(*recup)[i].first.size() ) break;
+                }
+                if(i==(*recup).size())
+                  (*recup).push_back(std::pair <std::vector<int> , pVertex>(transfo,vt2));
+              } else {
+                std::vector<std::pair<std::vector<int> , MDB_Point*> > remotePoints;
+                (remotePoints).push_back(std::pair <std::vector<int> , pVertex>(transfo,vt2));
+                EN_attachDataPtr((pEntity) vt1 , tagPeriodic, 
+                                 new std::vector<std::pair<std::vector<int> , pVertex> >(remotePoints));
+				   
+              }
+	   
+              isPeriodic = EN_getDataPtr((pEntity) vt2 , tagPeriodic, &temp_ptr);
+              if(isPeriodic) {
+                std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+                unsigned int i;
+                for(i=0 ; i<(*recup).size() ; i++) {
+                  unsigned int j;
+                  for(j=0 ; j<(*recup)[i].first.size() ; j++) {
+                    if((*recup)[i].first[j] != invtransfo[j]) break;
+                  }
+                  if(j==(*recup)[i].first.size() ) break;
+                }
+                if(i==(*recup).size())
+                  (*recup).push_back(std::pair <std::vector<int> , pVertex>(invtransfo,vt1));
+              } else {
+                std::vector<std::pair<std::vector<int> , MDB_Point*> > remotePoints;
+                (remotePoints).push_back(std::pair <std::vector<int> , pVertex>(invtransfo,vt1));
+                EN_attachDataPtr((pEntity) vt2 , tagPeriodic, 
+                                 new std::vector<std::pair<std::vector<int> , pVertex> >(remotePoints));	   
+              }
+            }
+            delete []t;
+          }  
+        }
+      } else {
+
+        assert(isPeriodic==2);
+        puts("format periodic CENAERO");
+        fseek(fp,0,SEEK_SET);
+        while(1) {
+          do {
+            if(!fgets(String, sizeof(String), fp))
+              break;
+            if(feof(fp))
+              break;
+          } while(String[0] != '$');
+    
+          if(feof(fp))
+            break;
+
+          if((!strncmp(&String[1],"PER", 3)) || 
+             (!strncmp(&String[1],"PeriodicNodes",13))) {
+            
+            int nPeriod;
+            fscanf(fp, "%d ", &nPeriod);
+
+            pMeshDataId tagPeriodic = MD_newMeshDataId("PeriodicVertexID");
+            
+            for(int ip = 0; ip < nPeriod; ip++) {
+              int Num,vtxId;
+              fscanf(fp, "%d ", &Num);
+              
+              std::vector<int> vtcs;
+
+              for (size_t i=0;i<Num;i++) {
+                fscanf(fp, "%d ", &vtxId);
+                vtcs.push_back(vtxId);
+              }
+              
+              int trafo;
+              fscanf(fp, "%d ",&trafo);
+              
+              std::vector<int>::const_iterator vIter = vtcs.begin();
+              for (;vIter!=vtcs.end();vIter++) {
+                
+                int vtxId = *vIter;
+                pVertex vt1 = m->find_point(vtxId);
+                
+                if (vt1) {
+                  
+                  void* tmp_periodic = NULL;
+                  int havePeriodic = EN_getDataPtr((pEntity) vt1,tagPeriodic,&tmp_periodic);
+                  std::map<int,std::vector<int> > *  connections = NULL;
+                  
+                  if (havePeriodic) connections = (std::map<int,std::vector<int> > * )  (tmp_periodic);
+                  else {
+                    connections = new std::map<int,std::vector<int> >;
+                    EN_attachDataPtr((pEntity) vt1,tagPeriodic,connections);
+                  }
+                  
+                  // transformations will be written later, using topological classification 
+                  
+                  std::vector<int>::const_iterator vIter2 = vtcs.begin();
+                  for (;vIter2!=vtcs.end();++vIter2) {
+                    if (vtxId != *vIter2) connections->insert(std::make_pair(*vIter2,std::vector<int>()));
+                  }
+                }
+              }
+            }
+          }
+          
+//           if(!strncmp(&String[1], "PER", 3)) {
+//             int nPeriod,nRefPeriod;
+//             nRefPeriod = 1;
+//             fscanf(fp, "%d ", &nPeriod);
+//             printf("%d Ref Periodic\n",nRefPeriod);
+//             int *t=new int[nRefPeriod];
+//             for(int ip = 0; ip < nPeriod; ip++) {
+//               int Num,v1,v2;
+//               fscanf(fp, "%d ", &Num);
+//               std::vector<int> transfo;
+//               std::vector<int> invtransfo;
+//               fscanf(fp, "%d %d %d",&v1, &v2,&Num);
+//               pVertex vt1 = m->find_point(v1);
+//               pVertex vt2 = m->find_point(v2);
+
+
+//               printf("point %d (%d) %d (%d)\n",EN_id((pEntity) vt1),GEN_tag(vt1->g),EN_id((pEntity) vt2),
+//                      GEN_tag(vt2->g));
+              
+//               for(int k=0 ; k<nRefPeriod ; k++) {
+//                 t[k]=-1;
+//                 transfo.push_back(t[k]);
+//                 invtransfo.push_back(-t[k]);
+//               }
+//               void *temp_ptr; 
+//               int isPeriodic = EN_getDataPtr((pEntity) vt1 , tagPeriodic, &temp_ptr);
+//               if(isPeriodic) {
+//                 std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+//                 unsigned int i=0;
+//                 for(i=0 ; i<(*recup).size() ; i++) {
+//                   unsigned int j=0;
+//                   for(j=0 ; j<(*recup)[i].first.size() ; j++) {
+//                     if((*recup)[i].first[j] != transfo[j]) break;
+//                   }
+//                   if(j==(*recup)[i].first.size() ) break;
+//                 }
+//                 if(i==(*recup).size())
+//                   (*recup).push_back(std::pair <std::vector<int> , pVertex>(transfo,vt2));
+//               } else {
+//                 std::vector<std::pair<std::vector<int> , MDB_Point*> > remotePoints;
+//                 (remotePoints).push_back(std::pair <std::vector<int> , pVertex>(transfo,vt2));
+//                 EN_attachDataPtr((pEntity) vt1 , tagPeriodic, 
+//                                  new std::vector<std::pair<std::vector<int> , pVertex> >(remotePoints));
+				   
+//               }
+	   
+//               isPeriodic = EN_getDataPtr((pEntity) vt2 , tagPeriodic, &temp_ptr);
+//               if(isPeriodic) {
+//                 std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+//                 unsigned int i;
+//                 for(i=0 ; i<(*recup).size() ; i++) {
+//                   unsigned int j;
+//                   for(j=0 ; j<(*recup)[i].first.size() ; j++) {
+//                     if((*recup)[i].first[j] != invtransfo[j]) break;
+//                   }
+//                   if(j==(*recup)[i].first.size() ) break;
+//                 }
+//                 if(i==(*recup).size())
+//                   (*recup).push_back(std::pair <std::vector<int> , pVertex>(invtransfo,vt1));
+//               } else {
+//                 std::vector<std::pair<std::vector<int> , MDB_Point*> > remotePoints;
+//                 (remotePoints).push_back(std::pair <std::vector<int> , pVertex>(invtransfo,vt1));
+//                 EN_attachDataPtr((pEntity) vt2 , tagPeriodic, 
+//                                  new std::vector<std::pair<std::vector<int> , pVertex> >(remotePoints));	   
+//               }
+//             }
+//             delete []t;
+//           }
+        }
+      }  
+    }
+
+    fclose(fp);
+
+    
+// #ifdef PARALLEL
+
+    // ----------------------------------------------
+    // ------ Tagging inter-partition nodes
+    // ----------------------------------------------
+
+    pMeshDataId tag = MD_lookupMeshDataId("RemotePoint");
+    
+    V_createInfoInterface(m,tag);
+    E_createInfoInterface(m,tag);
+    F_createInfoInterface(m,tag);
+  
+// #endif
+
+    m->initializeIdData();
+  }
+
+
+  // -------------------------------------------------------------------
+  // ------------- Save a Gmsh mesh ------------------------------------
+  // -------------------------------------------------------------------
+
+  void SaveGmshMesh (const pMesh m,const char *filename, int version, 
+                     const int * partitionTable)
+  {
+    if ( version == 1 && partitionTable ) {
+      Msg(MDB_FATAL,"Error while saving mesh on file %s: SaveGmshMesh not implemented for msh1 format with partitioning\n",filename);
+    }
+
+    int meshDim = M_dim(m);
+    int nbModelVertex = 0;
+    pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+    // Create a reverse map of physical tags
+    GEntity2Physical gentity2phys(m->geomFeatures_Tags);
+    FILE *f = fopen(filename, "w");
+    if ( !f ) {
+      printf("Error: could not open file %s\n",filename);
+      throw;
+    }
+    if ( version != 1 ) {
+      fprintf(f, "$MeshFormat\n2 0 8\n$EndMeshFormat\n");
+    }
+    // ------ Writting the nodes ------
+    if ( version == 1 || !(m->isParametric()) )
+      {
+        if ( version == 1 ) { fprintf(f, "$NOD\n");   } 
+        else                { fprintf(f, "$Nodes\n"); }
+        fprintf(f, "%d\n", m->nbPoints);
+        VIter vit = M_vertexIter(m); 
+        while (VIter_next(vit)){}
+        VIter_reset(vit);
+        pVertex pv;  
+        int NN = 0;
+        while ((pv = VIter_next(vit)))
+          {
+            NN++;
+            if(pv->g)
+              {
+                int dim = GEN_type(pv->g); 
+                if(dim == 0)  nbModelVertex++;
+                fprintf(f, "%d %g %g %g\n", pv->iD, pv->X, pv->Y, pv->Z);
+              }
+            else
+              {
+                fprintf(f, "%d %g %g %g\n", pv->iD, pv->X, pv->Y, pv->Z);
+              }
+          }
+        if (NN != m->nbPoints) {
+          MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                      "Vertex iterator saw %d vertices while there are %d points in the mesh",
+                                      NN,m->nbPoints);
+        }
+        VIter_delete(vit);
+        if ( version == 1 ) { fprintf(f, "$ENDNOD\n");   } 
+        else                { fprintf(f, "$EndNodes\n"); }
+      }
+    // ------ Writting the parametric nodes ------
+    else
+      {
+        fprintf(f, "$ParametricNodes\n");
+        fprintf(f, "%d\n", m->nbPoints);
+        pVertex pv;
+        VIter vit = M_vertexIter(m);
+        while ((pv = VIter_next(vit)))
+          {
+            if(pv->g)
+              {
+                int gdim = GEN_type(pv->g);
+                int gtag = GEN_tag(pv->g);
+                fprintf(f, "%d %g %g %g %d %d", pv->iD, pv->X, pv->Y, pv->Z, gdim, gtag);
+                double u[2]; V_params(pv,&u[0],&u[1]);
+                switch (gdim) {
+                case 0: { nbModelVertex++; break; }
+                case 1: { fprintf(f, " %g", u[0]); break; }
+                case 2: { fprintf(f, " %g %g", u[0], u[1]); break; }
+                case 3: { break; }
+                }
+                fprintf(f, "\n");
+              }
+            else {
+              MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                          "Parametric point without classification");
+            }
+          }
+        VIter_delete(vit);
+        fprintf(f, "$EndParametricNodes\n");
+      }
+    // ------ Writting the elements ------
+    {
+      if ( version == 1 ) { fprintf(f, "$ELM\n");   } 
+      else                { fprintf(f, "$Elements\n"); }
+    
+      int nbClasEdges = 0;
+      int nbClasFaces = 0;
+      {
+        EIter eit = M_edgeIter(m);
+        pEdge pe;  
+        while ((pe = EIter_next(eit)))
+          {
+            int dim = GEN_type(pe->g); 
+            if(dim == 1) nbClasEdges++;
+          }
+        EIter_delete(eit);
+      }  
+      {
+        FIter fit = M_faceIter(m);
+        pFace pf;  
+        while ((pf = FIter_next(fit)))
+          {
+            int dim = GEN_type(pf->g); 
+            if(dim == 2) nbClasFaces++;
+            else if(F_numRegions(pf)==1) nbClasFaces++;
+          }
+        FIter_delete(fit);
+      }
+
+      fprintf(f, "%ld\n", (long int)(nbClasEdges + nbModelVertex + nbClasFaces + m->nbTets) );
+
+      int k = 1;
+      // --- Nodes ---
+      {
+        VIter vit = M_vertexIter(m);
+        pVertex pv;  
+        while ((pv = VIter_next(vit)))
+          {
+            if(pv->g)
+              {
+                int dim = GEN_type(pv->g);
+                int nbTags = 3;
+                int tag = GEN_tag (pv->g); 
+                int phys = gentity2phys.get_first_tag(pv->g);
+                int partition = -1;
+                if ( partitionTable ) {
+                  switch(meshDim) {
+                  case 0:
+                    partition = partitionTable[pv->iD];
+                    break;
+                  case 1:
+                    for (int i=0; i < V_numEdges(pv); i++) {
+                      int ePart = partitionTable[V_edge(pv,i)->iD];
+                      partition = std::min(ePart,partition);
+                      if (partition < 0) partition = ePart;
+                    }
+                    break;
+                  case 2: {
+                    pPList vFaces = V_faces(pv);
+                    void *tmp_ptr = 0;
+                    pFace pf;
+                    while( (pf = (pFace) PList_next(vFaces,&tmp_ptr)) ) {
+                      int fPart = partitionTable[pf->iD];
+                      partition = std::min(fPart,partition);
+                      if (partition < 0) partition = fPart;
+                    }
+                    PList_delete(vFaces);
+                    break;
+                  }
+                  case 3: {
+                    pPList vRegs = V_regions(pv);
+                    void *tmp_ptr = 0;
+                    pRegion pr;
+                    while( (pr = (pRegion) PList_next(vRegs,&tmp_ptr)) ) {
+                      int rPart = partitionTable[pr->iD];
+                      partition = std::min(rPart,partition);
+                      if (partition < 0) partition = rPart;
+                    }
+                    PList_delete(vRegs);
+                    break;
+                  }
+                  }
+                }
+
+                if(dim == 0) {
+                  if ( version == 1 ) { fprintf(f, "%d %d %d %d %d %d\n",
+                                                k++, 15, phys, tag, 1, pv->iD); }
+                  else                { fprintf(f, "%d %d %d %d %d %d %d\n",
+                                                k++, 15, nbTags, phys, tag, partition + 1, pv->iD); }
+                }
+              }
+          }
+        VIter_delete(vit);    
+      }
+      // --- Edges ---
+      {      
+        EIter eit = M_edgeIter(m);
+        pEdge pe;  
+        while ((pe = EIter_next(eit)))
+          {
+            if(pe->g)
+              {
+                int dim = GEN_type(pe->g);
+                int nbTags = 3;
+                int tag = GEN_tag (pe->g); 
+                int phys = gentity2phys.get_first_tag(pe->g);
+                int partition = -1;
+                if ( partitionTable ) {
+                  switch(meshDim) {
+                  case 1:
+                    partition = partitionTable[pe->iD];
+                    break;
+                  case 2:
+                    for (int i=0; i < E_numFaces(pe); i++) {
+                      int fPart = partitionTable[E_face(pe,i)->iD];
+                      partition = std::min(fPart,partition);
+                      if (partition < 0) partition = fPart;
+                    }
+                    break;
+                  case 3: {
+                    pPList eRegs = E_regions(pe);
+                    void *tmp_ptr = 0;
+                    pRegion pr;
+                    while( (pr = (pRegion) PList_next(eRegs,&tmp_ptr)) ) {
+                      int rPart = partitionTable[pr->iD];
+                      partition = std::min(rPart,partition);
+                      if (partition < 0) partition = rPart;
+                    }
+                    PList_delete(eRegs);
+                    break;
+                  }
+                  }
+                }
+	      
+                if(dim ==1) {
+                  if ( version == 1 ) { fprintf(f, "%d %d %d %d %d %d %d\n", 
+                                                k++, 1, phys, tag, 2, 
+                                                pe->p1->iD, pe->p2->iD); }
+                  else                { fprintf(f, "%d %d %d %d %d %d %d %d\n",
+                                                k++, 1, nbTags, phys, tag, partition + 1, 
+                                                pe->p1->iD, pe->p2->iD); }
+                }
+              }
+          }
+        EIter_delete(eit);
+      }
+      // --- Faces ---  
+      {
+        FIter fit = M_faceIter(m);
+        pFace pf;  
+        while ((pf = FIter_next(fit)))
+          {
+            if(pf->g)
+              {
+                MDB_Point *nod[4];
+                int dim = GEN_type(pf->g);
+                int nbTags = 3;
+                int tag = GEN_tag (pf->g); 
+                int phys = gentity2phys.get_first_tag(pf->g);
+                int partition = -1;
+                if ( partitionTable ) {
+                  switch(meshDim) {
+                  case 2:
+                    partition = partitionTable[pf->iD];
+                    break;
+                  case 3:
+                    for (int i=0; i < F_numRegions(pf); i++) {
+                      int rPart = partitionTable[F_region(pf,i)->iD];
+                      partition = std::min(rPart,partition);
+                      if (partition < 0) partition = rPart;
+                    }
+                    break;
+                  }
+                }
+	      
+                pf->getNodes(nod);
+                if(dim == 2 || F_numRegions(pf)==1) {
+                  if (pf->getNbEdges() == 4) { //quad
+                    if ( version == 1 ) { fprintf(f, "%d %d %d %d %d %d %d %d %d\n",
+                                                  k++, 3, phys, tag, 4,
+                                                  nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD); }
+                    else                { fprintf(f, "%d %d %d %d %d %d %d %d %d %d\n",
+                                                  k++, 3, nbTags, phys, tag, partition + 1, 
+                                                  nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD); }
+                  }
+                  else { //triangle
+                    if ( version == 1 ) { fprintf(f, "%d %d %d %d %d %d %d %d\n",
+                                                  k++, 2, phys, tag, 3,
+                                                  nod[0]->iD, nod[1]->iD, nod[2]->iD); }
+                    else                { fprintf(f, "%d %d %d %d %d %d %d %d %d\n",
+                                                  k++, 2, nbTags, phys, tag, partition + 1, 
+                                                  nod[0]->iD, nod[1]->iD, nod[2]->iD); }
+                  }
+                }
+              }
+          }
+        FIter_delete(fit);
+      } 
+      {
+        RIter rit = M_regionIter(m);
+        pRegion pr;  
+        while ((pr = RIter_next(rit)))
+          {
+            if(pr->g)
+              {
+                MDB_Point *nod[8];
+                //int dim = GEN_type(pr->g);
+                int nbTags = 3;
+                int tag = GEN_tag (pr->g);  
+                int phys = gentity2phys.get_first_tag(pr->g);
+                int partition = 0;
+                if ( partitionTable ) {
+                  partition = partitionTable[pr->iD];
+                }
+	      
+                int numVer =  pr->getNbVertex();
+                pPList ll = R_vertices(pr);
+                for(int i=0;i<numVer;i++) nod[i] = (pVertex)PList_item(ll, i);
+                PList_delete(ll);
+              
+                if(numVer==4) {
+                  if ( version == 1 ) { fprintf(f, "%d %d %d %d %d %d %d %d %d\n", 
+                                                k++, 4, phys, tag, 4,
+                                                nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD); }
+                  else                { fprintf(f, "%d %d %d %d %d %d %d %d %d %d\n",
+                                                k++, 4, nbTags, phys, tag, partition + 1, 
+                                                nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD); }
+                }
+                else if(numVer==8) {
+                  if ( version == 1 ) { fprintf(f, "%d %d %d %d %d %d %d %d %d %d %d %d %d\n", 
+                                                k++, 5, phys, tag, 5,
+                                                nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD,
+                                                nod[4]->iD, nod[5]->iD, nod[6]->iD, nod[7]->iD); }
+                  else                { fprintf(f, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+                                                k++, 5, nbTags, phys, tag, partition + 1, 
+                                                nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD,
+                                                nod[4]->iD, nod[5]->iD, nod[6]->iD, nod[7]->iD); }
+                }
+                else if(numVer==6) { 
+                  if ( version == 1 ) { fprintf(f, "%d %d %d %d %d %d %d %d %d %d %d\n", 
+                                                k++, 6, phys, tag, 6,
+                                                nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD,
+                                                nod[4]->iD, nod[5]->iD); }
+                  else                { fprintf(f, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
+                                                k++, 6, nbTags, phys, tag, partition + 1, 
+                                                nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD,
+                                                nod[4]->iD, nod[5]->iD); }
+                }
+              }
+          }
+        RIter_delete(rit);
+      }
+      if ( version == 1 ) { fprintf(f, "$ENDELM\n");   } 
+      else                { fprintf(f, "$EndElements\n"); }
+      {
+        int nperiodic = 0,nref = 0;;
+        VIter vit = M_vertexIter(m);
+        pVertex pv;  
+        while ((pv = VIter_next(vit)))
+          {
+            void *temp_ptr; 
+            int isPeriodic = EN_getDataPtr((pEntity) pv , tagPeriodic, &temp_ptr);
+            if(isPeriodic) {
+              std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+              if(!nperiodic) {
+                nref = (*recup)[0].first.size();
+              }
+              nperiodic+=(*recup).size();
+            }
+          }
+        VIter_delete(vit);  
+        if(nperiodic) {
+          fprintf(f, "$PERIODICNOD\n");
+          fprintf(f, "%d %d\n", nperiodic,nref);
+          int num = 1;
+          vit = M_vertexIter(m);
+          while ((pv = VIter_next(vit)))
+            {
+              void *temp_ptr; 
+              int isPeriodic = EN_getDataPtr((pEntity) pv , tagPeriodic, &temp_ptr);
+              if(isPeriodic) {
+	        std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+		for(unsigned int k=0 ; k<(*recup).size() ; k++) {
+	          fprintf(f, "%d", num++);
+	          for(unsigned int j=0 ; j<(*recup)[k].first.size() ; j++) fprintf(f, " %d", (*recup)[k].first[j]);
+		  fprintf(f, " %d %d \n", EN_id((pEntity) pv),EN_id((pEntity) (*recup)[k].second));
+	        }
+		//delete recup;
+		//EN_deleteData((pEntity) pv , tagPeriodic);
+              }
+            }
+          VIter_delete(vit);
+          fprintf(f, "$ENDPERIODICNOD\n");  
+        }
+      }  
+    }
+    fclose(f);
+    //MD_deleteMeshDataId(tagPeriodic);
+
+  }
+
+
+
+  void SaveGmshMeshPer (const pMesh m,const char *filename,MDB_DataExchangerPeriodic &deperiodic, int version)
+  {
+    int nbModelVertex = 0;
+    pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+    // Create a reverse map of physical tags
+    GEntity2Physical gentity2phys(m->geomFeatures_Tags);
+    FILE *f = fopen(filename, "w");
+    {
+      fprintf(f, "$NOD\n");
+      fprintf(f, "%d\n", m->nbPoints);
+      VIter vit = M_vertexIter(m); 
+      while (VIter_next(vit)){}
+      VIter_reset(vit);
+      pVertex pv;  
+      int NN = 0;
+      while ((pv = VIter_next(vit)))
+        {
+          if(pv->g)
+            {
+              NN++;
+              int dim = GEN_type(pv->g); 
+              if (pv->deleted)printf("ouuch\n");
+              if(dim == 0)
+                nbModelVertex++;
+              void *temp_ptr; 
+              int isPeriodic = EN_getDataPtr((pEntity) pv , tagPeriodic, &temp_ptr);
+              if(pv->X==2.25 && pv->Y==0.25) printf("%e %e %e : %d\n",pv->X,pv->Y,pv->Z,pv->iD);
+              if(pv->X==2.75 && pv->Y==0.25) printf("%e %e %e : %d\n",pv->X,pv->Y,pv->Z,pv->iD);
+              if(isPeriodic) {
+     		        std::vector<std::pair<std::vector<int> , pVertex> > *recup = (
+                  std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+                          
+                // the use of allocation is done due to ms visual c++ compiler 
+                // that due not support c99 standard (it uses the c95 et c++98 standards)
+                int* ntrans = new int[deperiodic.nbRefPeriodic()];
+                for(int kk = 0 ; kk<deperiodic.nbRefPeriodic() ; kk++) {
+                  ntrans[kk] = 0;
+                }
+                int nump = EN_id((pEntity) pv);
+                pVertex pnump = pv;
+                for(unsigned int k=0 ; k<(*recup).size() ; k++) {
+                  if ( nump > EN_id((pEntity) (*recup)[k].second) ) {
+                    nump  = EN_id((pEntity) (*recup)[k].second);
+                    pnump =  (*recup)[k].second;
+                    for(unsigned int j=0 ; j<(*recup)[k].first.size() ; j++) ntrans[j] = (-1) * (*recup)[k].first[j];
+                  }	        		
+     		        }
+                if (nump == EN_id((pEntity) pv)) {  
+                  fprintf(f, "%d %g %g %g\n", pv->iD, pv->X, pv->Y, pv->Z);					
+                } else {
+                  double X,Y,Z;
+                  X = pnump->X;
+                  Y = pnump->Y;
+                  Z = pnump->Z; 
+                  for(int kk = 0 ; kk<deperiodic.nbRefPeriodic() ; kk++) {
+                    if(ntrans[kk]){
+                      int inv1 = (ntrans[kk] < 0) ? 1 : 0;
+                      for(int nb = 0 ; nb<abs(ntrans[kk]) ; nb++) { //nb de fois qu'il faut appliquer la transfo
+                        deperiodic.fperiodic(inv1,X,Y,Z,kk+1,&X,&Y,&Z);
+                      }  
+                    }
+                  }
+                  fprintf(f, "%d %g %g %g\n", pv->iD, X, Y, Z);    
+                  if((fabs(X-pv->X) > 1e-12) || (fabs(Y-pv->Y) > 1e-12) || (fabs(Z-pv->Z) > 1e-12)  ) {
+                    printf("point %d : %e %e %e \n",EN_id((pEntity) pv),pv->X, pv->Y, pv->Z);
+                    printf("-- corresp %d : %e %e %e\n",nump,pnump->X,pnump->Y,pnump->Z);
+                    printf("*end* %e %e %e\n",X,Y,Z);  			
+                  }
+                }
+                delete [] ntrans;
+              } else {
+                fprintf(f, "%d %g %g %g\n", pv->iD, pv->X, pv->Y, pv->Z);
+              }
+            }
+          else
+            {
+              NN++;
+              fprintf(f, "%d %g %g %g\n", pv->iD, pv->X, pv->Y, pv->Z);
+            }
+          // 	   throw;
+        }
+      if (NN != m->nbPoints) 
+        {
+          printf("%d != %d\n",NN,m->nbPoints);
+          throw;
+        }
+      VIter_delete(vit);    
+      fprintf(f, "$ENDNOD\n");
+    }
+    {
+      fprintf(f, "$ELM\n");
+    
+      int nbClasEdges = 0;
+      int nbClasFaces = 0;
+      {
+        EIter eit = M_edgeIter(m);
+        pEdge pe;  
+        while ((pe = EIter_next(eit)))
+          {
+            int dim = GEN_type(pe->g); 
+            if(dim == 1)nbClasEdges++;
+          }
+        EIter_delete(eit);
+      }    
+      {
+        FIter fit = M_faceIter(m);
+        pFace pf;  
+        while ((pf = FIter_next(fit)))
+          {
+            int dim = GEN_type(pf->g); 
+            if(dim == 2)nbClasFaces++;
+            else if(F_numRegions(pf)==1) nbClasFaces++;
+          }
+        FIter_delete(fit);
+      } 
+
+      fprintf(f, "%ld\n", (long int)(nbClasEdges + nbModelVertex + nbClasFaces + m->nbTets) );
+
+      int k = 1;
+      {
+        VIter vit = M_vertexIter(m);
+        pVertex pv;  
+        while ((pv = VIter_next(vit)))
+          {
+            if(pv->g)
+              {
+                int dim = GEN_type(pv->g); 
+                int tag = GEN_tag (pv->g); 
+                int phys = gentity2phys.get_first_tag(pv->g);
+	      
+                if(dim == 0)
+                  fprintf(f, "%d %d %d %d %d %d\n",
+                          k++, 15, phys,tag, 1,pv->iD);
+              }
+          }
+        VIter_delete(vit);    
+      }
+      {      
+        EIter eit = M_edgeIter(m);
+        pEdge pe;  
+        while ((pe = EIter_next(eit)))
+          {
+            if(pe->g)
+              {
+                int dim = GEN_type(pe->g); 
+                int tag = GEN_tag (pe->g); 
+                int phys = gentity2phys.get_first_tag(pe->g);
+	      
+                if(dim ==1)
+                  fprintf(f, "%d %d %d %d %d %d %d\n", k++, 1, phys,tag, 2,pe->p1->iD, pe->p2->iD);
+              }
+          }
+        EIter_delete(eit);
+      }
+      {
+        FIter fit = M_faceIter(m);
+        pFace pf;  
+        while ((pf = FIter_next(fit)))
+          {
+            if(pf->g)
+              {
+                MDB_Point *nod[4];
+                int dim = GEN_type(pf->g); 
+                int tag = GEN_tag (pf->g); 
+                int phys = gentity2phys.get_first_tag(pf->g);
+	      
+                pf->getNodes(nod);
+                if(dim == 2 || F_numRegions(pf)==1){
+                  if (0 && nod[3]) //quad
+                    fprintf(f, "%d %d %d %d %d %d %d %d %d\n",
+                            k++, 3, phys,tag, 4,
+                            nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD);
+                  else //triangle
+                    fprintf(f, "%d %d %d %d %d %d %d %d\n",
+                            k++, 2, phys,tag, 3,
+                            nod[0]->iD, nod[1]->iD, nod[2]->iD);
+
+                }
+              }
+          }
+        FIter_delete(fit);
+      } 
+      {
+        RIter rit = M_regionIter(m);
+        pRegion pr;  
+        while ((pr = RIter_next(rit)))
+          {
+            if(pr->g)
+              {
+                MDB_Point *nod[8];
+                //int dim = GEN_type(pr->g); 
+                int tag = GEN_tag (pr->g);  
+                int phys = gentity2phys.get_first_tag(pr->g);
+	      
+                int numVer =  pr->getNbVertex();
+                pPList ll = R_vertices(pr);
+                for(int i=0;i<numVer;i++) nod[i] = (pVertex)PList_item(ll, i);
+                PList_delete(ll);
+              
+                if(numVer==4) fprintf(f, "%d %d %d %d %d %d %d %d %d\n", k++, 4, phys,tag, 4,
+                                      nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD);
+                else if(numVer==8) fprintf(f, "%d %d %d %d %d %d %d %d %d %d %d %d %d\n", k++, 5, phys,tag, 5,
+                                           nod[0]->iD, nod[1]->iD, nod[2]->iD, nod[3]->iD, nod[4]->iD, nod[5]->iD, nod[6]->iD, nod[7]->iD);
+              }
+          }
+        RIter_delete(rit);
+      }
+      fprintf(f, "$ENDELM\n");
+      {
+        int nperiodic = 0,nref = 0;;
+        VIter vit = M_vertexIter(m);
+        pVertex pv;  
+        while ((pv = VIter_next(vit)))
+          {
+            void *temp_ptr; 
+            int isPeriodic = EN_getDataPtr((pEntity) pv , tagPeriodic, &temp_ptr);
+            if(isPeriodic) {
+              std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+              if(!nperiodic) {
+                nref = (*recup)[0].first.size();
+              }
+              nperiodic+=(*recup).size();
+            }
+          }
+        VIter_delete(vit);  
+        if(nperiodic) {
+          fprintf(f, "$PERIODICNOD\n");
+          fprintf(f, "%d %d\n", nperiodic,nref);
+          int num = 1;
+          vit = M_vertexIter(m);
+          while ((pv = VIter_next(vit)))
+            {
+              void *temp_ptr; 
+              int isPeriodic = EN_getDataPtr((pEntity) pv , tagPeriodic, &temp_ptr);
+              if(isPeriodic) {
+	        std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+		for(unsigned int k=0 ; k<(*recup).size() ; k++) {
+	          fprintf(f, "%d", num++);
+	          for(unsigned int j=0 ; j<(*recup)[k].first.size() ; j++) fprintf(f, " %d", (*recup)[k].first[j]);
+		  fprintf(f, " %d %d \n", EN_id((pEntity) pv),EN_id((pEntity) (*recup)[k].second));
+	        }
+		//delete recup;
+		//EN_deleteData((pEntity) pv , tagPeriodic);
+              }
+            }
+          VIter_delete(vit);
+          fprintf(f, "$ENDPERIODICNOD\n");  
+        }
+      }  
+    }
+    fclose(f);
+    //MD_deleteMeshDataId(tagPeriodic);
+
+  }
+
+}
+
+
+
+  /*
+// -------------------------------------------------------------------
+// Old loader (no parallel)
+// -------------------------------------------------------------------
+
+void LoadGmshMesh (pMesh m,const char *filename, int version)
+{  
+  FILE *fp = fopen(filename, "r");
+  int  isperiodic=0;
+  pMeshDataId tagPeriodic = MD_newMeshDataId("PeriodicPoint");
+  if(!fp)
+    {
+      Msg(MDB_FATAL,"Unknown File %s\n",filename);
+    }
+  char String[256];
+  if (!m->model)
+    m->model = new NullModel; 
+
+  while(1) {
+    do {
+      if(!fgets(String, sizeof(String), fp))
+	break;
+      if(feof(fp))
+        break;
+    } while(String[0] != '$');
+    
+    if(feof(fp))
+      break;
+    
+    if(!strncmp(&String[1], "MeshFormat", 10)) {
+      int a, b, c;
+      fscanf(fp, "%d %d %d", &a, &b, &c);
+      version = a;      
+    }
+    
+    if(!strncmp(&String[1], "NOD", 3) ||
+       !strncmp(&String[1], "NOE", 3) ||
+       !strncmp(&String[1], "Nodes", 5)) {
+      
+      int Nbr_Nodes,Num;
+      double x,y,z;
+      fscanf(fp, "%d", &Nbr_Nodes);
+      for(int i_Node = 0; i_Node < Nbr_Nodes; i_Node++) {
+        fscanf(fp, "%d %lf %lf %lf", &Num, &x, &y, &z);
+        m->add_point (Num,x,y,z);
+      }
+    }
+    
+    // ELEMENTS
+    
+    else if(!strncmp(&String[1], "ELM", 3) ||
+	    !strncmp(&String[1], "Elements", 8)) {
+      int Nbr_Elements, NbTags, verts[256],Tag;
+      int Num, Type, Physical, Elementary, Nbr_Nodes, Partition;
+      fscanf(fp, "%d", &Nbr_Elements);
+
+      for(int i_Element = 0; i_Element < Nbr_Elements; i_Element++) {
+	
+	if(version == 1){
+	  fscanf(fp, "%d %d %d %d %d",
+		 &Num, &Type, &Physical, &Elementary, &Nbr_Nodes);
+	  Partition = 1;
+	}
+	else{
+	  fscanf(fp, "%d %d %d", &Num, &Type, &NbTags);
+	  Elementary = Physical = Partition = 1;
+	  for(int j = 0; j < NbTags; j++){
+	    fscanf(fp, "%d", &Tag);	    
+	    if(j == 0)
+	      Physical = Tag;
+	    else if(j == 1)
+	      Elementary = Tag;
+	    else if(j == 2)
+	      Partition = Tag;
+	    // ignore any other tags for now
+	  }
+	  Nbr_Nodes = getNumVerticesForElementTypeMSH(Type);
+	}
+
+        for(int j = 0; j < Nbr_Nodes; j++)
+          fscanf(fp, "%d", &verts[j]);
+
+	GEntity *geom = 0;
+	
+        switch (Type) {
+        case 1:
+	  {
+	    geom = m->model->edgeByTag(Elementary);
+	    m->add_edge(verts[0],verts[1],geom);
+	  }
+	  break;
+        case 8:
+	  {
+	    geom = m->model->edgeByTag(Elementary);
+	    //m->add_edge(verts[0],verts[2],verts[1],geom);
+	    m->add_edge(3,geom,verts[0],verts[2],verts[1]);
+	    //m->add_edge(verts[0],verts[1],ge);
+	  }
+	  break;
+        case 26:
+	  {
+	    geom = m->model->edgeByTag(Elementary);
+	    m->add_edge(4,geom, verts[0],verts[2],verts[3],verts[1]);
+	  }
+	  break;
+        case 27:
+	  {
+	    geom = m->model->edgeByTag(Elementary);
+	    m->add_edge(5,geom, verts[0],verts[2],verts[3],verts[4],verts[1]);
+	  }
+	  break;
+        case 28:
+	  {
+	    geom = m->model->edgeByTag(Elementary);
+	    m->add_edge(6,geom, verts[0],verts[2],verts[3],verts[4],verts[5],verts[1]);
+	  }
+	  break;
+        case 2:
+	  {
+	    geom = m->model->faceByTag(Elementary);
+	    m->add_triangle(verts[0],verts[1],verts[2],geom); 
+	  }
+	  break;
+// 6 nodes triangle
+        case MSH_TRI_6:
+	  {
+	    geom = m->model->faceByTag(Elementary);
+	    //	    printf ("adding a second order triangle %d %d %d %d %d %d\n",verts[0],verts[1],verts[2],verts[3],verts[4],verts[5]);
+	    m->add_triangle(2,0,geom,verts[0],verts[3],verts[1],verts[4],verts[2],verts[5]); 
+	    //m->add_triangle(verts[0],verts[3],verts[1],verts[4],verts[2],verts[5],geom); 
+	    //m->add_triangle(verts[0],verts[1],verts[2],gf); 
+	  }
+	  break;
+// 9 nodes triangle (SERENDIP !)
+        case MSH_TRI_9:
+	  {
+	    geom = m->model->faceByTag(Elementary);
+	    m->add_triangle(3,0,geom,verts[0],verts[3],verts[4],verts[1],verts[5],verts[6],verts[2],verts[7],verts[8]); 
+	    //m->add_triangle(verts[0],verts[3],verts[1],verts[4],verts[2],verts[5],geom); 
+	  }
+	  break;
+// 10 nodes triangle (LAGRANGE !)
+        case MSH_TRI_10:
+	  {
+	    geom = m->model->faceByTag(Elementary);
+	    m->add_triangle(3,1,geom,verts[0],verts[3],verts[4],verts[1],verts[5],verts[6],verts[2],verts[7],verts[8],verts[9]); 
+	  }
+	  break;
+// 12 nodes triangle (SERENDIP !)
+        case MSH_TRI_12:
+	  {
+	    geom = m->model->faceByTag(Elementary);
+	    m->add_triangle(4,0,geom,verts[0],verts[3],verts[4],verts[5],verts[1],verts[6],verts[7],verts[8],verts[2],verts[9],verts[10],verts[11]); 
+	  }
+	  break;
+// 15 nodes triangle (LAGRANGE !)
+        case MSH_TRI_15:
+	  {
+	    geom = m->model->faceByTag(Elementary);
+	    m->add_triangle(4,1,geom,verts[0],verts[3],verts[4],verts[5],verts[1],verts[6],verts[7],verts[8],verts[2],verts[9],verts[10],verts[11],verts[12],verts[13],verts[14]); 
+	  }
+	  break;
+// 15 nodes triangle (SERENDIP !)
+        case MSH_TRI_15I:
+	  {
+	    geom = m->model->faceByTag(Elementary);
+	    m->add_triangle(5,0,geom,verts[0],verts[3],verts[4],verts[5],verts[6],verts[1],verts[7],verts[8],verts[9],verts[10],verts[2],verts[11],verts[12],verts[13],verts[14]); 
+	  }
+	  break;
+        case 3:
+	  {
+	    geom = m->model->faceByTag(Elementary);
+	    m->add_quad(verts[0],verts[1],verts[2],verts[3],geom); 
+	  }
+	  break;
+        case 4:
+	  {
+	    geom = m->model->regionByTag(Elementary);
+	    m->add_tet(verts[0],verts[1],verts[2],verts[3],geom); 
+	  }
+	  break;
+        case 6:
+          {
+            geom = m->model->regionByTag(Elementary);
+            m->add_prism(verts[0],verts[1],verts[2],
+                         verts[3],verts[4],verts[5],geom); 
+          }
+          break;
+        case 15:
+	  {
+	    geom = m->model->vertexByTag(Elementary);
+	    MDB_Point *p = m->find_point(verts[0]);
+	    p->g = geom;
+	  }
+	  break;
+// 8 nodes hexahedron
+        case 5:
+	  {
+	    geom = m->model->regionByTag(Elementary); 
+	    m->add_hex(verts[0],verts[1],verts[2],verts[3],verts[4],verts[5],verts[6],verts[7],geom); 
+	  }
+	  break;
+          // 10 node tetrahedron, 2nd order
+        case MSH_TET_10:
+          {
+            geom = m->model->regionByTag(Elementary);
+            m->add_tet(geom,2,false,verts);
+            break;
+          }
+        default:
+	  throw;
+          break;
+        }
+	if (geom)
+	  {
+	    bool find = false;
+	    for (std::multimap<int, pGEntity>::iterator it = m->geomFeatures_Tags.lower_bound(Physical);
+		 it != m->geomFeatures_Tags.upper_bound(Physical);++it)
+	      if (it->second == geom)find = true;
+	    if (!find)
+	      m->geomFeatures_Tags.insert(std::pair<int,pGEntity>(Physical, geom));
+	  }
+      }
+    }
+    else if(!strncmp(&String[1], "PERIODICNOD", 11)) {
+      isperiodic = 1;
+    } 
+    else if(!strncmp(&String[1], "TRA", 3)) {
+      isperiodic = 2;
+    }
+
+    do {
+      if(!fgets(String, sizeof(String), fp))
+	throw;
+      if(feof(fp))
+	throw;
+    } while(String[0] != '$');    
+  }
+  
+  m->classify_unclassified_entities();
+
+  m->destroyStandAloneEntities();
+
+  if(isperiodic) {
+    if(isperiodic==1) {
+      fseek(fp,0,SEEK_SET);
+      while(1) {
+        do {
+          if(!fgets(String, sizeof(String), fp))
+	    break;
+          if(feof(fp))
+            break;
+        } while(String[0] != '$');
+    
+        if(feof(fp))
+          break;
+        if(!strncmp(&String[1], "PERIODICNOD", 11)) {
+          int nPeriod,nRefPeriod;
+          fscanf(fp, "%d %d", &nPeriod,&nRefPeriod);
+	  printf("%d Ref Periodic\n",nRefPeriod);
+	  int *t=new int[nRefPeriod];
+         for(int ip = 0; ip < nPeriod; ip++) {
+	   int Num,v1,v2;
+           fscanf(fp, "%d ", &Num);
+	   std::vector<int> transfo;
+	   std::vector<int> invtransfo;
+	   for(int k=0 ; k<nRefPeriod ; k++) {
+	     fscanf(fp, "%d ", &t[k]);
+	     transfo.push_back(t[k]);
+	     invtransfo.push_back(-t[k]);
+	   } 
+	   fscanf(fp, "%d %d",&v1, &v2);
+	   pVertex vt1 = m->find_point(v1);
+	   pVertex vt2 = m->find_point(v2);
+//printf("point %d %d\n",EN_id((pEntity) vt1),EN_id((pEntity) vt2));
+	   void *temp_ptr; 
+           int isPeriodic = EN_getDataPtr((pEntity) vt1 , tagPeriodic, &temp_ptr);
+	   if(isPeriodic) {
+	      std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+              unsigned int i=0;
+	      for(i=0 ; i<(*recup).size() ; i++) {
+	        unsigned int j=0;
+		for(j=0 ; j<(*recup)[i].first.size() ; j++) {
+		  if((*recup)[i].first[j] != transfo[j]) break;
+		}
+		if(j==(*recup)[i].first.size() ) break;
+	      }
+	      if(i==(*recup).size())
+	        (*recup).push_back(std::pair <std::vector<int> , pVertex>(transfo,vt2));
+	   } else {
+             std::vector<std::pair<std::vector<int> , MDB_Point*> > remotePoints;
+	     (remotePoints).push_back(std::pair <std::vector<int> , pVertex>(transfo,vt2));
+	      EN_attachDataPtr((pEntity) vt1 , tagPeriodic, 
+	    			new std::vector<std::pair<std::vector<int> , pVertex> >(remotePoints));
+				   
+	   }
+	   
+           isPeriodic = EN_getDataPtr((pEntity) vt2 , tagPeriodic, &temp_ptr);
+	   if(isPeriodic) {
+	      std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+              unsigned int i;
+	      for(i=0 ; i<(*recup).size() ; i++) {
+	        unsigned int j;
+		for(j=0 ; j<(*recup)[i].first.size() ; j++) {
+		  if((*recup)[i].first[j] != invtransfo[j]) break;
+		}
+		if(j==(*recup)[i].first.size() ) break;
+	      }
+	      if(i==(*recup).size())
+                (*recup).push_back(std::pair <std::vector<int> , pVertex>(invtransfo,vt1));
+	   } else {
+             std::vector<std::pair<std::vector<int> , MDB_Point*> > remotePoints;
+	     (remotePoints).push_back(std::pair <std::vector<int> , pVertex>(invtransfo,vt1));
+	      EN_attachDataPtr((pEntity) vt2 , tagPeriodic, 
+	    			new std::vector<std::pair<std::vector<int> , pVertex> >(remotePoints));	   
+	    }
+          }
+          delete []t;
+	}  
+      }
+    } else {
+      assert(isperiodic==2);
+      puts("format periodic CENAERO");
+      fseek(fp,0,SEEK_SET);
+      while(1) {
+        do {
+          if(!fgets(String, sizeof(String), fp))
+	    break;
+          if(feof(fp))
+            break;
+        } while(String[0] != '$');
+    
+        if(feof(fp))
+          break;
+        if(!strncmp(&String[1], "PER", 3)) {
+          int nPeriod,nRefPeriod;
+	  nRefPeriod = 1;
+          fscanf(fp, "%d ", &nPeriod);
+	  printf("%d Ref Periodic\n",nRefPeriod);
+	  int *t=new int[nRefPeriod];
+          for(int ip = 0; ip < nPeriod; ip++) {
+	   int Num,v1,v2;
+           fscanf(fp, "%d ", &Num);
+	   std::vector<int> transfo;
+	   std::vector<int> invtransfo;
+	   fscanf(fp, "%d %d %d",&v1, &v2,&Num);
+	   pVertex vt1 = m->find_point(v1);
+	   pVertex vt2 = m->find_point(v2);
+
+
+	printf("point %d (%d) %d (%d)\n",EN_id((pEntity) vt1),GEN_tag(vt1->g),EN_id((pEntity) vt2),
+				GEN_tag(vt2->g));
+	if(GEN_tag(vt1->g)==132 || GEN_tag(vt1->g)==130 || GEN_tag(vt1->g)== 118 || GEN_tag(vt1->g)== 117) {
+	  for(int k=0 ; k<nRefPeriod ; k++) {
+             t[k]=-1;
+	     transfo.push_back(t[k]);
+	     invtransfo.push_back(-t[k]);
+	   } 
+ 
+	} else {
+	  assert(GEN_tag(vt1->g)==348 || GEN_tag(vt1->g)==31 
+	     || GEN_tag(vt1->g)== 93 || GEN_tag(vt1->g)== 345
+	     || GEN_tag(vt1->g)== 29 || GEN_tag(vt1->g)== 94
+	     || GEN_tag(vt1->g)== 16 || GEN_tag(vt1->g)== 66
+	     || GEN_tag(vt1->g)== 13 || GEN_tag(vt1->g)== 74
+	     || GEN_tag(vt1->g)== 115 || GEN_tag(vt1->g)== 351
+	     || GEN_tag(vt1->g)== 116);
+	  for(int k=0 ; k<nRefPeriod ; k++) {
+             t[k]=1;
+	     transfo.push_back(t[k]);
+	     invtransfo.push_back(-t[k]);
+	   } 
+
+	}
+	   void *temp_ptr; 
+           int isPeriodic = EN_getDataPtr((pEntity) vt1 , tagPeriodic, &temp_ptr);
+	   if(isPeriodic) {
+	      std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+              unsigned int i=0;
+	      for(i=0 ; i<(*recup).size() ; i++) {
+	        unsigned int j=0;
+		for(j=0 ; j<(*recup)[i].first.size() ; j++) {
+		  if((*recup)[i].first[j] != transfo[j]) break;
+		}
+		if(j==(*recup)[i].first.size() ) break;
+	      }
+	      if(i==(*recup).size())
+	        (*recup).push_back(std::pair <std::vector<int> , pVertex>(transfo,vt2));
+	   } else {
+             std::vector<std::pair<std::vector<int> , MDB_Point*> > remotePoints;
+	     (remotePoints).push_back(std::pair <std::vector<int> , pVertex>(transfo,vt2));
+	      EN_attachDataPtr((pEntity) vt1 , tagPeriodic, 
+	    			new std::vector<std::pair<std::vector<int> , pVertex> >(remotePoints));
+				   
+	   }
+	   
+           isPeriodic = EN_getDataPtr((pEntity) vt2 , tagPeriodic, &temp_ptr);
+	   if(isPeriodic) {
+	      std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+              unsigned int i;
+	      for(i=0 ; i<(*recup).size() ; i++) {
+	        unsigned int j;
+		for(j=0 ; j<(*recup)[i].first.size() ; j++) {
+		  if((*recup)[i].first[j] != invtransfo[j]) break;
+		}
+		if(j==(*recup)[i].first.size() ) break;
+	      }
+	      if(i==(*recup).size())
+                (*recup).push_back(std::pair <std::vector<int> , pVertex>(invtransfo,vt1));
+	   } else {
+             std::vector<std::pair<std::vector<int> , MDB_Point*> > remotePoints;
+	     (remotePoints).push_back(std::pair <std::vector<int> , pVertex>(invtransfo,vt1));
+	      EN_attachDataPtr((pEntity) vt2 , tagPeriodic, 
+	    			new std::vector<std::pair<std::vector<int> , pVertex> >(remotePoints));	   
+	    }
+          }
+          delete []t;
+	}
+ 
+       }
+    }  
+  } 
+
+  // compute parametric coordinates of vertices on
+//   VIter vit = M_vertexIter(m); 
+//   pVertex pv;  
+//   while (pv = VIter_next(vit))
+//     {
+//       int vType=V_whatInType(pv);
+//       if(vType==1)
+// 	{
+// 	  double xyz[3];
+// 	  V_coord(pv, xyz);
+// 	  pGEdge pge = (pGEdge) EN_whatIn(pv);
+// 	  double par = pge->parFromPoint(SPoint3(xyz[0],xyz[1],xyz[2])); 
+// 	  printf("parametric coord is %12.5E\n",par);
+// 	  P_setParam1(pv, par);
+// 	}
+//     }	
+  fclose(fp);
+}
+
+
+
+*/
+
diff --git a/Mesh/MeshDataBaseIO.h b/Mesh/MeshDataBaseIO.h
new file mode 100644
index 0000000..3524e4d
--- /dev/null
+++ b/Mesh/MeshDataBaseIO.h
@@ -0,0 +1,44 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere, Cecile Dobrzynski
+// -------------------------------------------------------------------
+
+#ifndef _LOADGMSHMESH_H_
+#define _LOADGMSHMESH_H_
+
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseCommPeriodic.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+
+  // Load a Gmsh mesh
+  //   - msh1 or msh2
+  //   - serial or parallel (format msh2 for parallel)
+  //   - periodic or non-periodic
+  void LoadGmshMesh (MAd::pMesh, const char *);
+
+  // Save a mesh
+  //   - msh1 or msh2
+  //   - serial only
+  //   - If a partitioning table is submitted, 
+  //     write the right partition numbers in the file
+  void SaveGmshMesh (const MAd::pMesh, const char *, int version=2, 
+                     const int * partitionTable=NULL);
+
+  void SaveGmshMeshPer (const MAd::pMesh, const char *,  MDB_DataExchangerPeriodic &deperiodic,int version=1);
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Mesh/MeshDataBaseInterface.cc b/Mesh/MeshDataBaseInterface.cc
new file mode 100644
index 0000000..b13422b
--- /dev/null
+++ b/Mesh/MeshDataBaseInterface.cc
@@ -0,0 +1,2905 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere, Koen Hillewaert
+// -------------------------------------------------------------------
+
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseParallelInterface.h"
+#include "MeshDataBase.h"
+#include "MeshDataBaseIO.h"
+#include "PList.h"
+#include "ParallelUtils.h"
+#include "MAdDefines.h"
+#include "MathUtils.h"
+#include <string>
+#include <map>
+#ifdef PARALLEL
+#include "MeshDataBaseParallelIO.h"
+#endif
+#include "MAdMessage.h"
+#include "MAdSingleton.h"
+
+#include <sstream>
+
+/*! \defgroup mesh      Mesh operations */
+/*! \defgroup entity    Entity operations */
+/*! \defgroup region    Region operations */
+/*! \defgroup face      Face operations */
+/*! \defgroup edge      Edge operations */
+/*! \defgroup vertex    Vertex operations */
+/*! \defgroup point     Point operations */
+/*! \defgroup ios       Mesh in- and output */
+/*! \defgroup parallel  Communication */
+/*! \defgroup internal  Internal routines */ 
+
+typedef MAdSingleton< std::map <std::string, unsigned int> > attachableDataIds;
+typedef MAdSingleton< std::map <unsigned int, std::string > > attachableDataIds_rev;
+
+namespace MAd {
+
+  pMeshDataId newMeshDataId(const std::string tag)
+  {
+    std::string tag2;
+    if ( !strcmp(tag.c_str(),"") ) {
+      tag2 = "X";
+      bool unique = false;
+      while ( !unique )
+        {
+          std::map<std::string, unsigned int>::iterator iter = (attachableDataIds::instance()).find(tag2);
+          if(iter != (attachableDataIds::instance()).end()) {
+            tag2 = tag2 + "X";
+          }
+          else unique = true;
+        }
+    }
+    else tag2 = tag;
+
+    std::map<std::string, unsigned int>::iterator iter = (attachableDataIds::instance()).find(tag2);
+    if(iter != (attachableDataIds::instance()).end()) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "Mesh data id with tag \'%s\' already exists",tag2.c_str());
+      return (*iter).second;
+    }
+    if((attachableDataIds::instance()).empty())
+      {
+        (attachableDataIds_rev::instance())[1] = tag2;
+        (attachableDataIds::instance())    [tag2] = 1;
+        return 1;
+      }
+    else
+      {
+        unsigned int biggest = (*(--(attachableDataIds_rev::instance()).end())).first;
+        (attachableDataIds_rev::instance())[biggest+1] = tag2;
+        (attachableDataIds::instance())    [tag2] = biggest+1;
+        return biggest+1;
+      }
+  }
+
+  pMeshDataId MD_newMeshDataId(const std::string tag) 
+  {
+    return newMeshDataId(tag);
+  }
+
+  pMeshDataId MD_lookupMeshDataId(const std::string tag) {
+    std::map <std::string, unsigned int>::const_iterator it = 
+      (attachableDataIds::instance()).find(tag);
+    if(it == (attachableDataIds::instance()).end())return newMeshDataId(tag);
+    return (*it).second;
+  }
+
+  void MD_deleteMeshDataId(pMeshDataId id) {
+    (attachableDataIds::instance()).erase((attachableDataIds_rev::instance())[id]);
+    (attachableDataIds_rev::instance()).erase(id);
+  }
+
+  //!  Returns type/dimension of element pe \ingroup entity 
+  int EN_type(pEntity pe)
+  {
+    return pe->getDim();
+  }
+
+  //!  Remove data with tag t from element pe \ingroup entity 
+
+  void EN_removeData(pEntity pe, const char *t)
+  {
+    unsigned int itag = MD_lookupMeshDataId(t);
+    pe->deleteData (itag);
+  }
+
+  //!  Add pointer data to element pe with tag \ingroup entity 
+  void EN_attachDataP(pEntity pe, const char *tag, void *data)
+  {
+    unsigned int itag = MD_lookupMeshDataId(tag);
+    EN_attachDataPtr(pe, itag, data);
+  }
+
+  //!  Remove data with tag id from element pe \ingroup entity 
+  void EN_deleteData(pEntity pe, pMeshDataId id)
+  {
+    pe->deleteData (id);
+  }
+
+  //! Replace data with tag id with value \ingroup entity 
+  void EN_modifyDataPtr(pEntity ent, pMeshDataId id, void * value)
+  {
+    EN_attachDataPtr(ent, id, value);
+  }
+
+  //!  Add pointer data to element pe with tag \ingroup entity 
+  void EN_attachDataPtr(pEntity pe, pMeshDataId id, void * value)
+  {
+    mAttachableVoid *av = (mAttachableVoid *)pe->getData(id);
+    if(!av)
+      {
+        av = new mAttachableVoid;
+        pe->attachData(id,av);
+      }
+    av->veryNastyPointer = value;
+  }
+
+  //!  Get pointer data with tag from element \ingroup entity 
+  void * EN_dataP(pEntity pe, const char *tag)
+  {  
+    unsigned int itag = MD_lookupMeshDataId(tag);
+    mAttachableVoid *av = (mAttachableVoid *)pe->getData(itag);
+    if(!av)return 0;
+    return av->veryNastyPointer;
+  }
+
+  //! Replace data with tag id with value \ingroup entity 
+  int EN_modifyDataP(pEntity pe, const char *tag, void * data)
+  {
+    EN_attachDataP(pe, tag, data);
+    return 1;
+  }
+
+
+  //! Add integer data with tag id to element pe \ingroup entity 
+  void EN_attachDataI(pEntity pe, const char *tag, int data)
+  {
+    pe->attachInt(MD_lookupMeshDataId(tag),data);
+  }
+
+  //! Add integer data with tag id to element pe \ingroup entity 
+  void EN_attachDataInt(pEntity pe, pMeshDataId id, int data)
+  {
+    pe->attachInt(id,data);
+  }
+
+  //! Get integer data with tag id from element pe \ingroup entity 
+  int EN_dataI(pEntity pe, const char *tag)
+  {
+    return pe->getAttachedInt(MD_lookupMeshDataId(tag));
+  }
+
+
+  //! Get floating precision data pointer with tag id from element pe \ingroup entity 
+  int EN_getDataDbl(pEntity ent, pMeshDataId id, double *value)
+  {   
+    mAttachableDouble *ai = (mAttachableDouble *)ent->getData(id);
+    if(!ai)return 0;
+    *value = ai->d;
+    return 1;
+    //*value = ent->getAttachedDouble(id);
+    //return 1;
+  }
+
+  //! Add floating precision data pointer with tag id to element pe \ingroup entity 
+  void EN_attachDataDbl(pEntity ent, pMeshDataId id, double value)
+  {
+    ent->attachDouble(id,value);
+  }
+
+
+  //! Modify floating precision data pointer with tag id in element pe \ingroup entity 
+  void EN_modifyDataDbl(pEntity ent, pMeshDataId id, double value)
+  {
+    ent->attachDouble(id,value);
+  }
+
+  //! Modify integer data with tag id in element pe \ingroup entity 
+  int EN_modifyDataI(pEntity pe, const char *tag, int data)
+  {
+    pe->attachInt(MD_lookupMeshDataId(tag),data);
+    return 1;
+  }
+
+  //! Modify integer data with tag id in element pe \ingroup entity 
+  void EN_modifyDataInt(pEntity ent, pMeshDataId id, int value)
+  {
+    ent->attachInt(id,value);
+  }
+
+
+  //! Get address of data pointer with tag id in element pe \ingroup entity 
+  int EN_getDataPtr(pEntity ent, pMeshDataId id, void **value)
+  {
+  
+    mAttachableVoid *av = (mAttachableVoid *)ent->getData(id);
+    if(!av)return 0;
+    *value =  av->veryNastyPointer;
+    return 1;
+  }
+
+  //! Get integer data with tag id from element pe \ingroup entity 
+  int EN_getDataInt(pEntity ent, pMeshDataId id, int *value)
+  { 
+    mAttachableInt *ai = (mAttachableInt *)ent->getData(id);
+    (*value) = 0;
+    if(!ai)return 0;
+    *value = ai->i;
+    return 1;
+  
+    //*value = ent->getAttachedInt(id);
+    //if(*value)return 1;
+    //return 0;
+  }
+
+  pMesh M_new(pGModel pm)
+  {
+    pMesh m = new MDB_Mesh;
+    m->model = pm;
+    return m;
+  }
+
+  void M_delete(pMesh pm)
+  {
+    if (pm) { delete pm; pm=NULL; }
+  }
+
+  //! Load a mesh from a file \ingroup ios
+  //!   - msh1 or msh2
+  //!   - serial or parallel (format msh2 for parallel)
+  //!   - periodic or non-periodic
+  void M_load(pMesh pm, const char *filename)
+  {
+    LoadGmshMesh (pm, filename);
+
+    pMeshDataId remoteTag =  MD_lookupMeshDataId("RemotePoint");
+
+    V_createInfoInterface(pm,remoteTag);
+    E_createInfoInterface(pm,remoteTag);
+    F_createInfoInterface(pm,remoteTag);
+    
+  }
+
+  //! Save a mesh \ingroup ios
+  //!   - msh1 or msh2
+  //!   - serial or parallel
+  //!   - If a partitioning table is submitted, 
+  //!     write the right partition numbers in the file
+  void M_writeMsh(const pMesh mesh, const char *name, 
+                  int version, const int * partitionTable)
+  {
+#ifdef PARALLEL
+    SaveGmshMeshParallel (mesh, name, version);
+#else
+    SaveGmshMesh (mesh, name, version, partitionTable);
+#endif
+  }
+
+  //! Save a periodic mesh \ingroup ios
+  void M_writeMshPer(pMesh mesh, const char *name, MDB_DataExchangerPeriodic &deperiodic, int version)
+  {
+    SaveGmshMeshPer(mesh,name,deperiodic,version);
+  }
+
+  //! returns geometric model \ingroup mesh
+  pGModel M_model(pMesh mesh)
+  {
+    return mesh->model;
+  }
+
+  //! reduces the mesh to its minimal datastructure  \ingroup mesh
+  void M_shrink(pMesh mesh)
+  {
+    mesh->shrink();
+  }
+
+  //! reverts the mesh to its usable form \ingroup mesh
+  void M_expand(pMesh mesh)
+  {
+    mesh->expand();
+  }
+
+  //! removes all deleted entities - clean up \ingroup mesh
+  void M_clean(pMesh mesh)
+  {
+    RIter rIter = M_regionIter(mesh);
+    while ( RIter_next(rIter) ) {}
+    RIter_delete(rIter);
+
+    FIter fIter = M_faceIter(mesh);
+    while ( FIter_next(fIter) ) {}
+    FIter_delete(fIter);
+  
+    EIter eIter = M_edgeIter(mesh);
+    while ( EIter_next(eIter) ) {}
+    EIter_delete(eIter);
+  
+    VIter vIter = M_vertexIter(mesh);
+    while ( VIter_next(vIter) ) {}
+    VIter_delete(vIter);
+  }
+
+  // -------------------------------------------------------------------
+  //! Dump informations on the mesh \ingroup mesh
+  void M_info(const pMesh mesh, std::ostream& out)
+  {
+    out << "\n";
+    out << "Mesh statistics:\n";
+    out << "  Number of regions : " << M_numRegions(mesh)  << "\n";
+    out << "  Number of faces   : " << M_numFaces(mesh)    << "\n";
+    out << "  Number of edges   : " << M_numEdges(mesh)    << "\n";
+    out << "  Number of vertices: " << M_numVertices(mesh) << "\n";
+    out << "\n";
+  }
+
+  // -------------------------------------------------------------------
+#ifdef _HAVE_METIS_
+  //! Serial function to partition a mesh and write the partitioned mesh to a file in msh2 format  \ingroup parallel
+  void M_Partition(pMesh mesh, int nbParts, const char *filename)
+  {
+    PartitionMesh(mesh, nbParts, filename);
+  }
+#endif
+
+  // -------------------------------------------------------------------
+  //! Returns the dimension of the mesh \ingroup mesh
+  int M_dim(pMesh pm)
+  {
+    if      ( M_numRegions(pm)  > 0 ) return 3;
+    else if ( M_numFaces(pm)    > 0 ) return 2;
+    else if ( M_numEdges(pm)    > 0 ) return 1;
+    else if ( M_numVertices(pm) > 0 ) return 0;
+    return -1;
+  }
+
+  // -------------------------------------------------------------------
+  //! returns the maximum mapping order for mesh edges \ingroup mesh
+  int M_edgeMaxOrder(pMesh mesh) 
+  {
+    EIter eIter = M_edgeIter(mesh);
+    int o = 0;
+    while (pEdge pe = EIter_next(eIter)) o = std::max(o,pe->getOrder());
+    EIter_delete(eIter);
+    return o;
+  }
+  
+  //! returns the maximum mapping order for mesh face \ingroup mesh
+  int M_faceMaxOrder(pMesh mesh) 
+  {
+    FIter fIter = M_faceIter(mesh);
+    int o = 0;
+    while (pFace pf = FIter_next(fIter)) o = std::max(o,pf->getOrder());
+    FIter_delete(fIter);
+    return o;
+  }
+  
+  //! returns the maximum mapping order for mesh regions \ingroup mesh
+  int M_regionMaxOrder(pMesh mesh) 
+  {
+    RIter rIter = M_regionIter(mesh);
+    int o = 0;
+    while (pRegion pr = RIter_next(rIter)) o = std::max(o,pr->getOrder());
+    RIter_delete(rIter);
+    return o;
+  }
+
+  //! returns the maximum mapping order for all elements \ingroup mesh
+  int M_maxOrder(pMesh mesh) { 
+    return std::max(M_edgeMaxOrder(mesh),
+                    std::max(M_faceMaxOrder(mesh),
+                             M_regionMaxOrder(mesh)));
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns true if boundary nodes have parametric coordinates \ingroup mesh
+  bool M_isParametric(pMesh mesh)
+  {
+    return mesh->isParametric();
+  }
+
+  // -------------------------------------------------------------------
+  //! returns number of regions in mesh \ingroup mesh \ingroup mesh
+  int M_numRegions(pMesh pm)
+  {
+    return pm->nbTets + pm->nbHexes + pm->nbPrisms;
+  }
+
+  //! returns number of tetrahedra in mesh \ingroup mesh
+  int M_numTets(pMesh pm)
+  {
+    return pm->nbTets;
+  }
+
+  //! returns number of hexahedra in mesh \ingroup mesh
+  int M_numHexes(pMesh pm)
+  {
+    return pm->nbHexes;
+  }
+
+  //! returns number of prism in mesh \ingroup mesh
+  int M_numPrisms(pMesh pm)
+  {
+    return pm->nbPrisms;
+  }
+
+  //! returns number of faces in mesh \ingroup mesh
+  int M_numFaces(pMesh pm)
+  {
+    return pm->nbTriangles + pm->nbQuads;
+  }
+
+  //! returns number of triangles in mesh \ingroup mesh
+  int M_numTriangles(pMesh pm)
+  {
+    return pm->nbTriangles;
+  }
+
+  //! returns number of quadrilaterals in mesh \ingroup mesh
+  int M_numQuads(pMesh pm)
+  {
+    return pm->nbQuads;
+  }
+
+  //! returns number of edges in mesh \ingroup mesh
+  int M_numEdges(pMesh pm)
+  {
+    return pm->nbEdges;
+  }
+
+  //! returns number of vertices in mesh \ingroup mesh
+  int M_numVertices(pMesh pm)
+  {
+    return pm->nbPoints;
+  }
+
+  //! returns number of regions classified on ge \ingroup mesh
+  int M_numClassifiedRegions(pMesh m,pGEntity ge) {
+
+    return countClassifiedElements< MDB_ListT , MDB_Tet , pGEntity> (&m->tets,ge);
+  }
+
+  //! returns number of faces classified on ge \ingroup mesh
+  int M_numClassifiedFaces(pMesh m,pGEntity ge) {
+
+    return countClassifiedElements< MDB_ListF , MDB_Triangle , pGEntity> (&m->triangles,ge);
+  }
+
+  //! returns number of edges classified on ge \ingroup mesh
+  int M_numClassifiedEdges(pMesh m,pGEntity ge) {
+
+    return countClassifiedElements< MDB_ListE , MDB_Edge , pGEntity> (&m->edges,ge);
+  }
+
+  //! returns number of vertices classified on ge \ingroup mesh
+  int M_numClassifiedVertices(pMesh m,pGEntity ge) {
+
+    return countClassifiedElements< MDB_SetV , MDB_Point , pGEntity> (&m->points,ge);
+  }
+
+  //! returns region iterator over mesh \ingroup mesh
+  /*! \warning not thread-safe */
+  RIter M_regionIter(pMesh mesh)
+  {  
+    return new MDB_RegionIter (&mesh->tets,&mesh->hexes,&mesh->prisms);
+  }
+
+  //! returns face iterator over mesh \ingroup mesh
+  /*! \warning not thread-safe */
+  FIter M_faceIter(pMesh mesh)
+  {
+    return new MDB_FaceIter (&mesh->triangles,&mesh->quads);
+  }
+
+  //! returns edge iterator over mesh \ingroup mesh
+  /*! \warning not thread-safe */
+  EIter M_edgeIter(pMesh mesh)
+  {
+    return  new MDB_EIter (&mesh->edges);
+  }
+
+  //! returns vertex iterator over mesh \ingroup mesh
+  /*! \warning not thread-safe */
+  VIter M_vertexIter(pMesh mesh)
+  {
+    return new MDB_VIter (&mesh->points);
+  }
+
+  //! returns iterator for regions in \e mesh classified on model entity \e pg \ingroup mesh
+  /*!
+    When done with it, should be deleted  with function RIter_delete() to avoid
+    memory leaks.
+  */
+  RIter M_classifiedRegionIter(pMesh mesh,pGEntity pg)
+  {  
+    return new MDB_RegionIter (&mesh->tets,&mesh->hexes,&mesh->prisms,pg);
+  }
+
+  //! returns iterator for faces in \e mesh classified on model entity \e pg \ingroup mesh
+  /*!
+    The argument \e c (closure) must currently be set to 0. Only the faces directly classified on \e pg will be considered. \n
+    Example: if \e pg is a model region, the mesh faces classified on the model
+    faces bordering \e pg will not be reachable with the present iterator. \n \n
+    When done with it, should be deleted  with function FIter_delete() to avoid
+    memory leaks.
+  */
+  FIter M_classifiedFaceIter(pMesh mesh,pGEntity pg,int c)
+  {
+    return new MDB_FaceIter (&mesh->triangles,&mesh->quads,pg,c);
+  }
+
+  //! returns iterator for edges in \e mesh classified on model entity \e pg \ingroup mesh
+  /*!
+    The argument \e c (closure) must currently be set to 0. Only the edges directly classified on \e pg will be considered. \n
+    Example: if \e pg is a model region, the mesh edges classified on the model
+    edges and faces bordering \e pg will not be reachable with the present iterator. \n \n
+    When done with it, should be deleted  with function EIter_delete() to avoid
+    memory leaks.
+  */
+  EIter M_classifiedEdgeIter(pMesh mesh,pGEntity pg,int c)
+  {
+    return  new MDB_EIter (&mesh->edges,pg,c);
+  }
+
+  //! returns iterator for vertices in \e mesh classified on model entity \e pg \ingroup mesh
+  /*!
+    The argument \e c (closure) must currently be set to 0. Only the vertices directly classified on \e pg will be considered. \n
+    Example: if \e pg is a model region, the mesh vertices classified on the model
+    vertices, edges and faces bordering \e pg will not be reachable with the present iterator. \n \n
+    When done with it, should be deleted  with function VIter_delete() to avoid
+    memory leaks.
+  */
+  VIter M_classifiedVertexIter(pMesh mesh,pGEntity pg,int c)
+  {
+    return new MDB_VIter (&mesh->points,pg,c);
+  }
+
+  //! returns vertex in \e mesh classified on model vertex \e pg \ingroup mesh
+  /*!
+    returns 0 if failed
+  */
+  pVertex M_classifiedVertex(pMesh mesh,pGVertex pg)
+  {
+    return (MDB_VIter(&mesh->points,(pGEntity) pg,0)).next();
+  }
+
+  // -------------------------------------------------------------------
+  // Iterators
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  pRegion RIter_next(RIter it)
+  {
+    return it->next();
+  }
+  pFace FIter_next(FIter it)
+  {
+    return it->next();
+  }
+  pEdge EIter_next(EIter it)
+  {
+    return it->next();
+  }
+  pVertex VIter_next(VIter it)
+  {
+    return it->next();
+  }
+
+  // -------------------------------------------------------------------
+  void RIter_reset(RIter it)
+  {
+    it->reset();
+  }
+  void FIter_reset(FIter it)
+  {
+    it->reset();
+  }
+  void EIter_reset(EIter it)
+  {
+    it->reset();
+  }
+  void VIter_reset(VIter it)
+  {
+    it->reset();
+  }
+
+  // -------------------------------------------------------------------
+  void RIter_delete(RIter it)
+  {
+    delete it;
+  }
+  void FIter_delete(FIter it)
+  {
+    delete it;
+  }
+  void EIter_delete(EIter it)
+  {
+    delete it;
+  }
+  void VIter_delete(VIter it)
+  {
+    delete it;
+  }
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  // Region operators
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  //! Dumps all informations about the region. \ingroup region
+  void R_info(const pRegion region, std::string name, std::ostream& out)
+  {
+    out << "\nRegion \'" << name << "\' (" << region 
+        << ", Id: "<<(int)EN_id((pEntity)region)
+        <<") informations:\n";
+
+    out << "  Classification:  ";
+    pGEntity pGE = (pGEntity)R_whatIn(region);
+    if (!pGE) {
+      out << "NULL";
+    }
+    else {
+      out << "GEntity: " << pGE 
+          << ", dim: " << GEN_type(pGE)
+          << ", tag: " << GEN_tag(pGE);
+    }
+    out << "\n";
+
+    R_info_quality(region, out);
+    R_info_topology(region, out);
+
+    out << "\n";
+  }
+
+  // -------------------------------------------------------------------
+  //! Dumps quality informations about the region. \ingroup region
+  void R_info_quality(const pRegion region, std::ostream& out)
+  {
+    out << "  Quality informations:\n";
+    double volume = R_volume(region);
+    out << "    Volume      : " << volume  << "\n";
+    if (volume < 0.) out << "  *** Negative volume ***\n";
+    else {
+      out << "    r/R ratio : " << R_inscrRad(region)/R_circumRad(region)<< "\n";
+      double meanRatio3;
+      R_meanRatioCube(region,&meanRatio3);
+      out << "    Cubic mean ratio : " << meanRatio3 << "\n";
+    }
+  }
+
+  // -------------------------------------------------------------------
+  //! Dumps topology informations about the region. \ingroup region
+  void R_info_topology(const pRegion region, std::ostream& out)
+  {
+    out << "  Topology informations:\n";
+    out << "\n    Faces       (ids):   type  geom ent.      tag   orient\n";
+    for (int iF=0; iF<R_numFaces(region); iF++) {
+      pFace face = R_face(region,iF);
+      pGEntity pGE = F_whatIn(face);
+      int gTag = pGE ? GEN_tag(pGE) : -1;
+      int gDim = pGE ? GEN_type(pGE) : -1;
+      out << " " << face << " (" << EN_id((pEntity)face) << ") " 
+          << gDim << "   " << pGE << " " << gTag << " " 
+          << R_faceDir(region,iF) << "\n";
+    }
+    out << "\n    Edges       (ids):   type  model ent.      tag   orient\n";
+    pPList rEdges = R_edges(region);
+    void * temp = NULL;
+    while( pEdge edge = (pEdge)PList_next(rEdges,&temp) ) {
+      pGEntity pGE = E_whatIn(edge);
+      int gTag = pGE ? GEN_tag(pGE) : -1;
+      int gDim = pGE ? GEN_type(pGE) : -1;
+      out << " " << edge << " (" << EN_id((pEntity)edge) << ") " 
+          << gDim << "   " << pGE << " " << gTag << "\n";
+    }
+    PList_delete(rEdges);
+
+    out << "\nVertices    (ids):   type  model ent.      tag               coordinates\n";
+    pPList rVerts = R_vertices(region);
+    temp = NULL;
+    while( pVertex pV = (pVertex)PList_next(rVerts,&temp) ) {
+      double xyz[3];
+      V_coord(pV,xyz);
+      pGEntity pGE = V_whatIn(pV);
+      int gTag = pGE ? GEN_tag(pGE) : -1;
+      int gDim = pGE ? GEN_type(pGE) : -1;
+      out << " " << pV << " (" << EN_id((pEntity)pV) << ") " 
+          << gDim << "   " << pGE << " " << gTag << " " 
+          << xyz[0] << " " << xyz[1] << " " << xyz[2] << "\n";
+    }
+    PList_delete(rVerts);
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns number of faces for region "r" \ingroup region
+  int R_numFaces(pRegion pr)
+  {
+    return pr->getNbFace ();
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns n-th face for region "r" \ingroup region
+  pFace R_face(pRegion pr, int n)
+  {
+    return pr->getFace(n);
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns number of edges for region "r" \ingroup region
+  int R_numEdges(pRegion pr)
+  {
+    return pr->getNbEdge();
+  }
+
+  // -------------------------------------------------------------------
+  //! Classify region "r" on geometric entity "ge" \ingroup region
+  void R_setWhatIn(pRegion region, pGEntity what)
+  {
+    region->g = what;
+    for (int iF=0; iF<region->getNbFace(); iF++) {
+      pFace face = region->getFace(iF);
+      if ( GEN_type(face->g) > GEN_type(what) ) F_setWhatIn(face,what);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns n-th edge of region "r"
+  pEdge R_edge(pRegion pr, int n)
+  { 
+    return pr->getEdge(n);
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns number of principal vertices in region "r" \ingroup region
+  int R_numVertices(pRegion pr)
+  {
+    return pr->getNbVertex();
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns nth vertex in region "r" \ingroup region
+  pVertex R_vertex(pRegion pr, int n)
+  {
+    return pr->getVertex (n);
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns 1 if the face normal points outwards of region pr, 0 otherwise \ingroup region
+  int R_faceDir (pRegion pr, int n)
+  {
+    return pr->getFaceDir(n);
+  }
+
+  // -------------------------------------------------------------------
+  //! Determine face orientation with respect to the template of the region "r" \ingroup region
+  /*!
+    \warning Only implemented for tetrahedra
+    Returns s*(n+1), if the face is part of the closure of the region, 0 otherwise \n
+    Here
+    \li n is the number of times we need to rotate the face to correspond 
+    with the principal vertex of the face in the element
+    \li s is the sign of the normal with respect to that of the template
+  */
+  int R_faceOri(pRegion pr,int n) 
+  {
+    return pr->getFaceOrientation(n);
+  }
+
+  // -------------------------------------------------------------------
+  //! Return a list of ordered edges \ingroup region
+  pPList R_edges(pRegion pr)
+  {
+    pPList pl = PList_new();
+    for (int i=0;i<pr->getNbEdge();i++)
+      PList_append(pl,R_edge(pr,i));
+    return pl;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns a list of ordered faces \ingroup region
+  pPList R_faces(pRegion pr)
+  {
+    pPList pl = PList_new();
+    for (int i=0;i<pr->getNbFace();i++)
+      PList_append(pl,R_face(pr,i));
+    return pl;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns a list of ordered principal vertices \ingroup region
+  pPList R_vertices(pRegion pr)
+  {
+    pPList pl = PList_new();
+    for (int i=0;i<pr->getNbVertex();i++)
+      PList_append(pl,R_vertex(pr,i));
+    return pl;
+  }
+
+  // -------------------------------------------------------------------
+  //! Verify whether or not entity ent is a principal vertex, edge or face of region "r" \ingroup region
+  int R_inClosure(pRegion pr, pEntity ent)
+  {
+    int dim = EN_type (ent);
+    if (dim == 2)
+      {
+        for (int i=0;i<pr->getNbFace();i++)
+          {
+            if (R_face(pr,i)== ent) return 1;
+          }
+        return 0;
+      }
+    else if (dim ==1)
+      {
+        for (int i=0;i<pr->getNbEdge();i++)
+          {
+            if (R_edge(pr,i)== ent) return 1;
+          }
+        return 0;
+      }
+    else if (dim ==0)
+      {
+        for (int i=0;i<pr->getNbVertex();i++)
+          {
+            if (R_vertex(pr,i) == ent) return 1;
+          }
+        return 0;
+      }
+    else throw;
+  }
+
+  // -------------------------------------------------------------------
+  // !return 1 if the face direction points to outside of the tet
+  // !return 0                                 inside
+  int R_dirUsingFace(pRegion pr, pFace face)
+  {
+    for (int i=0;i<pr->getNbFace();i++)
+      if (pr->getFace(i) == face)
+        return R_faceDir (pr,i);
+    throw;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the orientation of the face pf in region pr \ingroup region
+  /*! Returns -1 if the face is not in the closure of the region */
+  int R_oriUsingFace(pRegion pr, pFace face)
+  {
+    for (int i=0;i<pr->getNbFace();i++)
+      if (pr->getFace(i) == face)
+        return R_faceOri (pr,i);
+    return -1;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns n-th higher order point inside of the region, excluding those in its closure \ingroup region
+  pPoint R_point(pRegion pr, int n)
+  {
+    return pr->getHighOrderPoint (n);
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the number of higher order points of the region, excluding those in its closure \ingroup region
+  int R_numPoints(pRegion pr)
+  {
+    return pr->getNbHighOrderPoints();
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns 1 if the direction of the edge in pf follows the template, 0 otherwise \ingroup face
+  int F_dirUsingEdge(pFace pf, pEdge edge)
+  {
+    const int nbEdge = pf->getNbEdges ();
+    for (int i=0;i<nbEdge;i++)
+      if (pf->getEdge(i) == edge)
+        return F_edgeDir (pf,i);
+    throw;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the geometrical entity on which the region "r" is classified \ingroup region
+  pGRegion R_whatIn(pRegion pe)
+  {
+    return (pGRegion) pe->g;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the type of the geometrical entity on which region "r" is classified \ingroup region
+  int R_whatInType(pRegion e) { return EN_whatInType(e);}
+
+  // -------------------------------------------------------------------
+  //! Get coordinates of vertices of the region not including high-order points. \ingroup region
+  void R_coordP1(const pRegion region, double xyz[][3])
+  {
+    int iNode = 0;
+
+    // Summits of the region (first order nodes)
+    pPList rVerts = R_vertices(region);
+    void * temp = NULL;
+    while ( pVertex pV = (pVertex)PList_next(rVerts,&temp) ) {
+      V_coord(pV,xyz[iNode]);
+      iNode++;
+    }
+    PList_delete(rVerts);
+  }
+
+  // -------------------------------------------------------------------
+  //! Get coordinates of vertices and high-order points of the region. \ingroup region
+  void R_coord(const pRegion region, double xyz[][3])
+  {
+    // Summits of the region (first order nodes)
+    R_coordP1(region,xyz);
+    int iNode = region->getNbVertex();
+
+    // points on edges (higher order nodes)
+    pPList rEdges = R_edges(region);
+    void * temp = NULL;
+    while ( pEdge edge = (pEdge) PList_next(rEdges, &temp)) {
+      int nEPts = E_numPoints(edge);
+      for (int iEP=0; iEP<nEPts; iEP++) {
+        pPoint pP = E_point(edge,iEP);
+        xyz[iNode][0] = P_x(pP); xyz[iNode][1] = P_y(pP); xyz[iNode][2] = P_z(pP);
+        iNode++;
+      }
+    }
+    PList_delete(rEdges);
+
+    // points on face (higher order nodes)
+    pPList rFaces = R_faces(region);
+    temp = NULL;
+    while ( pFace face = (pFace) PList_next(rFaces, &temp)) {
+      int nFPts = F_numPoints(face);
+      for (int iFP=0; iFP<nFPts; iFP++) {
+        pPoint pP = F_point(face,iFP);
+        xyz[iNode][0] = P_x(pP); xyz[iNode][1] = P_y(pP); xyz[iNode][2] = P_z(pP);
+        iNode++;
+      }
+    }
+    PList_delete(rFaces);
+
+    // points on region (higher order nodes)
+    int nRPts = R_numPoints(region);
+    for (int iRP=0; iRP<nRPts; iRP++) {
+      pPoint pP = R_point(region,iRP);
+      xyz[iNode][0] = P_x(pP); xyz[iNode][1] = P_y(pP); xyz[iNode][2] = P_z(pP);
+      iNode++;
+    }
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the physical volume of the region. \ingroup region
+  double R_volume(pRegion region)
+  {
+    double xyz[12][3];
+    R_coordP1(region,xyz);
+    return R_XYZ_volume(xyz);
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the physical volume of the region with coordinates xyz. \ingroup region 
+  double R_XYZ_volume (const double xyz[][3])
+  {
+    double e01[3], e02[3], e03[3];
+    diffVec(xyz[1],xyz[0],e01);
+    diffVec(xyz[2],xyz[0],e02);
+    diffVec(xyz[3],xyz[0],e03);
+    double nor012[3];
+    crossProd(e01,e02,nor012);
+    return ( dotProd(nor012,e03) * MAdSIXTH );
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the circumradius of the region \ingroup region
+  double R_circumRad(const pRegion region)
+  {
+    double xyz[4][3];
+    R_coordP1(region,xyz);
+
+    double edges0x[3][3];
+    for (int i=0; i<3; i++) diffVec(xyz[i+1],xyz[0],edges0x[i]);
+    double detEdgesInv = 1. / ( detMat(edges0x) );
+
+    double edgeMids[3][3];
+    for (int i=0; i<3; i++) {
+      for (int j=0; j<3; j++) {
+        edgeMids[i][j] = (xyz[0][j] + xyz[i+1][j]) * 0.5;
+      }
+    }
+
+    double tmpVec[3];
+    for (int i=0; i<3; i++) tmpVec[i] = dotProd(edges0x[i],edgeMids[i]);
+  
+    double center[3];
+    double tmpMat[3][3];
+    for (int i=0; i<3; i++) {
+      tmpMat[i][0] = tmpVec[i];
+      tmpMat[i][1] = edges0x[i][1];
+      tmpMat[i][2] = edges0x[i][2];
+    }
+    center[0] = detMat(tmpMat);
+
+    for (int i=0; i<3; i++) {
+      tmpMat[i][0] = edges0x[i][0];
+      tmpMat[i][1] = tmpVec[i];
+      tmpMat[i][2] = edges0x[i][2];
+    }
+    center[1] = detMat(tmpMat);
+
+    for (int i=0; i<3; i++) {
+      tmpMat[i][0] = edges0x[i][0];
+      tmpMat[i][1] = edges0x[i][1];
+      tmpMat[i][2] = tmpVec[i];
+    }
+    center[2] = detMat(tmpMat);
+    
+    for (int i=0; i<3; i++) { center[i] *= detEdgesInv; }
+  
+    double tmpVec2[3];
+    diffVec(center,xyz[0],tmpVec2);
+
+    return sqrt( tmpVec2[0]*tmpVec2[0] + tmpVec2[1]*tmpVec2[1] + tmpVec2[2]*tmpVec2[2]);
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the inscribed radius of the region \ingroup region
+  double R_inscrRad(const pRegion region)
+  {
+    double xyz[4][3];
+    R_coordP1(region,xyz);
+
+    double edges0x[5][3];
+    for (int i=0; i<3; i++) {
+      diffVec(xyz[i+1],xyz[0],edges0x[i]);
+    } 
+    diffVec(xyz[1],xyz[2],edges0x[3]);
+    diffVec(xyz[2],xyz[3],edges0x[4]);
+
+    double tmpVec[3];
+    double A = 0.;
+
+    crossProd(edges0x[0],edges0x[1],tmpVec);
+    A += sqrt( dotProd(tmpVec,tmpVec) ) * 0.5;
+    double V = dotProd(tmpVec,edges0x[2]) * MAdSIXTH;
+    crossProd(edges0x[1],edges0x[2],tmpVec);
+    A += sqrt( dotProd(tmpVec,tmpVec) ) * 0.5;
+    crossProd(edges0x[2],edges0x[0],tmpVec);
+    A += sqrt( dotProd(tmpVec,tmpVec) ) * 0.5;
+    crossProd(edges0x[3],edges0x[4],tmpVec);
+    A += sqrt( dotProd(tmpVec,tmpVec) ) * 0.5;
+
+    return ( 3. * V ) / A;
+  }
+
+  // -------------------------------------------------------------------
+  //! Computes the cubic mean ratio of a region. Returns 0 if negative volume. \ingroup region
+  bool R_meanRatioCube(const pRegion region, double * mrc)
+  {
+    double xyz[4][3];
+    R_coordP1(region,xyz);
+    return R_XYZ_meanRatioCube(xyz,mrc) ;
+  }
+
+  // -------------------------------------------------------------------
+  //! Computes the cubic mean ratio of a region with coordinates xyz. Returns false if negative volume. \ingroup region
+  bool R_XYZ_meanRatioCube(const double xyz[][3], double * mrc)
+  {
+    double edges[6][3];
+    diffVec(xyz[0],xyz[1],edges[0]);
+    diffVec(xyz[0],xyz[2],edges[1]);
+    diffVec(xyz[0],xyz[3],edges[2]);
+    diffVec(xyz[1],xyz[2],edges[3]);
+    diffVec(xyz[1],xyz[3],edges[4]);
+    diffVec(xyz[2],xyz[3],edges[5]);
+
+    // compute the sum of edges length square
+    double lSq = 0.;
+    for (int iE=0; iE<6; iE++) {
+      lSq += dotProd(edges[iE],edges[iE]);
+    }
+
+    // compute volume
+    double vol = R_XYZ_volume(xyz);
+    if ( vol < 0. ) {
+      *mrc = 0.;
+      return false;
+    }
+
+    // compute cubic mean ratio
+    *mrc = 15552. * vol * vol / ( lSq * lSq * lSq );
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  //! Check if the region with coordinates xyz \ingroup region
+  //! is nearly flat or with a negative volume.
+  bool R_XYZ_isFlat(const double xyz[][3])
+  {
+    for(int i=0; i<4; i++) {
+      int ind[3];
+      switch (i) {
+      case 0:
+        ind[0] = 1;
+        ind[1] = 3;
+        ind[2] = 2;
+        break;
+      case 1:
+        ind[0] = 0;
+        ind[1] = 2;
+        ind[2] = 3;
+        break;
+      case 2:
+        ind[0] = 3;
+        ind[1] = 1;
+        ind[2] = 0;
+        break;
+      case 3:
+        ind[0] = 0;
+        ind[1] = 1;
+        ind[2] = 2;
+        break;
+      }
+
+      double v01[3], v02[3];
+      diffVec(xyz[ind[1]],xyz[ind[0]],v01);
+      diffVec(xyz[ind[2]],xyz[ind[0]],v02);
+
+      double normal[3];
+      crossProd(v01,v02,normal);
+      double ASq = dotProd(normal,normal);
+
+      double v0X[3];
+      diffVec(xyz[i],xyz[ind[0]],v0X);
+      double distA = dotProd(v0X,normal);
+    
+      if( distA <= 0. || distA*distA < MAdTOL*MAdTOL*ASq) return true;
+    }
+
+    return false;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the vertex of the region opposite to the face. \ingroup region
+  pVertex R_fcOpVt(const pRegion region, const pFace face)
+  {
+    pVertex opp = NULL;
+
+    pPList fVerts = F_vertices(face,1);
+    pPList rVerts = R_vertices(region);
+
+    void * tempR = NULL;
+    while( pVertex pRV = (pVertex)PList_next(rVerts,&tempR) ) {
+      bool foundVertInFace = false;
+      void * tempF = NULL;
+      while( pVertex pFV = (pVertex)PList_next(fVerts,&tempF) ) {
+        if ( pFV == pRV ) {
+          foundVertInFace = true;
+          break;
+        }
+      }
+      if ( !foundVertInFace ) {
+        opp = pRV;
+        break;
+      }
+    }
+    PList_delete(rVerts);
+    PList_delete(fVerts);
+
+    return opp;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the edge of the region opposite to given edge. \ingroup region
+  pEdge R_gtOppEdg(const pRegion region, const pEdge edge)
+  {
+    assert( region->getNbEdge() == 6 );
+
+    pVertex v0 = E_vertex(edge,0);
+    pVertex v1 = E_vertex(edge,1);
+
+    for (int iE=0; iE<6; iE++) {
+
+      pEdge rEdge = R_edge(region,iE);
+
+      if ( rEdge == edge ) continue;
+
+      pVertex rEV0 = E_vertex(rEdge,0);
+      if ( rEV0 == v0 || rEV0 == v1 ) continue;
+      pVertex rEV1 = E_vertex(rEdge,1);
+      if ( rEV1 == v0 || rEV1 == v1 ) continue;
+
+      return rEdge;
+    }
+
+    MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                "could not find opposite edge");
+    throw;
+    return NULL;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the face of the region opposite to the vertex. \ingroup region
+  pFace R_vtOpFc(const pRegion region, const pVertex vertex)
+  {
+    assert( region->getNbFace() == 4 );
+  
+    for (int iF=0; iF<R_numFaces(region); iF++ ) {
+      pFace face = R_face(region,iF);
+      pPList fVerts = F_vertices(face,1);
+      if ( PList_inList(fVerts,vertex) ) {
+        PList_delete(fVerts);
+        continue;
+      }
+      PList_delete(fVerts);
+      return face;
+    }
+
+    return NULL;
+  }
+  
+  // -------------------------------------------------------------------
+  //! Finds the coordinates in the parent element 
+  void R_linearParams(const pRegion pR, const double xyz[3], 
+                      double res[3])
+  {
+    double rxyz[4][3];
+    R_coordP1(pR,rxyz);
+  
+    double mat[3][3];
+    mat[0][0] = rxyz[1][0] - rxyz[0][0];
+    mat[0][1] = rxyz[1][1] - rxyz[0][1];
+    mat[0][2] = rxyz[1][2] - rxyz[0][2];
+    mat[1][0] = rxyz[2][0] - rxyz[0][0];
+    mat[1][1] = rxyz[2][1] - rxyz[0][1];
+    mat[1][2] = rxyz[2][2] - rxyz[0][2];
+    mat[2][0] = rxyz[3][0] - rxyz[0][0];
+    mat[2][1] = rxyz[3][1] - rxyz[0][1];
+    mat[2][2] = rxyz[3][2] - rxyz[0][2];
+    
+    double invMat[3][3];
+    inverseMat(mat,invMat);
+    
+    double vec[3];
+    diffVec(xyz,rxyz[0],vec);
+
+    vecMat(vec,invMat,res);
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the center of a linear region. \ingroup region
+  void R_center(const pRegion region, double center[3])
+  {
+    double rxyz[4][3];
+    R_coordP1(region,rxyz);
+    center[0] = 0.25 * ( rxyz[0][0] + rxyz[1][0] + rxyz[2][0] + rxyz[3][0] );
+    center[1] = 0.25 * ( rxyz[0][1] + rxyz[1][1] + rxyz[2][1] + rxyz[3][1] );
+    center[2] = 0.25 * ( rxyz[0][2] + rxyz[1][2] + rxyz[2][2] + rxyz[3][2] );
+  }
+
+  // -------------------------------------------------------------------
+  // Get the Jacobian of a tetrahedron
+  void R_jacobian(const pRegion region, double jac[3][3])
+  {
+    double xyz[4][3];
+    R_coordP1(region,xyz);
+    for (int i=0; i<3; i++) {
+      jac[i][0] = xyz[1][i] - xyz[0][i];
+      jac[i][1] = xyz[2][i] - xyz[0][i];
+      jac[i][2] = xyz[3][i] - xyz[0][i];
+    }
+  }
+
+  // -------------------------------------------------------------------
+  // Get the inverse of the Jacobian of a tetrahedron
+  // returns the determinant of the Jacobian
+  double R_invJacobian(const pRegion region, double ijac[3][3])
+  {
+    double jac[3][3];
+    R_jacobian(region,jac);
+    return inverseMat(jac,ijac);
+  }
+
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  // Face operators
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  //! Dumps informations about the face. \ingroup face
+  void F_info(const pFace face, std::string name, std::ostream& out)
+  {
+    out << "\n";
+    out << "Face \'" << name << "\' " << face
+        << ", id: " << EN_id((pEntity)face) << "\n";
+    out << "  Classified on " << face->g 
+        << " with dim " << GEN_type(face->g) 
+        << " and tag "  << GEN_tag(face->g) << "\n";
+
+    out << "\n--- Regions:\n";
+    for (int iR=0; iR<2; iR++) {
+      pRegion region = face->getRegion(iR);
+      if (!region) {
+        out << "Region "<<iR<<": "<<region<<"\n";
+      }
+      else {
+        out << "Region "<<iR<<" (" << region 
+            << ", Id: "<<(int)EN_id((pEntity)region)
+            <<") informations:\n";
+        out << "  Classification:  ";
+        pGEntity pGE = (pGEntity)R_whatIn(region);
+        if (!pGE) {
+          out << "NULL";
+        }
+        else {
+          out << "GEntity: " << pGE 
+              << ", dim: " << GEN_type(pGE)
+              << ", tag: " << GEN_tag(pGE);
+        }
+        out << "  Vertex opposite to face: \n";
+        V_info(R_fcOpVt(region,face),"",out);
+        out << "\n";
+      }
+    }
+
+    out << "\n--- Edges:\n";
+    for (int iE=0; iE<face->getNbEdges(); iE++) {
+      pEdge edge = face->getEdge(iE);
+      out << "Edge " << iE << ":\n";
+      E_info(edge, "", out);
+    }
+
+//       out << "Edge "<<iE<<" ("<< edge <<"), id " 
+//           << EN_id((pEntity)edge) <<":\n";
+//       pGEntity pGE = EN_whatIn((pEntity)edge);
+//       out << "  - Classification: dim: " << GEN_type(pGE) << ", tag: " << GEN_tag(pGE) << "\n";
+//       pVertex pv0 = E_vertex(edge,0);
+//       pVertex pv1 = E_vertex(edge,1);
+//       pGEntity pGE0 = EN_whatIn((pEntity)pv0);
+//       pGEntity pGE1 = EN_whatIn((pEntity)pv1);
+//       out << "  - Vertices classifications:\n"
+//           << "      - V0: dim: " << GEN_type(pGE0) << ", tag: " << GEN_tag(pGE0) << "\n"
+//           << "      - V1: dim: " << GEN_type(pGE1) << ", tag: " << GEN_tag(pGE1) << "\n";
+//       out << "\n";
+//     }
+    out << "\n";
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns number of edges in pf \ingroup face
+  int F_numEdges(pFace pf)
+  {
+    return pf->getNbEdges();
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns n-th edge in pf \ingroup face
+  pEdge F_edge(pFace pf, int n)
+  {
+    return pf->getEdge(n);
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns number of vertices in pf \ingroup face
+  int F_numVertices(pFace pf)
+  {
+    return pf->getNbNodes();
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns n-th vertex in pf \ingroup face
+  pVertex F_vertex(pFace pf, int n)
+  {
+    return pf->getNode(n);
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns 1 if the direction of the n-th edge in pf follows the template, 0 otherwise \ingroup face
+  int F_edgeDir (pFace pf, int n)
+  {
+    pEdge e = F_edge (pf,n);
+    pVertex ve1 = E_vertex (e,0);
+    pVertex ve2 = E_vertex (e,1);
+    pVertex vf1 = F_vertex (pf,n);
+    pVertex vf2 = F_vertex (pf,(n+1)%3);
+    if (ve1 == vf1 && ve2 == vf2) return 1;
+    if (ve2 == vf1 && ve1 == vf2) return 0;
+    throw;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns number of regions referring to pf \ingroup face
+  int F_numRegions(pFace pf)
+  {
+    return pf->getNbRegions();
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the ordered list of vertices of pf \ingroup face
+  //! if dir \< 0 order is inverted, else the template is followed
+  pPList F_vertices(pFace pf, int dir)
+  {
+    pPList pl = PList_new();
+    if (dir<=0)
+      {
+        PList_append(pl,F_vertex(pf,2));
+        PList_append(pl,F_vertex(pf,1));
+        PList_append(pl,F_vertex(pf,0));
+      }
+    else
+      {
+        PList_append(pl,F_vertex(pf,0));
+        PList_append(pl,F_vertex(pf,1));
+        PList_append(pl,F_vertex(pf,2));
+      }
+    return pl;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the ordered list of edges composing the closure of pf \ingroup face
+  pPList F_edges(pFace pf)
+  {
+    pPList pl = PList_new();
+    PList_append(pl,F_edge(pf,0)); 
+    PList_append(pl,F_edge(pf,1)); 
+    PList_append(pl,F_edge(pf,2)); 
+    return pl;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the n-th region attached to pf \ingroup face
+  pRegion F_region(pFace pf, int n)
+  {
+    return pf->getRegion(n);
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the list of regions attached to pf \ingroup face
+  pPList F_regions(pFace pf)
+  {
+    pPList pl = PList_new();
+    for (int i=0;i<pf->getNbRegions();++i)
+      PList_append(pl,F_region(pf,i));  
+    return pl;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the region around 'pf' which is not 'pr' or NULL if none \ingroup face
+  pRegion F_otherRegion(const pFace pf, const pRegion pr)
+  {
+    if ( pf->getRegion(0) == pr ) return pf->getRegion(1);
+    if ( pf->getRegion(1) == pr ) return pf->getRegion(0);
+    MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                "Face not in the closure of region");
+    return NULL;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns 1 if ent is in the closure of pf, else 0 \ingroup face
+  int F_inClosure(pFace f, pEntity ent)
+  {
+    int dim = EN_type (ent);
+
+    if (dim ==1)
+      {
+        for (int i=0;i<f->getNbEdges();i++)
+          {
+            if (F_edge(f,i)== ent) return 1;
+          }
+        return 0;
+      }
+    else if (dim ==0)
+      {
+        for (int i=0;i<f->getNbEdges();i++)
+          {
+            if (F_vertex(f,i) == ent) return 1;
+          }
+        return 0;
+      }
+    else throw;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the geometric entity to which pf is attached \ingroup face
+  pGEntity F_whatIn(pFace pf)
+  {
+    return pf->g;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the type/dimension of the geometric entity to which pf is attached \ingroup face
+  int F_whatInType(pFace e)   { return EN_whatInType(e);}
+
+  // -------------------------------------------------------------------
+  //! Classify pf on geometric entity 'what' \ingroup face
+  void F_setWhatIn(pFace face, pGEntity what)
+  {
+    face->g = what;
+    for (int iE=0; iE<face->getNbEdges(); iE++) {
+      pEdge edge = face->getEdge(iE);
+      if ( GEN_type(edge->g) > GEN_type(what) ) E_setWhatIn(edge,what);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  //! Inverts the direction of face pf by switching edge 1 and 2 \ingroup face
+  /*! \warning only implemented for triangles */
+  void F_chDir(pFace pf) 
+  {
+    assert (pf->getNbEdges() == 3);
+    {
+      MDB_Triangle *t = (MDB_Triangle*)pf;
+      pEdge temp = t->e2;
+      t->e2 = t->e1;
+      t->e1 = temp;
+    }
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the n-th higher-order point attached to pf, excluding the closure \ingroup face
+  pPoint F_point(pFace f, int n)
+  {
+    return f->getHighOrderPoint (n);
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the number of higher-order points attached to pf, excluding the closure \ingroup face
+  int F_numPoints(pFace f)
+  {
+    return f->getNbHighOrderPoints();
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the number of points attached to pf, including summits and points in closure \ingroup face
+  int F_numPointsTot(pFace f)
+  {
+    int numPt = f->getNbNodes() + f->getNbHighOrderPoints();
+
+    pPList list = F_edges(f);
+    void * temp = NULL;
+    while ( pEdge edge = (pEdge) PList_next(list, &temp)) {
+      numPt += edge->getNbHighOrderPoints();
+    }
+    PList_delete(list);
+
+    return numPt;
+  }
+
+  // -------------------------------------------------------------------
+  //! Aligns the face with a set of points
+  //! will return zero if not successful
+  //! otherwise the absolute value will contain the index of the element vertex coinciding with the first vertex
+  //! the sign indicates the orientation 
+  int F_align(pFace pf,pVertex pv1,pVertex pv2,pVertex pv3,pVertex pv4)
+  {
+    return pf->align(pv1,pv2,pv3,pv4);
+  }
+
+  // -------------------------------------------------------------------
+  //! Gets coordinates of vertices of the face, not including high-order points. \ingroup face
+  void F_coordP1(const pFace face, double xyz[][3])
+  {
+    int iNode = 0;
+
+    // Summits of the face (first order nodes)
+    pPList fVerts = F_vertices(face,1);
+    void * temp = NULL;
+    while ( pVertex pV = (pVertex)PList_next(fVerts,&temp)) {
+      V_coord(pV,xyz[iNode]);
+      iNode++;
+    }
+    PList_delete(fVerts);
+  }
+
+  // -------------------------------------------------------------------
+  //! Gets coordinates of points of the face including high-order points. \ingroup face
+  void F_coord(const pFace face, double xyz[][3])
+  {
+    // Summits of the face (first order nodes)
+    F_coordP1(face,xyz);
+    int iNode = face->getNbNodes();
+
+    // points on edges (higher order nodes)
+    pPList fEdges = F_edges(face);
+    void * temp = NULL;
+    while ( pEdge edge = (pEdge) PList_next(fEdges, &temp)) {
+      int nEPts = E_numPoints(edge);
+      for (int iEP=0; iEP<nEPts; iEP++) {
+        pPoint pP = E_point(edge,iEP);
+        xyz[iNode][0] = P_x(pP); xyz[iNode][1] = P_y(pP); xyz[iNode][2] = P_z(pP);
+        iNode++;
+      }
+    }
+    PList_delete(fEdges);
+
+    // points on face (higher order nodes)
+    int nFPts = F_numPoints(face);
+    for (int iFP=0; iFP<nFPts; iFP++) {
+      pPoint pP = F_point(face,iFP);
+      xyz[iNode][0] = P_x(pP); xyz[iNode][1] = P_y(pP); xyz[iNode][2] = P_z(pP);
+      iNode++;
+    }
+  }
+
+  // -------------------------------------------------------------------
+  //! Gets the parametric coordinates of the summits of the face \ingroup face
+  //! in the geometric entity on which it is classified.
+  //! Returns false if parametric coordinates are not available.
+  bool F_params(const pFace face, double u[][2])
+  {
+#ifdef _HAVE_GMSH_
+    pGEntity faceGE = F_whatIn(face);
+    int gDim = GEN_type(faceGE);
+    if ( gDim != 2 ) return false;
+
+    for (int iV=0; iV<F_numVertices(face); iV++)
+      {
+        pVertex pv = F_vertex(face,iV);
+        pGEntity vG = EN_whatIn(pv);
+        int vGDim = GEN_type(vG);
+        
+        switch ( vGDim ) {
+        case 3: throw;
+        case 2: {
+          assert ( vG == faceGE );
+          if ( !V_params(pv,&u[iV][0],&u[iV][1]) ) return false;
+          break;
+        }
+        case 1: {
+          double tmp0,tmp1;
+          if ( !V_params(pv,&tmp0,&tmp1) ) return false;
+          GE_reparamOnFace( (pGEdge)vG, (pGFace)faceGE, tmp0, u[iV], NULL );
+          break;
+        }
+        case 0: {
+          GV_reparamOnFace( (pGVertex)vG, (pGFace)faceGE, u[iV], NULL );
+          break;
+        }
+        }
+      }
+    return true;
+#else
+    return false;
+#endif
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns area of a triangular face \ingroup face
+  //! if 'dir' is not NULL, the area is signed
+  double F_area(const pFace face, const double * dir)
+  {
+    double fxyz[4][3];
+    F_coordP1(face,fxyz);
+    return XYZ_F_area(fxyz,dir);
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns area of a triangular face \ingroup face
+  //! if 'dir' is not NULL, the area is signed
+  double XYZ_F_area(const double xyz[][3], const double * dir)
+  {
+    double areaSq = XYZ_F_areaSq(xyz, dir);
+    if ( areaSq >= 0. ) return sqrt(areaSq);
+    return -1.0 * sqrt ( -1.0*areaSq );
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns square area of a triangular face. \ingroup face
+  //! if 'dir' is not NULL, the square area is signed
+  double F_areaSq(const pFace face, const double * dir)
+  {
+    double xyz[3][3];
+    F_coordP1(face,xyz);
+    return XYZ_F_areaSq(xyz,dir);
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns square area of a triangular face with coordinates xyz. \ingroup face
+  //! if 'dir' is not NULL, the square area is signed
+  double XYZ_F_areaSq(const double xyz[][3], const double * dir)
+  {
+    double e01[3], e02[3], normal[3];
+    diffVec(xyz[1],xyz[0],e01);
+    diffVec(xyz[2],xyz[0],e02);
+    crossProd(e01,e02,normal);
+    if( dir && ( dotProd(dir,normal) < 0. ) ) {
+      return -0.25 * dotProd(normal,normal);
+    }
+    return 0.25 * dotProd(normal,normal);
+  }
+  // -------------------------------------------------------------------
+  //! Returns the center of a triangular linear face. \ingroup face
+  void F_center(const pFace face, double center[])
+  {
+    double fxyz[3][3];
+    F_coordP1(face,fxyz);
+    center[0] = MAdTHIRD * ( fxyz[0][0] + fxyz[1][0] + fxyz[2][0] );
+    center[1] = MAdTHIRD * ( fxyz[0][1] + fxyz[1][1] + fxyz[2][1] );
+    center[2] = MAdTHIRD * ( fxyz[0][2] + fxyz[1][2] + fxyz[2][2] );
+  }
+  
+  // -------------------------------------------------------------------
+  //! Returns the coordinates (u,v) of the point in the parent element
+  void F_linearParams(const pFace pF, const double xyz[3], 
+                      double res[2])
+  {
+    // using barycentric coordinates
+    double fxyz[3][3];
+    F_coordP1(pF,fxyz);
+  
+    Tri_linearParams(fxyz,xyz,res);
+  }
+
+  // -------------------------------------------------------------------
+  //! Computes the normal vector of the face \ingroup face
+  //! The normal is not normalized
+  void F_normal(const pFace face, double normal[3])
+  {
+    double xyz[4][3];
+    F_coordP1(face,xyz);
+    double v01[3],v02[3];
+    diffVec(xyz[1],xyz[0],v01);
+    diffVec(xyz[2],xyz[0],v02);
+    crossProd(v01,v02,normal);
+  }
+
+  // -------------------------------------------------------------------
+  //! Computes the normal vector of a triangle with given coordinates \ingroup face
+  //! The normal is not normalized
+  void XYZ_F_normal(const double xyz[3][3], double normal[3])
+  {
+    double v01[3],v02[3];
+    diffVec(xyz[1],xyz[0],v01);
+    diffVec(xyz[2],xyz[0],v02);
+    crossProd(v01,v02,normal);
+  }
+  
+  // -------------------------------------------------------------------
+  //! Computes the ratio between the regions around the face \ingroup face
+  //! Returns false if there is less than 2 regions
+  bool F_volumeRatio(const pFace face, double * ratio) 
+  {
+    const pRegion pr0 = F_region(face,0);
+    const pRegion pr1 = F_region(face,1);
+  
+    if ( !( pr0 && pr1 ) ) return false;
+  
+    double vol0 = R_volume(pr0);
+    double vol1 = R_volume(pr1);
+  
+    if( vol0 <= 0. || vol1 <= 0. ) *ratio = -1.;
+    else *ratio = ( vol0 < vol1 ) ? vol1/vol0 : vol0/vol1;
+  
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  //! Computes the maximal volume ratio among the faces \ingroup face
+  double F_worstVolumeRatio(const std::set<pFace> faces)
+  {
+    double maxRatio = 0.;
+  
+    std::set<pFace>::const_iterator fIter = faces.begin();
+    for(; fIter != faces.end(); fIter++ ) {
+      double ratio;
+      if ( !F_volumeRatio(*fIter,&ratio) ) continue;
+      if( ratio < 0. )    return -1;
+      if( ratio > maxRatio ) maxRatio = ratio;
+    }
+  
+    return maxRatio;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the vertex of face opposite to edge \ingroup face
+  pVertex F_edOpVt(const pFace face, const pEdge edge)
+  {
+    assert(face->getNbEdges() == 3);
+
+    pVertex v0 = E_vertex(edge,0);
+    pVertex v1 = E_vertex(edge,1);
+
+    for (int iE=0; iE<3; iE++) {
+      pEdge pE = face->getEdge(iE);
+      if (pE==edge) continue;
+      pVertex pEv0 = E_vertex(pE,0);
+      if ( pEv0 != v0 && pEv0 != v1 ) return pEv0;
+      else return E_vertex(pE,1);
+    }
+
+    return NULL;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the edge of face opposite to vertex \ingroup face
+  pEdge F_vtOpEd(const pFace face, const pVertex vertex)
+  {
+    assert(face->getNbEdges() == 3);
+
+    for (int iE=0; iE<3; iE++) {
+      pEdge pE = face->getEdge(iE);
+      if ( E_vertex(pE,0) != vertex &&
+           E_vertex(pE,1) != vertex ) {
+        return pE;
+      }
+    }
+    return NULL;
+  }
+
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  // Edge operators
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  //! Dumps informations about the edge. \ingroup edge
+  void E_info(const pEdge edge, std::string name, std::ostream& out)
+  {
+    out << "\n";
+    out << "Edge \'" << name << "\' " << edge 
+        << ", id: " << EN_id((pEntity)edge) << "\n";
+    pGEntity pGE = EN_whatIn((pEntity)edge);
+    out << "  - Classification: dim: " << GEN_type(pGE) << ", tag: " << GEN_tag(pGE) << "\n";
+    pVertex pv0 = E_vertex(edge,0);
+    pVertex pv1 = E_vertex(edge,1);
+    out << "  - Vertices:\n"
+        << "     * Vertex 0:\n";
+    V_info(pv0, "", out);
+    out << "     * Vertex 1:\n";
+    V_info(pv1, "", out);
+    out << "\n";
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the number of regions attached to the edge pe \ingroup edge
+  int E_numRegions(pEdge pe)
+  {
+    pPList rlist = E_regions(pe);
+    int num = PList_size(rlist);
+    PList_delete(rlist);
+    return num;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the number of vertices in edge pe \ingroup edge
+  //! Guess what, there are two !
+  int E_numVertices(pEdge pe)
+  {
+    return 2;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the n-th vertex of edge pe \ingroup edge
+  /*! \warning will throw an error for n>1 */
+  pVertex E_vertex(pEdge pe, int n)
+  {
+    switch(n){
+    case 0 : return pe->p1;
+    case 1 : return pe->p2;
+    }
+    throw;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns a list of the vertices of edge pe \ingroup edge
+  pPList E_vertices(const pEdge pe)
+  {
+    pPList vList;
+    PList_append(vList,pe->p1);
+    PList_append(vList,pe->p2);
+    return vList;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the number of faces attached to edge pe \ingroup edge
+  int E_numFaces(pEdge pe)
+  {
+    return pe->numfaces() ;
+  }  
+
+  // -------------------------------------------------------------------
+  //! Returns a list of regions attached to edge pe \ingroup edge
+  pPList E_regions(pEdge e)
+  {
+    pPList pl = PList_new();
+    for (int i=0;i<e->numfaces();++i)
+      {
+        pFace pf = e->faces(i);
+        for(int k=0;k<pf->getNbRegions();k++)
+          PList_appUnique(pl,pf->getRegion(k));
+      }
+    return pl;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the number of higher-order points on edge pe, excluding vertices \ingroup edge
+  int E_numPoints(pEdge pE)
+  {
+    return pE->getNbHighOrderPoints ();
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the n-th face attached to edge pe \ingroup edge
+  pFace E_face(pEdge pe, int n)
+  {
+    return pe->faces(n);
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the list of faces connected to the edge \ingroup edge
+  pPList E_faces(const pEdge pe)
+  {
+    pPList eFaces = PList_new();
+    for (int iF=0; iF < pe->numfaces(); iF++) {
+      PList_append(eFaces,pe->faces(iF));
+    }
+    return eFaces;    
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns 1 of ent is one of the vertices of edge pe, else 0 \ingroup edge
+  int E_inClosure(pEdge pe, pEntity ent)
+  {
+    if (pe->p1 == ent) return 1;
+    if (pe->p2 == ent) return 1;
+    return 0;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the other face attached to edge pe belonging to the closure of region r \ingroup edge
+  pFace E_otherFace(pEdge edge, pFace face, pRegion r)
+  {
+    for (int i=0;i<r->getNbFace();i++)
+      {
+        pFace f1 = r->getFace(i);
+        if (f1 != face && F_inClosure (f1,edge) ) return f1;
+      }
+    throw;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the other vertex of edge pe \ingroup edge
+  pVertex  E_otherVertex(pEdge e, pVertex v)
+  {
+    if(e->p1 == v)return e->p2;
+    if(e->p2 == v)return e->p1;
+    throw;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the n-th higher order point - excluding vertices - of edge pe \ingroup edge
+  pPoint E_point(pEdge e, int n)
+  {
+    return e->getHighOrderPoint (n);
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the geometrical entity on which entity 'pe' is classified \ingroup entity
+  pGEntity EN_whatIn(pEntity pe)
+  {
+    return pe->g;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the type/dimension of the geometrical entity on which edge pe is classified \ingroup edge
+  pGEntity  E_whatIn(pEdge pe)
+  {
+    return pe->g;
+  }
+
+  // -------------------------------------------------------------------
+  //! Classify entity e on the geometrical entity 'what'  \ingroup entity
+  void EN_setWhatIn(pEntity e, pGEntity what){e->g = what;}
+
+  // -------------------------------------------------------------------
+  //! Classify edge e on the geometrical entity 'what'  \ingroup entity
+  void E_setWhatIn(pEdge edge, pGEntity what)
+  {
+    edge->g = what;
+    pPoint p1 = edge->p1;
+    if ( GEN_type(p1->g) > GEN_type(what) ) V_setWhatIn(p1,what);
+    pPoint p2 = edge->p2;
+    if ( GEN_type(p2->g) > GEN_type(what) ) V_setWhatIn(p2,what);
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the type/dimension of the geometrical entity on which edge pe is classified \ingroup edge
+  int E_whatInType(pEdge e)   { return EN_whatInType(e);}
+
+  // -------------------------------------------------------------------
+  //! Aligns the current edge with the node order \ingroup edge
+  //! returns 1 if the edge is already aligned, -1 if the edge is inverted and 0 if the edge does not correspond
+  int E_align(pEdge pe,pVertex pv1,pVertex pv2) {return pe->align(pv1,pv2);}
+
+  // -------------------------------------------------------------------
+  //! Returns 1 of the edge is oriented from first vertex \ingroup edge
+  //! to second one, 0 otherwise
+  int E_dir(pEdge pe, pVertex pv1, pVertex pv2) {
+    if (pe->p1 == pv1 && pe->p2 == pv2) return 1;
+    if (pe->p1 == pv2 && pe->p2 == pv1) return 0;
+    throw;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns coordinates of vertices of the edge not including high-order points. \ingroup edge
+  void E_coordP1(const pEdge edge, double xyz[][3]) 
+  {
+    // points of extremities
+    MDB_Point * pP1 = edge->p1;
+    xyz[0][0] = P_x(pP1);
+    xyz[0][1] = P_y(pP1);
+    xyz[0][2] = P_z(pP1);
+    MDB_Point * pP2 = edge->p2;
+    xyz[1][0] = P_x(pP2);
+    xyz[1][1] = P_y(pP2);
+    xyz[1][2] = P_z(pP2);
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns coordinates of vertices of the edge including high-order points. \ingroup edge
+  void E_coord(const pEdge edge, double xyz[][3]) 
+  {
+    E_coordP1(edge,xyz);
+
+    // points on edges (higher order nodes)
+    int n = E_numPoints(edge);
+    for (int i=0; i<n; i++) {
+      pPoint pnt = E_point(edge,i);
+      xyz[2+i][0] = P_x(pnt); xyz[2+i][1] = P_y(pnt); xyz[2+i][2] = P_z(pnt);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  //! Gets the parametric coordinates of the summits of the edge \ingroup edge
+  //! in the geometric entity on which it is classified.
+  //! Returns false if parametric coordinates are not available.
+  bool E_params(const pEdge edge, double u[2][2])
+  {
+#ifdef _HAVE_GMSH_
+
+    pGEntity edgeGE = E_whatIn(edge);
+    int gDim = GEN_type(edgeGE);
+  
+    if ( gDim != 1 && gDim != 2 ) return false;
+
+    for (int iV=0; iV<2; iV++) {
+    
+      pVertex pv = E_vertex(edge,iV);
+      pGEntity vG = EN_whatIn(pv);
+      int vGDim = GEN_type(vG);
+
+      // --------------------------------------------------------------------
+      // edge classified on a surface: we want the parameters on the surface
+      // --------------------------------------------------------------------
+      if ( gDim == 2 ) {
+
+        switch ( vGDim ) {
+        case 3: throw;
+        case 2: {
+          if ( !V_params(pv,&u[iV][0],&u[iV][1]) ) return false;
+//           printf("node on face %d: %lf %lf\n",GEN_tag(edgeGE),u[iV][0],u[iV][1]);
+          break;
+        }
+        case 1: {
+          double tmp0,tmp1;
+          if ( !V_params(pv,&tmp0,&tmp1) ) return false;
+
+          double * otherU = NULL;
+          if ( GE_isSeam( (pGEdge)vG, (pGFace)edgeGE ) )
+            {
+              pVertex otherV = E_vertex(edge,1-iV);
+              double tmp20,tmp21;
+              if ( V_whatInType(otherV)==2 && V_params(otherV,&tmp20,&tmp21) ) {
+                otherU = new double[2];
+                otherU[0] = tmp20;
+                otherU[1] = tmp21;
+              }
+              else if ( V_whatInType(otherV)==1 && V_params(otherV,&tmp20,&tmp21) ) {
+                if ( GE_isSeam( (pGEdge)V_whatIn(otherV), (pGFace)edgeGE ) ) {
+                  MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+                                                "Found a surface with 2 seams");
+                  return false;
+                }
+                otherU = new double[2];
+                GE_reparamOnFace( (pGEdge)V_whatIn(otherV), (pGFace)edgeGE, 
+                                  tmp20, &(otherU[0]) );
+                otherU[1] = -1.;
+              }
+            }
+          GE_reparamOnFace( (pGEdge)vG, (pGFace)edgeGE, tmp0, u[iV], otherU );
+//           printf("node from edge %d on face %d: %lf %lf\n",GEN_tag(vG),GEN_tag(edgeGE),u[iV][0],u[iV][1]);
+          break;
+        }
+        case 0: {
+          double tmp0,tmp1;
+          if ( !V_params(pv,&tmp0,&tmp1) ) return false;
+
+          double * otherU = NULL;
+          if ( GV_isOnSeam( (pGVertex)vG, (pGFace)edgeGE ) ) 
+            {
+              pVertex otherV = E_vertex(edge,1-iV);
+              double tmp20,tmp21;
+              if ( V_whatInType(otherV)==2 && V_params(otherV,&tmp20,&tmp21) ) {
+                otherU = new double[2];
+                otherU[0] = tmp20;
+                otherU[1] = tmp21;
+              }
+              else if ( V_whatInType(otherV)==1 && V_params(otherV,&tmp20,&tmp21) ) {
+                if ( GE_isSeam( (pGEdge)V_whatIn(otherV), (pGFace)edgeGE ) ) {
+                  MAdMsgSgl::instance().warning(__LINE__,__FILE__,
+                                                "Found a surface with 2 seams");
+                  return false;
+                }
+                otherU = new double[2];
+                GE_reparamOnFace( (pGEdge)V_whatIn(otherV), (pGFace)edgeGE, 
+                                  tmp20, &(otherU[0]) );
+                otherU[1] = -1.;
+              }
+            }
+          GV_reparamOnFace( (pGVertex)vG, (pGFace)edgeGE, u[iV], otherU );
+//           printf("vert %d on face %d: %lf %lf\n",GEN_tag(vG),GEN_tag(edgeGE),u[iV][0],u[iV][1]);
+          break;
+        }
+        }
+      }
+
+      // --------------------------------------------------------------
+      // edge classified on a line: we want the parameters on the line
+      // --------------------------------------------------------------
+      else if ( gDim == 1) {
+
+        switch ( vGDim ) {
+        case 3: throw;
+        case 2: throw;
+        case 1: {
+          double tmp;
+          if ( !V_params(pv,&u[iV][0],&tmp) ) return false;
+          break;
+        }
+        case 0: {
+          if ( !(pv->isParametric() ) ) return false;
+
+          double otherU = -1.;
+          pVertex otherV = E_vertex(edge,1-iV);
+          double tmp20,tmp21;
+          if ( V_whatInType(otherV)==1 && V_params(otherV,&tmp20,&tmp21) ) {
+            otherU = tmp20;
+          }
+          else if ( V_whatInType(otherV)==0 ) {
+            GV_reparamOnEdge( (pGVertex)V_whatIn(otherV), (pGEdge)edgeGE, &otherU );
+          }
+
+          GV_reparamOnEdge( (pGVertex)vG, (pGEdge)edgeGE, &u[iV][0], otherU );
+          break;
+        }
+        }
+
+      }
+
+      else throw;
+    }
+
+    return true;
+#else
+    return false;
+#endif
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the physical length of the edge \ingroup edge
+  double E_length(const pEdge edge)
+  {
+    double eCoords[2][3];
+    E_coordP1(edge,eCoords);
+    double e[3];
+    diffVec(eCoords[1],eCoords[0],e);
+    return sqrt ( e[0]*e[0] + e[1]*e[1] + e[2]*e[2] );
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the physical square length of the edge \ingroup edge
+  double E_lengthSq(const pEdge edge)
+  {
+    double eCoords[2][3];
+    E_coordP1(edge,eCoords);
+    double e[3];
+    diffVec(eCoords[1],eCoords[0],e);
+    return e[0]*e[0] + e[1]*e[1] + e[2]*e[2];
+  }
+  
+  // -------------------------------------------------------------------
+  double E_linearParams(const pEdge pE, 
+                        const pVertex pv)
+  {
+    double xyz[3];
+    V_coord(pv,xyz);
+    return E_linearParams(pE,xyz);
+  }
+  
+  // -------------------------------------------------------------------
+  double E_linearParams(const pEdge pE, 
+                        const double xyz[3])
+  {
+    double eCoords[2][3];
+    E_coordP1(pE,eCoords);
+
+    double v01[3];
+    diffVec(eCoords[1],eCoords[0],v01);
+
+    double vX1[3];
+    diffVec(eCoords[1],xyz,vX1);
+    double temp = dotProd(v01,vX1);
+    if ( temp < MAdTOL ) return 1.;
+
+    double v0X[3];
+    diffVec(xyz,eCoords[0],v0X);
+    double temp2 = dotProd(v01,v0X);
+    if ( temp2 < MAdTOL ) return 0.;
+
+    double ratio = temp2 / temp;
+    return ( ratio / (1. + ratio ) );
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the center of a linear edge. \ingroup edge
+  void E_center(const pEdge edge, double center[3])
+  {
+    double exyz[2][3];
+    E_coordP1(edge,exyz);
+    center[0] = 0.5 * ( exyz[0][0] + exyz[1][0] );
+    center[1] = 0.5 * ( exyz[0][1] + exyz[1][1] );
+    center[2] = 0.5 * ( exyz[0][2] + exyz[1][2] );
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the center of the cavity surrounding an edge. \ingroup edge
+  void E_cavityCenter(const pEdge edge, double center[3])
+  {
+    if( E_whatInType(edge)!=3 ) {
+      MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                  "not implemented for edges classified on <3D");
+    }
+
+    center[0] = 0.; center[1] = 0.; center[2] = 0.;
+
+    int nbF = 0;
+    pPList vFaces = E_faces(edge);
+    void * temp = NULL;
+    while ( pFace face = (pFace)PList_next(vFaces,&temp) ) {
+      pVertex oppV = F_edOpVt(face,edge);
+      double xyz[3];
+      V_coord(oppV,xyz);
+      center[0] += xyz[0]; center[1] += xyz[1]; center[2] += xyz[2];
+      nbF++;
+    }
+    PList_delete(vFaces);
+
+    double invNbF = 1. / nbF;
+    center[0] *= invNbF; center[1] *= invNbF; center[2] *= invNbF;
+  }
+
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  // Vertex operators
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  //! Dumps informations about the vertex. \ingroup vertex
+  void V_info(const pVertex vertex, std::string name, std::ostream& out)
+  {
+    out << "\n";
+    out << "Vertex \'" << name << "\' " << vertex
+        << ", id: " << EN_id((pEntity)vertex) << "\n";
+    pGEntity pGE = EN_whatIn((pEntity)vertex);
+    out << "  - Classification: dim: " << GEN_type(pGE) << ", tag: " << GEN_tag(pGE) << "\n";
+    out << "  - Num edges: " << vertex->edges.size() << "\n";
+    out << "  - Parameters:\n";
+    double u,v;
+    if ( vertex->getParams(&u,&v) ) {
+      out << "     Point is parametric: (u,v) = ("<<u<<", "<<v<<")\n";
+    }
+    else {
+      out <<"      Point is not parametric\n";
+    }
+    out << "  - Coordinates:\n";
+    double xyz[3];
+    V_coord(vertex,xyz);
+    out << "     ( "<<xyz[0]<<", "<<xyz[1]<<", "<<xyz[2]<<" )\n";
+    out << "\n";
+    
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the type/dimension of the geometrical entity on which vertex e is classified \ingroup vertex
+  int V_whatInType(pVertex e)
+  {
+    return EN_whatInType(e);
+  }
+
+  // -------------------------------------------------------------------
+  //! Classify vertex e on the geometrical entity 'what'  \ingroup vertex
+  void V_setWhatIn(pVertex e, pGEntity what)
+  {
+    e->g = what;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the geometrical entity on which vertex pv is classified \ingroup vertex
+  pGEntity V_whatIn(pVertex pv)
+  { 
+    return pv->g;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the list of regions attached to vertex v \ingroup vertex
+  pPList V_regions(pVertex v)
+  {
+    //  3D SPECIFIC printf("coucou\n");
+    pPList pl = PList_new();
+    for (unsigned int i=0;i<v->edges.size();++i)
+      {
+        pEdge pe = v->edges[i];
+        for (int j=0;j<pe->numfaces();j++)
+          {
+            pFace pf = pe->faces(j);
+            for(int k=0;k<pf->getNbRegions();k++)
+              PList_appUnique(pl,pf->getRegion(k));
+          }
+      }  
+    return pl;
+  }
+
+  // -------------------------------------------------------------------
+  //! Copies the coordinates of vertex pv in point \ingroup vertex
+  pPoint  V_point(pVertex pv)
+  {
+    return pv;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns number of edges attached to vertex pv \ingroup vertex
+  int V_numEdges(pVertex  pv)
+  {
+    return pv->edges.size();
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns number of faces attached to vertex pv \ingroup vertex
+  int V_numFaces(pVertex  pv)
+  {
+    pPList faces =  V_faces(pv);
+    int num = PList_size(faces);
+    PList_delete(faces);
+    return num;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns number of regions attached to vertex pv \ingroup vertex
+  int V_numRegions(pVertex  pv)
+  {
+    pPList regions =  V_regions(pv);
+    int num = PList_size(regions);
+    PList_delete(regions);
+    return num;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns n-th edge attached to vertex pv \ingroup vertex
+  pEdge V_edge(pVertex pv, int n)
+  {
+    return pv->edges[n];
+  }
+
+
+  // -------------------------------------------------------------------
+  //! Returns the identity tag of the vertex pv \ingroup vertex
+  int V_id(const pVertex pv) {
+    return pv->iD;
+  }
+
+  // -------------------------------------------------------------------
+  //! Copy position of vertex p to xyz \ingroup vertex
+  void V_coord(const pVertex p, double xyz[3])
+  {
+    xyz[0] = p->X;
+    xyz[1] = p->Y;
+    xyz[2] = p->Z;
+  }
+
+  // -------------------------------------------------------------------
+  //! Gets the parametric coordinates of the vertex. \ingroup vertex
+  //! Returns false is the vertex is not parametric. 
+  bool V_params(pVertex pv, double * u, double * v)
+  {
+    return pv->getParams(u,v);
+  }
+
+  // -------------------------------------------------------------------
+  //! Return the list of faces attached to vertex v \ingroup vertex
+  pPList V_faces(pVertex v)
+  {
+    pPList pl = PList_new();
+    for (unsigned int i=0;i<v->edges.size();++i)
+      {
+        pEdge pe = v->edges[i];
+        for (int j=0;j<pe->numfaces();j++)
+          {
+            pFace pf = pe->faces(j);
+            PList_appUnique(pl,pf);
+          }
+      }
+  
+    return pl;
+  }
+
+  // -------------------------------------------------------------------
+  //! Return the list of edges attached to vertex v \ingroup vertex
+  pPList V_edges(pVertex v)
+  {
+    pPList pl = PList_new();
+    for (unsigned int i=0; i<v->edges.size(); ++i) {
+      pEdge pe = v->edges[i];
+      PList_append(pl,pe);
+    }
+  
+    return pl;
+  }
+
+  // -------------------------------------------------------------------
+  //! Compute the mean length square of the edges adjacent to the vertex \ingroup vertex
+  double V_meanEdgeLenSq(const pVertex pv)
+  {
+    double lenSq = 0.;
+    for( int iE=0; iE<V_numEdges(pv); iE++ ) {
+      lenSq += E_lengthSq( V_edge(pv,iE) );
+    }
+    lenSq /= V_numEdges(pv);
+    return lenSq;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the center of the cavity surrounding a vertex. \ingroup vertex
+  void V_cavityCenter(const pVertex vertex, double center[3])
+  {
+    center[0] = 0.; center[1] = 0.; center[2] = 0.;
+
+    int nbE = 0;
+    pPList vEdges = V_edges(vertex);
+    void * temp = NULL;
+    while ( pEdge edge = (pEdge)PList_next(vEdges,&temp) ) {
+      pVertex otherV = E_otherVertex(edge,vertex);
+      double xyz[3];
+      V_coord(otherV,xyz);
+      center[0] += xyz[0]; center[1] += xyz[1]; center[2] += xyz[2];
+      nbE++;
+    }
+    PList_delete(vEdges);
+
+    double invNbE = 1. / nbE;
+    center[0] *= invNbE; center[1] *= invNbE; center[2] *= invNbE;
+  }
+
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  // Point operators
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  //! Returns x coordinate of point p \ingroup point
+  double P_x(pPoint p){return p->X;}
+
+  // -------------------------------------------------------------------
+  //! Returns y coordinate of point p \ingroup point
+  double P_y(pPoint p){return p->Y;}
+
+  // -------------------------------------------------------------------
+  //! Returns z coordinate of point p \ingroup point
+  double P_z(pPoint p){return p->Z;}
+
+  // -------------------------------------------------------------------
+  //! Deletes point p \ingroup point
+  void P_delete(pPoint p)
+  {
+    delete p;
+  }
+
+  // -------------------------------------------------------------------
+  //! Sets the coordinates of point p \ingroup point
+  void P_setPos(pPoint p , double x, double y, double z)
+  {
+    p->X = x;
+    p->Y = y;
+    p->Z = z;
+  }
+
+  // -------------------------------------------------------------------
+  //! Sets the identity of point p \ingroup point
+  void P_setID(pPoint p, int id){p->iD = id;}
+
+  // -------------------------------------------------------------------
+  //! Returns the identity of point p \ingroup point
+  int P_id(pPoint p){return p->iD;}
+
+  // -------------------------------------------------------------------
+  double P_param1(pPoint p)
+  {
+    pMeshDataId id = MD_lookupMeshDataId("_param1");
+    double pp;
+    EN_getDataDbl(p, id,&pp);
+    return pp;
+  }
+
+  // -------------------------------------------------------------------
+  void P_setParam1(pPoint p, double param)
+  {
+    pMeshDataId id = MD_lookupMeshDataId("_param1");
+    EN_attachDataDbl(p, id, param);
+  }
+
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  // Entity operators
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  //! Print informations about the entity
+  void EN_info(const pEntity e, std::string name, std::ostream& out)
+  {
+    switch ( EN_type(e) ) {
+    case 3: R_info((pRegion)e,name,out);
+    case 2: F_info((pFace)e,  name,out);
+    case 1: E_info((pEdge)e,  name,out);
+    case 0: V_info((pVertex)e,name,out);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the identity tag for entity e \ingroup entity
+  int EN_id(pEntity pe)
+  {
+    return pe->iD;
+  }
+
+  // -------------------------------------------------------------------
+  //! Sets the identity tag for entity e \ingroup entity
+  void EN_setID(pEntity pe, int id){
+    pe->iD=id;
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the type(dimension) of the geometrical entity on which entity e is classified \ingroup entity
+  int EN_whatInType(pEntity e){return GEN_type(e->g);}
+
+  // -------------------------------------------------------------------
+  //! Returns the number of vertices in the entity \ingroup entity
+  int EN_numVertices(const pEntity e)
+  {
+    switch ( EN_type(e) ) {
+    case 3: return R_numVertices((pRegion)e);
+    case 2: return F_numVertices((pFace)e);
+    case 1: return E_numVertices((pEdge)e);
+    case 0: return 1;
+    }
+  }
+
+  // -------------------------------------------------------------------
+  //! Returns the list of the vertices of the entity \ingroup entity
+  pPList EN_vertices(const pEntity e)
+  {
+    pPList vList;
+    switch ( EN_type(e) ) {
+    case 3: { vList = R_vertices((pRegion)e); break; }
+    case 2: { vList = F_vertices((pFace)e,1); break; }
+    case 1: { vList = E_vertices((pEdge)e); break; }
+    case 0: { vList = PList_new(); PList_append(vList,e); break; }
+    }
+    return vList;
+  }
+
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  /* mesh entity creation routines */
+
+  //! Creates a region, classified on gent, in mesh m using specified faces \ingroup mesh
+  pRegion M_createR(pMesh mesh, int nFace, pFace *faces, pGEntity gent)
+  {
+    pRegion pr(0);
+    switch(nFace)
+      {
+      case 4 : pr =  mesh->add_tet((MDB_Triangle*)faces[0],(MDB_Triangle*)faces[1],(MDB_Triangle*)faces[2],(MDB_Triangle*)faces[3],gent);
+        break;
+      case 5 : pr =  mesh->add_prism((MDB_Triangle*)faces[0],(MDB_Triangle*)faces[1],
+                                     (MDB_Quad*)faces[2],(MDB_Quad*)faces[3],(MDB_Quad*)faces[4],gent);
+        break;
+      case 6 : pr =  mesh->add_hex((MDB_Quad*)faces[0],(MDB_Quad*)faces[1],(MDB_Quad*)faces[2],
+                                   (MDB_Quad*)faces[3],(MDB_Quad*)faces[4],(MDB_Quad*)faces[5],gent);
+        break;      
+      }
+    return pr;
+  }
+
+  //! Creates a face, classified on gent, in mesh m using specified edges \ingroup mesh
+  /*! \warning currently only implemented for triangles */
+  pFace M_createF(pMesh mesh, int nEdge, pEdge *edges, pGEntity gent)
+  {
+    pFace pf = mesh->add_triangle (edges[0],edges[1],edges[2],gent);
+    return pf;
+  }
+
+  //! Create a edge, classified on ent, in mesh m using specified vertices \ingroup mesh
+  pEdge M_createE(pMesh mesh, pVertex v1, pVertex v2, pGEntity ent)
+  {
+    return mesh->add_edge (v1,v2,ent);
+  }
+  pVertex M_createV(pMesh mesh, double x, double y, double z,
+                    int patch, pGEntity ent)
+  {
+    return mesh->add_point (patch,x,y,z,ent);
+  }
+  pVertex M_createV2(pMesh mesh, double xyz[3],int patch, pGEntity ent)
+  {
+    return M_createV(mesh,xyz[0],xyz[1],xyz[2],patch,ent);
+  }
+  pVertex M_createVP(pMesh mesh, double x, double y, double z,
+                     double u, double v, int patch, pGEntity ent)
+  {
+    return mesh->add_pointParam (patch,x,y,z,u,v,ent);
+  }
+  /* mesh entity deletion routines */
+
+  //! Removes a region from the mesh, deletes it \ingroup mesh
+  void M_removeRegion(pMesh m, pRegion region)
+  {
+    if (dynamic_cast<MDB_Tet*>(region))  m->del_tet((MDB_Tet*)region);
+    else if (dynamic_cast<MDB_Hex*>(region))  m->del_hex((MDB_Hex*)region); 
+    else if (dynamic_cast<MDB_Prism*>(region))  m->del_prism((MDB_Prism*)region); 
+  }
+
+  //! Removes a face from the mesh, deletes it \ingroup mesh
+  /*! \warning currently only implemented for triangles */
+  void M_removeFace(pMesh m, pFace face)
+  {
+    m->del_triangle((MDB_Triangle*)face);
+  }
+
+  //! Removes an edge from the mesh, deletes it \ingroup mesh
+  void M_removeEdge(pMesh m, pEdge edge)
+  {
+    m->del_edge (edge);
+  }
+
+  //! Removes a vertex from the mesh, deletes it \ingroup mesh
+  void M_removeVertex(pMesh m, pVertex vertex)
+  {
+    m->del_point(vertex);
+  }
+
+  //! Return edge between two vertices, if not found returns 0  \ingroup mesh
+  pEdge E_exist(pVertex v1, pVertex v2)
+  {
+    MDB_VectorE edges = v1->edges;
+    MDB_VectorE::iterator it  = edges.begin();
+    MDB_VectorE::iterator ite = edges.end();
+    while(it!=ite){
+      pVertex p = (*it)->othervertex(v1);
+      if(p==v2) return((*it));
+      ++it;
+    }
+    return 0;
+  }
+
+  //! Returns triangle defined by an edge and a vertex. Returns 0 if not found.  \ingroup mesh
+  pFace F_exist(pEdge edge, pVertex vertex)
+  {
+    for (int iF=0; iF<edge->numfaces(); iF++) {
+      MDB_Triangle * tri = edge->faces(iF);
+      MDB_Edge * otherE = tri->e1;
+      if ( otherE == edge) otherE = tri->e2;
+      if ( otherE->p1 == vertex || otherE->p2 == vertex ) {
+        if ( edge->p1 == vertex || edge->p2 == vertex ) {
+          F_info(tri);
+          MAdMsgSgl::instance().error(__LINE__,__FILE__,"Bad triangle or bad input (edge: %p, vertex: %p)",
+                                      edge,vertex);
+        }
+        return tri;
+      }
+    }
+    return NULL;
+  }
+
+  //! Returns face defined by at most 4 entities, return 0 on failure  \ingroup mesh
+  /*! entities e1..4 may be either vertices or edges */
+  pFace F_exist(pEntity e1, pEntity e2, pEntity e3, pEntity e4){
+    int typeEnt = EN_type(e1);
+    switch(typeEnt) {
+    case 0:
+      { pVertex p1 = (pVertex) e1;
+        pVertex p2 = (pVertex) e2;
+        pVertex p3 = (pVertex) e3;
+        MDB_ListF listFaces;
+        p1->getTriangles(listFaces);
+        MDB_ListF::iterator it  = listFaces.begin();
+        MDB_ListF::iterator ite = listFaces.end();
+        while(it!=ite){
+          pVertex p[3];
+          (*it)->getNodes(p);
+          if(p[0]==p1 && p[1]==p2 && p[2]==p3) return(*it);
+          if(p[0]==p1 && p[1]==p3 && p[2]==p2) return(*it);
+          if(p[0]==p2 && p[1]==p1 && p[2]==p3) return(*it);
+          if(p[0]==p2 && p[1]==p3 && p[2]==p1) return(*it);
+          if(p[0]==p3 && p[1]==p1 && p[2]==p2) return(*it);
+          if(p[0]==p3 && p[1]==p2 && p[2]==p1) return(*it);
+          ++it;
+        }      
+        return 0;
+      }
+      break;
+    case 1:
+      {
+        pEdge ped1 = (pEdge) e1;
+        pEdge ped2 = (pEdge) e2;
+        pEdge ped3 = (pEdge) e3;
+        for(int k=0 ; k<ped1->numfaces() ; k++) {
+          pFace pface = ped1->faces(k);
+          if(pface->getEdge(0)==ped1 && pface->getEdge(1)==ped2 && pface->getEdge(2)==ped3) return(pface);
+          if(pface->getEdge(0)==ped1 && pface->getEdge(1)==ped3 && pface->getEdge(2)==ped2) return(pface);
+          if(pface->getEdge(0)==ped2 && pface->getEdge(1)==ped1 && pface->getEdge(2)==ped3) return(pface);
+          if(pface->getEdge(0)==ped2 && pface->getEdge(1)==ped3 && pface->getEdge(2)==ped1) return(pface);
+          if(pface->getEdge(0)==ped3 && pface->getEdge(1)==ped1 && pface->getEdge(2)==ped2) return(pface);
+          if(pface->getEdge(0)==ped3 && pface->getEdge(1)==ped2 && pface->getEdge(2)==ped1) return(pface);
+        }
+        return 0;
+      }
+      break;
+    default:
+      throw;  
+    }
+    return 0;
+  }
+
+  //! Returns the number of geometric entities associated to the mesh \ingroup mesh
+
+  int    M_numGeomFeatures (pMesh pm)
+  {
+    return pm->geomFeatures_Tags.size(); 
+  }
+
+  //! Returns the id tag of the n-th geometric entity associated to the mesh \ingroup mesh
+  int    M_geomFeatureId   (pMesh pm, int n)
+  {
+    int count = 0;
+    for (std::multimap<int, pGEntity>::iterator it = pm->geomFeatures_Tags.begin();
+         it != pm->geomFeatures_Tags.end();
+         ++it)
+      {
+        if (count++ == n) return it->first;
+      }
+    throw;
+  }
+
+  //! Returns the number of geometric entities associated to the mesh with tag id \ingroup mesh
+  /*! \warning id's are only guaranteed to be unique per type of geometric feature */
+  pPGList M_geomFeature     (pMesh pm, int id)
+  {
+    pPGList pl = PGList_new();
+    for (std::multimap<int, pGEntity>::iterator it = pm->geomFeatures_Tags.lower_bound(id) ;
+         it != pm->geomFeatures_Tags.upper_bound(id) ; ++it)
+      PGList_append(pl,it->second);
+    return pl;  
+  }
+
+  //! Print a list of geometric entities attached to the mesh to standard output \ingroup mesh
+  /*! \warning id's  are only guaranteed to be unique per type of geometric feature */
+  void M_printGeomFeatures (pMesh pm)
+  {
+    std::cout << "\nPrinting geometric features: \n\n";
+    std::multimap<int, pGEntity>::iterator it = pm->geomFeatures_Tags.begin();
+    std::multimap<int, pGEntity>::iterator itEnd = pm->geomFeatures_Tags.end();
+    for (;it != itEnd; it++) {
+      std::cout << "geometric id: " << it->first << " geometric entity: " << it->second << "\n";
+    }
+  }
+
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  // PList operators
+  // -------------------------------------------------------------------
+
+  // -------------------------------------------------------------------
+  PList * PList_new()
+  {
+    return new PList();
+  }
+
+  // -------------------------------------------------------------------
+  void PList_delete(PList * lst)
+  {
+    if (lst) delete lst;
+    lst = NULL;
+  }
+
+  // -------------------------------------------------------------------
+  void PList_clear(PList * lst)
+  {
+    lst->clear();
+  }
+
+  // -------------------------------------------------------------------
+  PList * PList_appUnique(PList * lst, MDB_MeshEntity * ent)
+  {
+    for ( unsigned int i=0; i<lst->entities.size(); i++ ) {
+      if ( lst->entities[i] == ent ) return lst;
+    }
+    lst->entities.push_back(ent);
+    return lst;
+  }
+
+  // -------------------------------------------------------------------
+  PList * PList_appPListUnique(PList * lst, PList * source)
+  {
+    for ( unsigned int iSrc=0; iSrc<source->entities.size(); iSrc++ ) {
+      PList_appUnique(lst,source->entities[iSrc]);
+    }
+    return lst;
+  }
+
+  // -------------------------------------------------------------------
+  PList * PList_append(PList * lst, MDB_MeshEntity * ent)
+  {
+    lst->entities.push_back(ent);
+    return lst;
+  }
+
+  // -------------------------------------------------------------------
+  int PList_size(PList * lst)
+  {
+    return lst->entities.size();
+  }
+
+  // -------------------------------------------------------------------
+  MDB_MeshEntity * PList_item(PList * lst, int i)
+  {
+    return lst->entities[i];
+  }
+
+  // -------------------------------------------------------------------
+  MDB_MeshEntity * PList_next(PList * lst, void **restart)
+  {
+    if( *(int*)(restart) >= (int)lst->entities.size() ) return NULL;
+    return lst->entities[(*(int*)(restart))++];
+  }
+
+  // -------------------------------------------------------------------
+  int PList_inList(PList * lst, MDB_MeshEntity * ent)
+  {
+    for ( unsigned int i=0; i<lst->entities.size(); i++ ) {
+      if ( lst->entities[i] == ent ) return 1;
+    }
+    return 0;
+  }
+
+  // -------------------------------------------------------------------
+  void PList_remItem(PList * lst, MDB_MeshEntity * ent)
+  {
+    std::vector<MDB_MeshEntity *>::iterator eIter = lst->entities.begin();
+    for (; eIter != lst->entities.end() ; eIter++) {
+      if ( *eIter == ent ) lst->entities.erase(eIter);
+    }
+  }
+
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+
+}
diff --git a/Mesh/MeshDataBaseInterface.h b/Mesh/MeshDataBaseInterface.h
new file mode 100644
index 0000000..1f8acab
--- /dev/null
+++ b/Mesh/MeshDataBaseInterface.h
@@ -0,0 +1,381 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef H_MESHDATABASEINTEFACE
+#define H_MESHDATABASEINTEFACE
+
+#include "MeshDataBase.h"
+#include "MeshDataBaseCommPeriodic.h"
+
+namespace MAd {
+
+  typedef unsigned int pMeshDataId;
+
+  typedef class MDB_Mesh  * pMesh;  
+
+  typedef class MDB_MeshEntity * pEntity;
+  typedef class MDB_Region     * pRegion;
+  typedef class MDB_Face       * pFace;
+  typedef class MDB_Edge       * pEdge;
+  typedef class MDB_Point      * pVertex;
+  typedef class MDB_Point      * pPoint;
+  
+  typedef class MDB_RegionIter * RIter;
+  typedef class MDB_FaceIter   * FIter;
+  typedef class MDB_EIter      * EIter;
+  typedef class MDB_VIter      * VIter;
+
+  typedef class PList * pPList;
+
+  /********************/
+  /*  Mesh Operators  */
+  /********************/
+
+  pMesh   M_new(pGModel);
+  void    M_delete(pMesh);
+  void    M_load(pMesh, const char * filename);
+  void    M_clean(pMesh);
+
+  void    M_shrink(pMesh);
+  void    M_expand(pMesh);
+
+  void    M_info(const pMesh, std::ostream& out=std::cout);
+  pGModel M_model(pMesh);
+  int     M_dim(pMesh);
+
+  int     M_edgesMaxOrder(pMesh);
+  int     M_facesMaxOrder(pMesh);
+  int     M_regionsMaxOrder(pMesh);
+  int     M_maxOrder(pMesh);
+
+  bool    M_isParametric(pMesh);
+
+  void    M_writeMsh(const pMesh, const char *name, 
+                     int version=2, const int * partitionTable=NULL);
+  void    M_writeMshPer(pMesh, const char *name, 
+                        MDB_DataExchangerPeriodic &, int version);
+
+#ifdef _HAVE_METIS_
+  void    M_Partition(pMesh, int nbParts, const char * filename);
+#endif
+
+  int M_numRegions(pMesh);
+  int M_numTets(pMesh);
+  int M_numHexes(pMesh);
+  int M_numPrisms(pMesh);
+  int M_numFaces(pMesh);
+  int M_numQuads(pMesh);
+  int M_numTriangles(pMesh);
+  int M_numEdges(pMesh);
+  int M_numVertices(pMesh);
+
+  RIter M_regionIter(pMesh);
+  FIter M_faceIter(pMesh);
+  EIter M_edgeIter(pMesh);
+  VIter M_vertexIter(pMesh);
+
+  int M_numClassifiedRegions (pMesh, pGEntity);
+  int M_numClassifiedFaces   (pMesh, pGEntity);
+  int M_numClassifiedEdges   (pMesh, pGEntity);
+  int M_numClassifiedVertices(pMesh, pGEntity);
+
+  RIter   M_classifiedRegionIter(pMesh, pGEntity);
+  FIter   M_classifiedFaceIter  (pMesh, pGEntity, int closure);
+  EIter   M_classifiedEdgeIter  (pMesh, pGEntity, int closure);
+  VIter   M_classifiedVertexIter(pMesh, pGEntity, int closure);
+  pVertex M_classifiedVertex    (pMesh, pGVertex);
+
+  /* mesh entity creation routines */
+  pRegion M_createR(pMesh, int nFace, pFace *faces, pGEntity);
+  pFace   M_createF(pMesh, int nEdge, pEdge *edges, pGEntity);
+  pEdge   M_createE(pMesh, pVertex v1, pVertex v2, pGEntity);
+  pVertex M_createV(pMesh, double x, double y, double z, int patch, pGEntity);
+  pVertex M_createV2(pMesh, double xyz[3], int patch, pGEntity);
+  pVertex M_createVP(pMesh, double x, double y, double z, 
+                     double u, double v, int patch, pGEntity);
+
+  /* mesh entity deletion routines */
+  void M_removeRegion(pMesh, pRegion);
+  void M_removeFace  (pMesh, pFace);
+  void M_removeEdge  (pMesh, pEdge);
+  void M_removeVertex(pMesh, pVertex);
+  void P_delete(pPoint);
+  pPoint P_new(void);
+
+  /***********************/
+  /* Geometric model ops */
+  /***********************/
+
+  int     M_numGeomFeatures   (pMesh);
+  int     M_geomFeatureId     (pMesh, int ith);
+  pPGList M_geomFeature       (pMesh, int id);
+  void    M_printGeomFeatures (pMesh);
+
+  /********************/
+  /* Entity Iter Ops  */
+  /********************/
+
+  pRegion RIter_next  (RIter);
+  void    RIter_delete(RIter);
+  void    RIter_reset (RIter);
+  pFace   FIter_next  (FIter);
+  void    FIter_delete(FIter);
+  void    FIter_reset (FIter);
+  pEdge   EIter_next  (EIter);
+  void    EIter_delete(EIter);
+  void    EIter_reset (EIter);
+  pVertex VIter_next  (VIter);
+  void    VIter_delete(VIter);
+  void    VIter_reset (VIter);
+
+  /********************/
+  /* Entity Operators */
+  /********************/
+  
+  void     EN_info(const pEntity, std::string name="", std::ostream& out=std::cout);
+  void     EN_setID(pEntity, int id);
+  int      EN_id   (pEntity);
+  void     EN_print(pEntity);
+
+  int      EN_type(pEntity);
+  int      EN_whatInType(pEntity);
+  pGEntity EN_whatIn(pEntity);
+  void     EN_setWhatIn(pEntity,pGEntity);
+  
+  int      EN_numVertices(const pEntity);
+  pPList   EN_vertices(const pEntity);
+  int      EN_inClosure(pEntity, pEntity);
+
+  /********************/
+  /* Region Operators */
+  /********************/
+
+  void     R_info         (const pRegion, std::string name="", std::ostream& out=std::cout);
+  void     R_info_quality (const pRegion, std::ostream& out=std::cout);
+  void     R_info_topology(const pRegion, std::ostream& out=std::cout);
+
+  pGRegion R_whatIn(pRegion);
+  int      R_whatInType(pRegion);
+  void     R_setWhatIn(pRegion, pGEntity);
+
+  int      R_numPoints(pRegion);
+  pPoint   R_point(pRegion,int);
+  int      R_numVertices(pRegion);
+  pPList   R_vertices(pRegion);
+  pVertex  R_vertex(pRegion, int);
+  pVertex  R_fcOpVt(const pRegion, const pFace);
+  pPList   R_edges(pRegion);
+  pEdge    R_edge(pRegion, int);
+  pEdge    R_gtOppEdg(const pRegion, const pEdge);
+  int      R_numFaces(pRegion);
+  pFace    R_face(pRegion, int);
+  pPList   R_faces(pRegion);
+  pFace    R_vtOpFc(const pRegion, const pVertex);
+  int      R_inClosure(pRegion, pEntity);
+  int      R_faceDir(pRegion, int);
+  int      R_faceOri(pRegion, int);
+  int      R_dirUsingFace(pRegion,pFace);
+  int      R_oriUsingFace(pRegion,pFace);
+
+  void     R_coordP1(const pRegion, double [][3]);
+  void     R_coord(const pRegion, double [][3]);
+  double   R_volume(const pRegion);
+  double   R_XYZ_volume (const double [][3]);
+  double   R_circumRad(const pRegion);
+  double   R_inscrRad(const pRegion);
+  bool     R_meanRatioCube(const pRegion, double *);
+  bool     R_XYZ_meanRatioCube(const double [][3], double *);
+  bool     R_XYZ_isFlat(const double [][3]);
+  void     R_linearParams(const pRegion, const double[3], double[3]);
+  void     R_center(const pRegion, double [3]);
+  void     R_jacobian(const pRegion, double [3][3]);
+  double   R_invJacobian(const pRegion, double [3][3]);
+
+  /********************/
+  /*  Face Operators  */
+  /********************/
+
+  void     F_info(const pFace, std::string name="", std::ostream& out=std::cout);
+
+  pFace    F_exist(pEntity, pEntity, pEntity, pEntity);
+  pFace    F_exist(pEdge,pVertex);
+
+  pGEntity F_whatIn(pFace);
+  int      F_whatInType(pFace);
+  void     F_setWhatIn(pFace, pGEntity);
+
+  pPoint   F_point(pFace, int);
+  int      F_numPoints(pFace);
+  int      F_numPointsTot(pFace);
+  int      F_numVertices(pFace);
+  pPList   F_vertices(pFace, int dir);
+  pVertex  F_vertex(pFace, int);
+  pEdge    F_vtOpEd(const pFace, const pVertex);
+  int      F_numEdges(pFace);
+  pPList   F_edges(pFace);
+  pEdge    F_edge(pFace, int);
+  int      F_edgeDir(pFace, int);
+  pVertex  F_edOpVt(const pFace, const pEdge);
+  int      F_dirUsingEdge(pFace, pEdge);
+  int      F_numRegions(pFace);
+  pPList   F_regions(pFace);
+  pRegion  F_region(pFace, int);
+  pRegion  F_otherRegion(const pFace, const pRegion);
+  int      F_inClosure(pFace, pEntity);
+  void     F_chDir(pFace);
+  int      F_align(pFace,pVertex,pVertex,pVertex,pVertex);
+
+  void     F_coordP1(const pFace, double [][3]);
+  void     F_coord(const pFace, double [][3]);
+  bool     F_params(const pFace, double [][2]);
+  double   F_area(const pFace, const double *dir=NULL);
+  double   XYZ_F_area(const double [][3], const double *dir=NULL);
+  double   F_areaSq(const pFace, const double *dir=NULL);
+  double   XYZ_F_areaSq(const double [][3], const double *dir=NULL);
+  void     F_linearParams(const pFace, const double[3], double[2]);
+  void     F_center(const pFace, double [3]);
+  void     F_normal(const pFace, double [3]);
+  void     XYZ_F_normal(const double [3][3], double [3]);
+  bool     F_volumeRatio(const pFace, double *);
+  double   F_worstVolumeRatio(const std::set<pFace>);
+
+  /********************/
+  /*  Edge Operators  */
+  /********************/
+
+  void     E_info(const pEdge, std::string name="", std::ostream& out=std::cout);
+
+  pEdge    E_exist(pVertex, pVertex);
+
+  pGEntity E_whatIn(pEdge);
+  int      E_whatInType(pEdge);
+  void     E_setWhatIn(pEdge, pGEntity);
+
+  int      E_numPoints(pEdge);
+  pPoint   E_point(pEdge, int);
+  pVertex  E_vertex(pEdge, int);
+  pPList   E_vertices(const pEdge);
+  pVertex  E_otherVertex(pEdge, pVertex);
+  int      E_numFaces(pEdge);
+  pPList   E_faces(const pEdge);
+  pFace    E_face(pEdge, int);
+  pFace    E_otherFace(pEdge, pFace, pRegion);
+  int      E_numRegions(pEdge);
+  pPList   E_regions(pEdge);
+  int      E_inClosure(pEdge, pEntity);
+  int      E_dir(pEdge, pVertex, pVertex);
+  int      E_align(pEdge, pVertex,pVertex);
+
+  void     E_coordP1(const pEdge, double [][3]);
+  void     E_coord(const pEdge, double [][3]);
+  bool     E_params(const pEdge, double [2][2]);
+  double   E_length(const pEdge);
+  double   E_lengthSq(const pEdge);
+  double   E_linearParams(const pEdge, const pVertex);
+  double   E_linearParams(const pEdge, const double[3]);
+  void     E_center(const pEdge, double[3]);
+  void     E_cavityCenter(const pEdge, double[3]);
+
+  /********************/
+  /* Point Operators  */
+  /********************/
+
+  double P_x(pPoint);
+  double P_y(pPoint);
+  double P_z(pPoint);
+  void   P_setPos(pPoint, double x, double y, double z);
+
+  void   P_setID(pPoint, int);
+  int    P_id(pPoint);
+
+  double P_param1(pPoint);
+  void   P_setParam1(pPoint, double);
+
+  /********************/
+  /* Vertex Operators */
+  /********************/
+
+  void     V_info(const pVertex, std::string name="", std::ostream& out=std::cout);
+ 
+  pGEntity V_whatIn(pVertex);
+  int      V_whatInType(pVertex);
+  void     V_setWhatIn(pVertex, pGEntity);
+
+  pPoint   V_point(pVertex);
+  int      V_numEdges(pVertex);
+  pPList   V_edges(pVertex);
+  pEdge    V_edge(pVertex, int);
+  int      V_numFaces(pVertex);
+  pPList   V_faces(pVertex);
+  int      V_numRegions(pVertex);
+  pPList   V_regions(pVertex);
+
+  int      V_id(const pVertex);
+
+  void     V_coord(const pVertex, double [3]);
+  bool     V_params(pVertex, double *, double *);
+  double   V_meanEdgeLenSq(const pVertex);
+  void     V_cavityCenter(const pVertex, double[3]);
+
+  /***************************/
+  /* Entities list operators */
+  /***************************/
+
+  pPList  PList_new();
+  pPList  PList_allocate( );
+  void    PList_delete         (pPList);
+  void    PList_deallocate     (pPList);
+  void    PList_clear          (pPList);
+  pPList  PList_appPListUnique (pPList, pPList source);
+  pPList  PList_appUnique      (pPList, pEntity);
+  pPList  PList_append         (pPList, pEntity);
+  int     PList_size           (pPList); 
+  pEntity PList_item           (pPList, int n);
+  pEntity PList_next           (pPList, void ** restart);
+  int     PList_inList         (pPList, pEntity);
+  void    PList_remItem        (pPList, pEntity);
+  
+  /***********************/
+  /* Attached data tools */
+  /***********************/
+  
+  pMeshDataId MD_newMeshDataId(const std::string="");
+  pMeshDataId MD_lookupMeshDataId(const std::string);
+  void        MD_deleteMeshDataId(pMeshDataId);
+  
+  void EN_attachDataInt(pEntity, pMeshDataId, int);
+  void EN_attachDataDbl(pEntity, pMeshDataId, double);
+  void EN_attachDataPtr(pEntity, pMeshDataId, void *);
+  void EN_attachDataP  (pEntity, const char *, void *);
+  void EN_attachDataI  (pEntity, const char *, int);
+  
+  void EN_modifyDataInt(pEntity, pMeshDataId, int);
+  void EN_modifyDataDbl(pEntity, pMeshDataId, double);
+  void EN_modifyDataPtr(pEntity, pMeshDataId, void *);
+  int  EN_modifyDataP  (pEntity, const char *, void *);
+  int  EN_modifyDataI  (pEntity, const char *, int);
+  
+  void EN_deleteData(pEntity, pMeshDataId);
+  void EN_removeData(pEntity, const char *);
+  
+  int  EN_getDataInt(pEntity, pMeshDataId, int *);
+  int  EN_getDataDbl(pEntity, pMeshDataId, double *);
+  int  EN_getDataPtr(pEntity, pMeshDataId, void **);
+  void * EN_dataP(pEntity, const char *);
+  int    EN_dataI(pEntity, const char *);
+
+}
+
+#endif 
+
+
diff --git a/Mesh/MeshDataBaseIterators.h b/Mesh/MeshDataBaseIterators.h
new file mode 100644
index 0000000..33ea10e
--- /dev/null
+++ b/Mesh/MeshDataBaseIterators.h
@@ -0,0 +1,200 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef H_MESHDATABASEITERATORS
+#define H_MESHDATABASEITERATORS
+
+namespace MAd {
+
+  template <class CONTAINER, class DATA, class CLASSIF>
+  class MDB_Iter
+  {
+  public:
+    CONTAINER *l;
+    CLASSIF   g;
+    int closure;
+  
+    typename CONTAINER::iterator current;
+    typename CONTAINER::iterator end;
+  
+    MDB_Iter (CONTAINER *_l):l(_l),g(NULL),closure(0)
+    {
+      reset();
+    }
+    MDB_Iter (CONTAINER *_l,CLASSIF _g):l(_l),g((CLASSIF) _g),closure(0) {
+      reset();
+    }
+  
+    MDB_Iter (CONTAINER *_l,CLASSIF _g,int _c):l(_l),g((CLASSIF) _g),closure(_c) {
+
+      /*     if ((DATA::getDim() == 3) && (_c == 1)) { */
+      /*       printf("Closure iterator not allowed for regions\n"); */
+      /*       exit(1); */
+      /*     } */
+    
+      if (_c == 1) {
+        printf("Closure iterator not yet implemented \n");
+        exit(1);
+      }
+    
+      reset();
+    }
+    
+    virtual ~MDB_Iter() {}
+  
+    inline void reset()
+    {
+      end = l->end();
+      current = l->begin();
+
+      if (!g) {
+        while(current != end && (*current)->deleted)
+          {
+            typename CONTAINER::iterator currentb = current;
+            current++;
+            delete *currentb;
+            l->erase(currentb);       
+          }
+      }
+      else {  
+        while(current != end && ((*current)->deleted || (*current)->g != g))
+          {
+            typename CONTAINER::iterator currentb = current;
+            current++;
+            if ((*currentb)->deleted) {
+              delete *currentb;
+              l->erase(currentb);
+            }
+          }
+      }
+      //     if (!g  && current!= end && (*current)->deleted)next();
+      //     if (g   && current!= end && ((*current)->deleted || (*current)->g != g)) next();
+    
+    }
+    inline void cleanup()
+    {
+      current = l->begin();
+      while(next()){}  
+    }
+  
+    inline virtual DATA * next ()
+    {
+      if (current == end) return 0;
+    
+      DATA *r = *current;
+      ++ current;
+
+      if (!g) {
+        while(current != end && (*current)->deleted)
+          {
+            typename CONTAINER::iterator currentb = current;
+            current++;
+            delete *currentb;
+            l->erase(currentb);       
+          }
+      }
+      else {  
+        while(current != end && ((*current)->deleted || (*current)->g != g))
+          {
+            typename CONTAINER::iterator currentb = current;
+            current++;
+            if ((*currentb)->deleted) {
+              delete *currentb;
+              l->erase(currentb);
+            }
+          }
+      }
+
+      // if the result data was marked for deletion
+      // after previous call to next() look for the next one
+      if (r->deleted) {
+
+        if (current == end) return 0;
+
+        r = *current;
+        ++ current;
+      
+        if (!g) {
+          while(current != end && (*current)->deleted)
+            {
+              typename CONTAINER::iterator currentb = current;
+              current++;
+              delete *currentb;
+              l->erase(currentb);       
+            }
+        }
+        else {  
+          while(current != end && ((*current)->deleted || (*current)->g != g))
+            {
+              typename CONTAINER::iterator currentb = current;
+              current++;
+              if ((*currentb)->deleted) {
+                delete *currentb;
+                l->erase(currentb);
+              }
+            }
+        }
+
+      }
+
+      return r;
+    }
+  
+  };
+
+  template <class CONTAINER, class DATA, class CLASSIF>
+  int countClassifiedElements (CONTAINER* c,CLASSIF g) {
+  
+    MDB_Iter<CONTAINER,DATA,CLASSIF>* iter = new MDB_Iter<CONTAINER,DATA,CLASSIF>(c,g);
+  
+    DATA* el = NULL;
+    int count = 0;
+    while ( (el = iter->next()) ) count++;
+    delete iter;
+
+    return count;
+  
+  }
+
+}
+
+  
+/* //report errors to koen.hillewaert at cenaero.be */
+/* template <class CONTAINER, class DATA> */
+/* class MDB_CIter: public  MDB_Iter <CONTAINER,DATA> */
+/* { */
+/* public: */
+/*   pGEntity ge; */
+/*   MDB_CIter (CONTAINER *_l,pGEntity _g):MDB_Iter<CONTAINER,DATA>(_l),ge(_g) */
+/*   { */
+/*     reset(); */
+/*   } */
+/*   inline DATA * next () */
+/*   { */
+/*     if (current == end)return 0; */
+/*     DATA *r = *current; */
+/*     ++ current; */
+/*     while(current != end && */
+/*           (*current)->deleted && */
+/*           EN_whatIn(current) != ge) */
+/*       { */
+/*         typename CONTAINER::iterator currentb = current; */
+/*         current++; */
+/*         delete *currentb; */
+/*         l->erase(currentb);        */
+/*       } */
+/*     return r; */
+/*   } */
+/* }; */
+
+#endif
diff --git a/Mesh/MeshDataBaseLoadBalancing.cc b/Mesh/MeshDataBaseLoadBalancing.cc
new file mode 100644
index 0000000..9971300
--- /dev/null
+++ b/Mesh/MeshDataBaseLoadBalancing.cc
@@ -0,0 +1,3032 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+
+#include "MeshDataBase.h"
+#include "MSops.h"
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseParallelInterface.h"
+#include "MeshDataBaseLoadBalancing.h"
+#include "MeshDataBaseComm.h"
+
+#include "assert.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <fstream>
+#include <iostream>
+
+namespace MAd {
+
+  typedef std::pair<int, pVertex>              CommonpVertex_type;
+  typedef std::vector< CommonpVertex_type  >  VectorOfCommonpVertex_type;
+  // -------------------------------------------------------------------
+  struct points_comm
+  {
+    pVertex p;     //pointeur in dest
+    int nID;       //myrank
+    int newproc;
+  };
+
+  // -------------------------------------------------------------------
+  struct oldinterfaces_comm
+  {
+    int     oldnum;
+    pVertex oldpv;                
+  };
+  // -------------------------------------------------------------------
+  struct coor_comm
+  {
+    double   X,Y,Z;
+    int tag,dim;
+    int nproc;
+    pVertex  psend;
+  };  
+  // -------------------------------------------------------------------
+  struct newinterfaces_comm
+  {
+    int newproc;
+  };  
+  // -------------------------------------------------------------------
+  struct points_comm_new
+  {
+    pVertex pdest;       //pointeur in dest
+    int     destID;
+    pVertex psend;
+    int     sendID;       
+  };
+
+  // -------------------------------------------------------------------
+  void ExchangeUpdatedInterfaceNodalInfo(pMesh mesh)
+  {
+    int nproc,myrank;
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+    int *sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+    
+    pMeshDataId tagData   = MD_lookupMeshDataId("RemotePoint");
+    pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+    pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+ 
+    VIter vit = M_vertexIter(mesh);
+    pVertex pv;
+    while ((pv = VIter_next(vit))) {
+      void *temp_ptr;
+      int isInterface = EN_getDataPtr((pEntity) pv, tagData, &temp_ptr);
+    
+      if(!isInterface) continue;
+      const VectorOfCommonpVertex_type *recup = 
+        (const VectorOfCommonpVertex_type *) temp_ptr;
+      int tmp;
+      int isChanged = EN_getDataInt((pEntity) pv, tagChange, &tmp);
+      assert(isChanged);
+      void *temp_ptr2;
+      int is = EN_getDataPtr((pEntity) pv, tagRemote, &temp_ptr2);
+      assert(is);
+      VectorOfCommonpVertex_type *recup2 = 
+        (VectorOfCommonpVertex_type  *) temp_ptr2;
+
+      for(int j=0; j<(int)((*recup).size()); j++) {
+        for( int i=0; i<(int)((*recup2).size()); i++) {
+          int remoteID  = (*recup)[j].first;
+          assert(remoteID != myrank);
+          void *buf = AP_alloc(remoteID,444,sizeof(points_comm));
+          points_comm *castbuf = (points_comm *) buf;
+          castbuf->p     = (*recup)[j].second;
+          castbuf->nID     = myrank;
+          assert((*recup2)[i].first < nproc);
+          castbuf->newproc   = (*recup2)[i].first;
+          AP_send(buf);
+          sendcounts[remoteID]++;
+        }
+      }
+    }
+    VIter_delete(vit);  
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+  
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        points_comm * castbuf = (points_comm*) msg;
+        pVertex precv (NULL);
+        precv = castbuf -> p;
+        assert(precv);
+        int nprocrecv = castbuf->newproc;
+        assert(nprocrecv<nproc);
+        int tmp; 
+        int isChanged = EN_getDataInt((pEntity) precv, tagChange, &tmp);
+        assert(isChanged);
+        void *temp_ptr; 
+        int is = EN_getDataPtr((pEntity) precv, tagRemote, &temp_ptr);
+        assert(is);
+        VectorOfCommonpVertex_type *recup = 
+          (VectorOfCommonpVertex_type  *) temp_ptr;
+        int * tabproc = new int[nproc];
+        for(int i=0 ; i<nproc ; i++){
+          tabproc[i] = 0;
+        }
+        for(unsigned int i=0 ; i<(*recup).size() ; i++){
+          tabproc[(*recup)[i].first] = 1;
+        }
+        if(!tabproc[nprocrecv]){
+          (*recup).push_back( CommonpVertex_type (nprocrecv,NULL));
+        }
+                
+        AP_free(msg);
+        delete []tabproc;
+      }
+    }
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;
+
+  }
+
+  // -------------------------------------------------------------------
+  void MarkEltVertex(pMesh mesh, pMeshDataId tagElt)
+  {
+    int nproc,myrank;
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+    // Integer set to one if the vertex will change
+    pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+
+    // Data attached to each parallel vertex: distant proc 
+    // together with distant pointer for the same vertex
+    pMeshDataId tagData   = MD_lookupMeshDataId("RemotePoint");
+
+    // Like tagData but after the interface move
+    pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+
+  
+    // --- Mark vertices ---
+    int Dim = (mesh->tets.empty()) ? 2 : 3;
+    if(Dim==2) {
+      FIter fit = M_faceIter(mesh);
+      pFace pface;  
+      while ((pface = FIter_next(fit))) {
+        int dest; 
+        int migre = EN_getDataInt((pEntity) pface, tagElt, &dest);
+        if(!migre) continue;    
+    
+        pVertex nod[3];
+        nod[0] = F_vertex(pface,0);
+        nod[1] = F_vertex(pface,1);
+        nod[2] = F_vertex(pface,2);
+        for(int i=0 ; i<3 ; i++) {
+          EN_attachDataInt((pEntity) nod[i], tagChange, 1);
+        }
+      }
+      FIter_delete(fit);
+    } else {
+      if(Dim!=3) throw;
+      RIter rit = M_regionIter(mesh);
+      pRegion pr;  
+      while ((pr = RIter_next(rit))) {
+        int dest; 
+        int migre = EN_getDataInt((pEntity) pr, tagElt, &dest);
+        if(!migre) continue;    
+    
+        pVertex nod[4];
+        nod[0] = R_vertex(pr,0);
+        nod[1] = R_vertex(pr,1);
+        nod[2] = R_vertex(pr,2);
+        nod[3] = R_vertex(pr,3);
+        for(int i=0 ; i<4 ; i++) {
+          EN_attachDataInt((pEntity) nod[i], tagChange, 1);
+        }
+      }
+      RIter_delete(rit);
+    }
+  
+    // --- Attach info about every future distant node to the marked nodes ---
+    VIter vit = M_vertexIter(mesh);
+    pVertex pv;  
+    vit = M_vertexIter(mesh);
+    while ((pv = VIter_next(vit))) {
+      int tmp;
+      int isChanged = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+      void *temp_ptr; 
+      int isInterface = EN_getDataPtr((pEntity) pv, tagData, &temp_ptr);
+      if(!(isInterface || isChanged)) continue;
+      if(!isChanged) EN_attachDataInt((pEntity) pv, tagChange, 1);
+      /*vertex ball*/
+      int ncompt = 0;
+      int *tabproc=new int[nproc];
+      for(int i=0 ; i<nproc ; i++){
+        tabproc[i] = 0;
+      }
+      if(Dim==2) { 
+        void *iter = 0;
+        pPList ball = V_faces (pv);
+        pFace pface;
+        while( (pface =(pFace) PList_next(ball,&iter)) ) {
+          int dest;
+          int migre = EN_getDataInt((pEntity) pface, tagElt, &dest);
+          if(migre) {
+            tabproc[dest-1] = 1;
+          } else {
+            tabproc[myrank] = 1;
+          }
+        }
+      } else {
+        void *iter = 0;
+        pPList ball = V_regions (pv);
+        pRegion pr;
+        while( (pr =(pRegion) PList_next(ball,&iter)) ) {
+          int dest;
+          int migre = EN_getDataInt((pEntity) pr , tagElt,&dest);
+          if(migre) {
+            tabproc[dest-1] = 1;
+          } else {
+            tabproc[myrank] = 1;
+          }
+        }
+    
+      }
+      for(int i=0 ; i<nproc ; i++){
+        ncompt += tabproc[i];
+      }
+      if(ncompt > 1) {
+        VectorOfCommonpVertex_type  remoteUpdate;
+        for(int i=0 ; i<nproc ; i++) {
+          if(tabproc[i]) {
+            (remoteUpdate).push_back(CommonpVertex_type(i,NULL));
+          }
+          EN_attachDataPtr((pEntity) pv , tagRemote, 
+                           new VectorOfCommonpVertex_type (remoteUpdate));
+        } 
+      } else {
+        int i=0;
+        for(i=0 ; i<nproc ; i++) {
+          if(tabproc[i] && (i != myrank)) break;  
+        }  
+        if(i==nproc) {
+          assert(tabproc[myrank]);
+          assert(isInterface);
+          i = myrank;
+        }
+        VectorOfCommonpVertex_type  remoteUpdate;
+        (remoteUpdate).push_back(CommonpVertex_type(i,NULL));
+        EN_attachDataPtr((pEntity) pv , tagRemote, 
+                         new VectorOfCommonpVertex_type (remoteUpdate));
+      }
+      delete []tabproc;
+    }
+    VIter_delete(vit);
+
+    // --- Send and receive info at nodes for updated interface ---
+    ExchangeUpdatedInterfaceNodalInfo(mesh);
+
+  }
+
+#ifdef DEBUG
+  // -------------------------------------------------------------------
+  void checkRemotePointer(pMesh mesh, pMeshDataId tagData ) {
+    int nproc,myrank;
+  
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+    int *sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+ 
+    VIter vit = M_vertexIter(mesh);  
+    pVertex pv;
+    while ((pv = VIter_next(vit))) {
+      void *temp_ptr; 
+      int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+      if(!isInterface) continue;
+      const VectorOfCommonpVertex_type *recup = 
+        (const VectorOfCommonpVertex_type *) temp_ptr;
+      int sizeinterface = (*recup).size();
+
+      for(int i=0 ; i<sizeinterface ; i++) {
+        int remoteID = (*recup)[i].first;
+        assert(remoteID!=myrank);
+        void *buf = AP_alloc(remoteID,444,sizeof(oldinterfaces_comm));
+        oldinterfaces_comm *castbuf = (oldinterfaces_comm *) buf; 
+        castbuf->oldnum = myrank;
+        assert((*recup)[i].second);
+        castbuf->oldpv  = (*recup)[i].second;
+        AP_send(buf);
+        sendcounts[remoteID]++;       
+      } 
+    }
+    VIter_delete(vit);   
+
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+
+    /*receive pointers*/
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        oldinterfaces_comm * castbuf = (oldinterfaces_comm *) msg;
+        pVertex pv    = castbuf->oldpv;
+        int recvID    = castbuf->oldnum;
+        void *temp_ptr; 
+        int isInte = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+        assert(isInte);
+        const VectorOfCommonpVertex_type *recup = 
+          (const VectorOfCommonpVertex_type *) temp_ptr;
+        unsigned int j=0;
+        for( j=0 ; j<(*recup).size() ; j++) {
+          int remoteID  = (*recup)[j].first;
+          assert((*recup)[j].second);
+          if(remoteID == recvID) break;
+        }
+        assert(j!= (*recup).size());  
+        AP_free(msg);      
+      }
+    
+    }      
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;
+
+
+
+  }
+
+  // -------------------------------------------------------------------
+  void checkRemotePointer2(pMesh mesh, pMeshDataId tagData ) {
+    int nproc,myrank;
+  
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+    pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+
+    int *sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+ 
+    VIter vit = M_vertexIter(mesh);  
+    pVertex pv;
+    while ((pv = VIter_next(vit))) {
+      void *temp_ptr; 
+      int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+      if(!isInterface) continue;
+      int tmp;
+      int isChange=EN_getDataInt((pEntity) pv , tagChange, &tmp);
+      if(!(isChange && tmp==1)) continue;
+      const VectorOfCommonpVertex_type *recup = 
+        (const VectorOfCommonpVertex_type *) temp_ptr;
+      int sizeinterface = (*recup).size();
+
+      for(int i=0 ; i<sizeinterface ; i++) {
+        int remoteID = (*recup)[i].first;
+        assert(remoteID!=myrank);
+        void *buf = AP_alloc(remoteID,444,sizeof(oldinterfaces_comm));
+        oldinterfaces_comm *castbuf = (oldinterfaces_comm *) buf; 
+        castbuf->oldnum = myrank;
+        castbuf->oldpv  = (*recup)[i].second;
+        AP_send(buf);
+        sendcounts[remoteID]++;       
+      } 
+    }
+    VIter_delete(vit);   
+
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+
+    /*receive pointers*/
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        oldinterfaces_comm * castbuf = (oldinterfaces_comm *) msg;
+        pVertex pv    = castbuf->oldpv;
+        int recvID    = castbuf->oldnum;
+        void *temp_ptr; 
+        int isInte = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+        assert(isInte);
+        const VectorOfCommonpVertex_type *recup = 
+          (const VectorOfCommonpVertex_type *) temp_ptr;
+        unsigned int j=0;
+        for( j=0 ; j<(*recup).size() ; j++) {
+          int remoteID  = (*recup)[j].first;
+          if(remoteID == recvID) break;
+        }
+        assert(j!= (*recup).size());  
+        AP_free(msg);      
+      }
+    
+    }      
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;
+
+
+
+  }
+
+  // -------------------------------------------------------------------
+  void checkRemotePointerChange(pMesh mesh, pMeshDataId tagData,
+                                pMeshDataId tagNew, pMeshDataId tagChange ) {
+    int nproc,myrank;
+  
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+    int *sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+ 
+    VIter vit = M_vertexIter(mesh);  
+    pVertex pv;
+    while ((pv = VIter_next(vit))) {
+      int tmp;
+      int isChange = EN_getDataInt((pEntity) pv , tagChange, &tmp);
+      if(isChange) {
+        void *temp_ptr; 
+        int isInterface = EN_getDataPtr((pEntity) pv , tagNew, &temp_ptr);
+        assert(isInterface);
+        if(!isInterface) continue;
+        VectorOfCommonpVertex_type *recup = 
+          (VectorOfCommonpVertex_type *) temp_ptr;
+        int sizeinterface = (*recup).size();
+        for(int i=0 ; i<sizeinterface ; i++) {
+          int remoteID = (*recup)[i].first;
+          if(remoteID==myrank){
+            assert(sizeinterface==1);
+            continue;
+          }
+          void *buf = AP_alloc(remoteID,444,sizeof(oldinterfaces_comm));
+          oldinterfaces_comm *castbuf = (oldinterfaces_comm *) buf; 
+          castbuf->oldnum = myrank;
+          castbuf->oldpv  = (*recup)[i].second;
+          AP_send(buf);
+          sendcounts[remoteID]++;       
+        } 
+    
+      } else {
+        void *temp_ptr; 
+        int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+        if(!isInterface) continue;
+        const VectorOfCommonpVertex_type *recup = 
+          (const VectorOfCommonpVertex_type *) temp_ptr;
+        int sizeinterface = (*recup).size();
+
+        for(int i=0 ; i<sizeinterface ; i++) {
+          int remoteID = (*recup)[i].first;
+          assert(remoteID!=myrank);
+          void *buf = AP_alloc(remoteID,444,sizeof(oldinterfaces_comm));
+          oldinterfaces_comm *castbuf = (oldinterfaces_comm *) buf; 
+          castbuf->oldnum = myrank;
+          castbuf->oldpv  = (*recup)[i].second;
+          AP_send(buf);
+          sendcounts[remoteID]++;       
+        } 
+      }
+    }
+    VIter_delete(vit);   
+
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+
+    /*receive pointers*/
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        oldinterfaces_comm * castbuf = (oldinterfaces_comm *) msg;
+        pVertex pv    = castbuf->oldpv;
+        int recvID    = castbuf->oldnum;
+        int tmp;
+        int isChange = EN_getDataInt((pEntity) pv , tagChange, &tmp);
+        if(isChange) {
+          void *temp_ptr; 
+          int isInte = EN_getDataPtr((pEntity) pv , tagNew, &temp_ptr);
+          assert(isInte);
+          VectorOfCommonpVertex_type *recup = 
+            (VectorOfCommonpVertex_type *) temp_ptr;
+          unsigned int j=0;
+          for( j=0 ; j<(*recup).size() ; j++) {
+            int remoteID  = (*recup)[j].first;
+            if(remoteID == recvID) break;
+          }
+          assert(j!= (*recup).size());  
+      
+        } else {
+          void *temp_ptr; 
+          int isInte = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+          if(isInte) {
+            unsigned int j=0;
+            const VectorOfCommonpVertex_type *recup = 
+              (const VectorOfCommonpVertex_type *) temp_ptr;
+            for( j=0 ; j<(*recup).size() ; j++) {
+              int remoteID  = (*recup)[j].first;
+              if(remoteID == recvID) break;
+            }
+            if(j==(*recup).size()) {
+              void *temp_ptr2; 
+              int is = EN_getDataPtr((pEntity) pv , tagNew, &temp_ptr2);
+              assert(is);
+              VectorOfCommonpVertex_type *recup2 = 
+                (VectorOfCommonpVertex_type *) temp_ptr2;
+              if((*recup2).size()==1) break;
+              for( j=0 ; j<(*recup2).size() ; j++) {
+                int remoteID  = (*recup2)[j].first;
+                if(remoteID == recvID) break;
+              }
+              if(j==(*recup2).size()) {
+                for( j=0 ; j<(*recup2).size() ; j++) {
+                  printf("recup2 %d\n",(*recup2)[j].first);
+                }       
+                printf("je suis %d et tu es %d\n",myrank,recvID);
+              }  
+              assert(j<(*recup2).size());
+              int minproc = nproc + 10;
+              for( j=0 ; j<(*recup2).size() ; j++) {
+                int remoteID  = (*recup2)[j].first;
+                minproc = std::min(minproc,remoteID);
+              }
+              assert(minproc==recvID);
+            }
+          }
+        }
+        AP_free(msg);      
+      }
+    
+    }      
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;
+  }
+
+  // -------------------------------------------------------------------
+  void checkNew(pMesh mesh, pMeshDataId tagData,pMeshDataId tagChange ) {
+    int nproc,myrank;
+  
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+    pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+    pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+
+    VIter vit = M_vertexIter(mesh);  
+    pVertex pv;
+  
+    while ((pv = VIter_next(vit))) {
+      int tmp;
+      int isMaster = EN_getDataInt((pEntity) pv , tagMaster, &tmp);
+      if(!isMaster) continue;
+      int isChange = EN_getDataInt((pEntity) pv , tagChange, &tmp);
+      if(!(isChange && (tmp==1))) continue;
+      void *temp_ptr; 
+      int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+      assert(isInterface);
+      const VectorOfCommonpVertex_type *recup = 
+        (const VectorOfCommonpVertex_type *) temp_ptr;
+      int sizeinterface = (*recup).size();
+      if(sizeinterface<=1) {
+        printf("--------------- my %d\n",myrank);
+        unsigned int kk;
+        for(kk=0 ; kk<(*recup).size() ; kk++) {
+          printf("recup %d \n",(*recup)[kk].first);
+        }
+        void *temp_ptr2; 
+        int is = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr2);
+        assert(is);
+        VectorOfCommonpVertex_type *recup2 = 
+          (VectorOfCommonpVertex_type *) temp_ptr2;
+        assert((*recup2).size());
+        for(kk=0 ; kk<(*recup2).size() ; kk++){
+          printf("recup2 %d \n",(*recup2)[kk].first); 
+        }
+      }
+      assert(sizeinterface>1);
+      int i;
+      for(i=0 ; i<sizeinterface ; i++){
+        if(myrank==(*recup)[i].first) break;
+      }
+      assert(i<sizeinterface);
+    }
+    VIter_delete(vit); 
+  
+    vit = M_vertexIter(mesh);  
+    while ((pv = VIter_next(vit))) {
+      int tmp;
+      int isChange = EN_getDataInt((pEntity) pv , tagChange, &tmp);
+      if(!(isChange && (tmp==1))) continue;
+      void *temp_ptr; 
+      int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+      assert(isInterface);
+      const VectorOfCommonpVertex_type *recup = 
+        (const VectorOfCommonpVertex_type *) temp_ptr;
+      int sizeinterface = (*recup).size();
+      if(sizeinterface<=1) {
+        printf("--------------- my %d\n",myrank);
+        unsigned int kk;
+        for(kk=0 ; kk<(*recup).size() ; kk++){
+          printf("recup %d \n",(*recup)[kk].first);
+        }
+        void *temp_ptr2; 
+        int is = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr2);
+        assert(is);
+        VectorOfCommonpVertex_type *recup2 =
+          (VectorOfCommonpVertex_type *) temp_ptr2;
+        assert((*recup2).size());
+        for(kk=0 ; kk<(*recup2).size() ; kk++) {
+          printf("recup2 %d %p\n",(*recup2)[kk].first,(*recup2)[kk].second);   
+        } 
+      } 
+      assert(sizeinterface>1);
+      int i;
+      for(i=0 ; i<sizeinterface ; i++){
+        if(myrank==(*recup)[i].first) break;
+      }
+      assert(i<sizeinterface);
+    }
+    VIter_delete(vit);   
+  }
+
+#endif
+
+  // -------------------------------------------------------------------
+  void UpdateInterfaces4(pMesh mesh) {
+    int nproc,myrank;
+  
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+    int *sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+    pMeshDataId tagData   = MD_lookupMeshDataId("RemotePoint");
+    pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+    pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+
+    VIter vit = M_vertexIter(mesh);  
+    pVertex pv;
+    while ((pv = VIter_next(vit))) {
+      int tmp; 
+      int isMaster = EN_getDataInt((pEntity) pv , tagMaster,&tmp);
+      if(!isMaster) continue;
+    
+      int isChanged = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+      assert(tmp==1 && isChanged);
+
+      void *temp_ptr; 
+      int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+      assert(isInterface);
+      const VectorOfCommonpVertex_type *recup =
+        (const VectorOfCommonpVertex_type *) temp_ptr;
+      assert((*recup).size()>1);
+
+      for(unsigned int i=0 ; i<(*recup).size() ; i++) {
+        int remoteID = (*recup)[i].first;
+        if(remoteID==myrank) continue;
+        pVertex remoteP = (*recup)[i].second;
+        assert(remoteP);
+        for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+          int intID = (*recup)[j].first;
+          if(intID==remoteID || intID==myrank) continue;
+          pVertex intP = (*recup)[j].second;
+          assert(intP);
+          void *buf = AP_alloc(remoteID,444,sizeof(points_comm_new));
+          points_comm_new *castbuf = (points_comm_new *) buf; 
+          castbuf->pdest  = remoteP;
+          castbuf->psend  = intP;
+          castbuf->sendID = intID;
+          AP_send(buf);
+          sendcounts[remoteID]++;      
+        }
+      }
+    }
+    VIter_delete(vit);   
+
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+
+    /*receive pointers*/
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        points_comm_new * castbuf = (points_comm_new *) msg;
+        pVertex pmine =  castbuf->pdest;
+        pVertex precv  = castbuf->psend;
+        int     recvID = castbuf->sendID;
+        void *temp_ptr; 
+        int isInterface = EN_getDataPtr((pEntity) pmine , tagData, &temp_ptr);
+        int tmp; 
+        int isMaster = EN_getDataInt((pEntity) pmine , tagMaster,&tmp);
+        assert(isInterface);
+        assert(!isMaster);
+        VectorOfCommonpVertex_type *recup = 
+          (VectorOfCommonpVertex_type *) temp_ptr;
+        unsigned int j=0;
+        for(j=0 ; j<(*recup).size() ; j++) {
+          int remoteID  = (*recup)[j].first;
+          if(remoteID == recvID) {
+            (*recup)[j].second = precv;
+            break;
+          }
+        }           
+        assert(j<(*recup).size());    
+        AP_free(msg);      
+      }
+    
+    }      
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;
+  
+    vit = M_vertexIter(mesh);  
+    while ((pv = VIter_next(vit))) {
+      int tmp;     
+      EN_getDataInt((pEntity) pv , tagChange,&tmp);
+      if(tmp!=1) continue;
+
+      void *temp_ptr; 
+      int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+      assert(isInterface);
+      const VectorOfCommonpVertex_type *recup = 
+        (const VectorOfCommonpVertex_type *) temp_ptr;
+      assert((*recup).size()>1);
+
+      VectorOfCommonpVertex_type newInterface;
+      for(unsigned int i=0 ; i<(*recup).size() ; i++) {
+        int remoteID = (*recup)[i].first;
+        if(remoteID==myrank) continue;
+        pVertex remoteP = (*recup)[i].second;
+        assert(remoteP);
+        newInterface.push_back(CommonpVertex_type(remoteID,remoteP));
+      }
+      EN_attachDataPtr((pEntity) pv ,tagData, 
+                       new VectorOfCommonpVertex_type(newInterface));                
+
+    }
+    VIter_delete(vit);   
+
+
+  }  
+  
+  // -------------------------------------------------------------------
+  void UpdateInterfaces3(pMesh mesh) {
+    int nproc,myrank;
+  
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+    int *sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+    pMeshDataId tagData   = MD_lookupMeshDataId("RemotePoint");
+    pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+    pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+
+    VIter vit = M_vertexIter(mesh);  
+    pVertex pv;
+    while ((pv = VIter_next(vit))) {
+      int tmp; 
+      int isChanged = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+      if(!isChanged) continue;
+      if(tmp==2) continue;
+      if(tmp==3) continue;
+      assert(tmp==1);
+      void *temp_ptr; 
+      int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+      int isMaster = EN_getDataInt((pEntity) pv , tagMaster,&tmp);
+      if(isMaster) assert(isInterface);
+      assert(isInterface);
+      const VectorOfCommonpVertex_type *recup = 
+        (const VectorOfCommonpVertex_type *) temp_ptr;
+      if(isMaster) assert((*recup).size()>1);
+      if(!isMaster) {
+        assert((*recup).size()>1);
+        int remoteID = nproc + 10;
+        pVertex psend;
+        for(unsigned int i=0 ; i<(*recup).size() ; i++) {
+          if(remoteID > (*recup)[i].first) {
+            remoteID = (*recup)[i].first;
+            psend    = (*recup)[i].second;
+          }
+        }
+        assert(remoteID < nproc);
+        assert(remoteID!=myrank);
+        assert(remoteID<myrank);
+        for(unsigned int i=0 ; i<(*recup).size() ; i++) {
+          assert(remoteID <=(*recup)[i].first);
+        }
+        void *buf = AP_alloc(remoteID,444,sizeof(points_comm_new));
+        points_comm_new *castbuf = (points_comm_new *) buf; 
+        castbuf->pdest  = psend;
+        castbuf->psend  = pv;
+        castbuf->sendID = myrank;
+        AP_send(buf);
+        sendcounts[remoteID]++;      
+      }
+    }
+    VIter_delete(vit);   
+
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+
+    /*receive pointers*/
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        points_comm_new * castbuf = (points_comm_new *) msg;
+        pVertex pmine =  castbuf->pdest;
+        pVertex precv  = castbuf->psend;
+        int     recvID = castbuf->sendID;
+        void *temp_ptr; 
+        int isInterface = EN_getDataPtr((pEntity) pmine , tagData, &temp_ptr);
+        int tmp; 
+        int isMaster = EN_getDataInt((pEntity) pmine , tagMaster,&tmp);
+        assert(isInterface);
+        assert(isInterface && isMaster);
+        VectorOfCommonpVertex_type *recup = 
+          (VectorOfCommonpVertex_type *) temp_ptr;
+        unsigned int j=0;
+        for(j=0 ; j<(*recup).size() ; j++) {
+          int remoteID  = (*recup)[j].first;
+          if(remoteID == recvID) {
+            (*recup)[j].second = precv;
+            break;
+          }
+        }           
+        assert(j<(*recup).size());    
+        AP_free(msg);      
+      }
+    
+    }      
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;
+  }  
+  
+  // -------------------------------------------------------------------
+  void UpdateInterfaces2(pMesh mesh, MDB_DataExchanger &de) {
+    int nproc,myrank;
+  
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+    int *sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+    pMeshDataId tagData   = MD_lookupMeshDataId("RemotePoint");
+    pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+    pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+    pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+ 
+    VIter vit = M_vertexIter(mesh);  
+    pVertex pv;
+    while ((pv = VIter_next(vit))) {
+      int tmp; 
+      int isMaster = EN_getDataInt((pEntity) pv , tagMaster,&tmp);
+      if(!isMaster) continue;
+#ifdef DEBUG
+      int isChanged = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+      assert(isChanged);
+      assert(tmp==1);
+#endif
+      void *temp_ptr2; 
+      int is = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr2);
+      assert(is);
+      const VectorOfCommonpVertex_type *recup2 = 
+        (const VectorOfCommonpVertex_type *) temp_ptr2;
+      int sizeinterface = (*recup2).size();
+      assert(sizeinterface>1);
+      int  *listID=new int[sizeinterface];
+      for(int i=0 ; i<sizeinterface ; i++){
+        listID[i] = (*recup2)[i].first;
+      }
+#ifdef DEBUG
+      int k;
+      for(k=0 ; k<sizeinterface ; k++){
+        if(myrank==(*recup2)[k].first) break;
+      }
+      assert(k!=sizeinterface);
+#endif
+      void *temp_ptr; 
+      int oldPoint = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr);
+      VectorOfCommonpVertex_type *recup = 
+        (VectorOfCommonpVertex_type *) temp_ptr;
+      assert(oldPoint);
+      assert((*recup).size());
+#ifdef DEBUG
+      unsigned int kk;
+      for(kk=0 ; kk<(*recup).size() ; kk++){
+        if(myrank==(*recup)[kk].first) break;
+      }
+      if(kk!=(*recup).size()) {
+        if((*recup).size()!=1) {
+          printf("----------------- myrank %d %d\n",myrank,kk);
+          for(k=0 ; k<sizeinterface ; k++){
+            printf("recup2 %d \n",(*recup2)[k].first);
+          }
+          for(kk=0 ; kk<(*recup).size() ; kk++){
+            printf("recup %d \n",(*recup)[kk].first);
+          }
+        }
+        assert((*recup).size()==1);
+      }
+#endif
+
+      int *tabp=new int[nproc];
+      int *tabproc=new int[nproc];
+      for(int i=0 ; i<nproc ; i++) tabproc[i] = 0;
+      for(unsigned int i=0 ; i<(*recup).size() ; i++) {
+        tabproc[(*recup)[i].first] += 1;
+        tabp[(*recup)[i].first]     = i;
+      }
+      for(int i=0 ; i<sizeinterface ; i++) {
+        int remoteID = (*recup2)[i].first;
+        if(remoteID==myrank) continue;
+        if(tabproc[remoteID]) { /*already exists --  send my pointer, my ID and its pointer*/
+          assert(tabproc[remoteID]==1);
+          assert(remoteID!=myrank);
+          int sizebuf;
+          void *msg = de.sendData ((pEntity) pv, remoteID, sizebuf );
+  
+          void *buf = AP_alloc(remoteID,de.tag(),sizeof(int) + 
+                               sizeof(points_comm_new) + sizebuf);
+          char *castbuf = (char *) buf; 
+          int  cas = -1;
+          memcpy(&castbuf[0],&cas,sizeof(int));
+          points_comm_new pcn;
+          pcn.pdest  = ((*recup)[tabp[remoteID]]).second;
+          assert(((*recup)[tabp[remoteID]]).first==remoteID);
+          pcn.psend  = pv;
+          pcn.sendID = myrank;
+          pcn.destID = remoteID;
+          memcpy(&castbuf[sizeof(int)],&pcn,sizeof(points_comm_new));
+          memcpy(&castbuf[sizeof(int)+sizeof(points_comm_new)],msg,sizebuf);        
+          free(msg);
+          AP_send(buf);
+          sendcounts[remoteID]++;       
+        } else { /*new for proc remoteID  -- send coor point + Remote info + my pointer*/
+          assert(remoteID!=myrank);
+          int sizebuf;
+          void *msg = de.sendData ((pEntity) pv, remoteID, sizebuf );
+          void *buf = AP_alloc(remoteID,de.tag(),2*sizeof(int)+ 
+                               sizeof(coor_comm)+ (sizeinterface) * sizeof(int) + sizebuf );
+          char *castbuf = (char *) buf; 
+          int  cas = 1;
+          memcpy(&castbuf[0],&cas,sizeof(int));
+          coor_comm  coorcom;           
+          coorcom.X     = P_x(pv);
+          coorcom.Y     = P_y(pv);
+          coorcom.Z     = P_z(pv);
+          pGEntity  pg  = EN_whatIn(pv);
+          coorcom.tag   = GEN_tag(pg);
+          coorcom.dim   = GEN_type(pg);
+          coorcom.nproc = myrank;
+          coorcom.psend = pv;
+          memcpy(&castbuf[sizeof(int)],&coorcom,sizeof(coor_comm));
+          memcpy(&castbuf[sizeof(int) + sizeof(coor_comm)],&sizeinterface,sizeof(int));
+          memcpy(&castbuf[sizeof(int) + sizeof(coor_comm) + sizeof(int)],&listID[0],sizeinterface * sizeof(int));
+          memcpy(&castbuf[2*sizeof(int) + sizeof(coor_comm)+ (sizeinterface) * sizeof(int)],msg,sizebuf);
+          free(msg);
+          AP_send(buf);
+          sendcounts[remoteID]++;                  
+        }
+      }       
+      delete []tabp;
+      delete []tabproc;
+      delete []listID;
+    }
+    VIter_delete(vit);   
+
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+
+    /*receive pointers*/
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        char * castbuf = (char *) msg;
+        int cas = *((int *) &castbuf[0]);
+        if(cas == 1) {/*point doesn't exist*/
+          coor_comm * coorcom = (coor_comm * ) &castbuf[sizeof(int)];
+          pGEntity pent;
+          int dim  = coorcom->dim;
+          int tag  = coorcom->tag;
+          if(dim == 0) {
+            pent = (pGEntity) GM_vertexByTag(mesh->model,tag);
+          } else if(dim==1) {
+            pent = (pGEntity) GM_edgeByTag(mesh->model,tag);     
+          } else if(dim==2) {
+            pent = (pGEntity) GM_faceByTag(mesh->model,tag);
+          } else if(dim==3) {
+            pent = (pGEntity) GM_regionByTag(mesh->model,tag);
+          } else {
+            printf("pbs**** %d\n",dim);
+          }
+          //           double  X = coorcom->X;
+          //           double  Y = coorcom->Y;
+          //           double  Z = coorcom->Z;
+          //           pVertex pnew = M_createVP(mesh,X,Y,Z,-1,pent);
+          
+          double  XYZ[3] = {coorcom->X,coorcom->Y,coorcom->Z};
+          pVertex pnew = M_createV2(mesh,XYZ,-1,pent);
+
+          assert(pnew);
+          int procdep  = coorcom->nproc;
+          pVertex pdep = coorcom->psend;
+          unsigned int sizeinterfaces = *((int *) &castbuf[sizeof(int) + 
+                                                           sizeof(coor_comm)]);
+          assert(sizeinterfaces > 1);
+          VectorOfCommonpVertex_type RemoteData;
+          int isOK=0;
+          for(unsigned int i=0 ; i<sizeinterfaces ; i++) {
+            int num = *((int *) &castbuf[2*sizeof(int) + sizeof(coor_comm) 
+                                         + i*sizeof(int)]);
+            if(num==procdep) {
+              isOK = 1;
+              RemoteData.push_back(CommonpVertex_type(procdep,pdep));
+            } else {
+              RemoteData.push_back(CommonpVertex_type(num,NULL));     
+            }
+          } 
+          assert(isOK);
+          EN_attachDataInt((pEntity) pnew ,tagChange, 1);
+          assert(RemoteData.size()==sizeinterfaces);
+          assert(RemoteData.size()>1);
+
+          EN_attachDataPtr((pEntity) pnew ,tagData, 
+                           new VectorOfCommonpVertex_type(RemoteData));               
+          de.receiveData (pnew,from, &castbuf[2*sizeof(int)
+                                              + sizeof(coor_comm)+ (sizeinterfaces) * sizeof(int)]);
+           
+        } else { /*point already exists*/
+          assert(cas==-1);
+          points_comm_new * pcn = (points_comm_new * ) &castbuf[sizeof(int)];
+          pVertex pv    = pcn->pdest;
+          pVertex precv = pcn->psend;
+          int recvID    = pcn->sendID;
+          int destID    = pcn->destID;
+          assert(pv);
+          assert(destID==myrank);
+          assert(recvID!=myrank);
+          void *temp_ptr; 
+          int isInte = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr);
+          assert(isInte);
+#ifdef DEBUG
+          int tmp; 
+          int isMaster = EN_getDataInt((pEntity) pv , tagMaster,&tmp);
+          assert(isInte && !isMaster);
+          int isC = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+          assert(isC && (tmp==1));
+#endif
+          VectorOfCommonpVertex_type *recup = 
+            (VectorOfCommonpVertex_type *) temp_ptr;
+          assert((*recup).size()>1);
+          VectorOfCommonpVertex_type newRemote;
+          for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+            int remoteID  = (*recup)[j].first;
+            if(remoteID == recvID) {
+              newRemote.push_back(CommonpVertex_type(remoteID,precv));
+            } else {
+              newRemote.push_back(CommonpVertex_type(remoteID,NULL));
+            }
+          }
+          assert(newRemote.size()>1);
+          void *temp_ptr2; 
+          int is = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr2);
+          if(is) EN_deleteData((pEntity) pv , tagData);
+
+          EN_attachDataPtr((pEntity) pv ,tagData, 
+                           new VectorOfCommonpVertex_type(newRemote));                
+          de.receiveData (pv,from, &castbuf[sizeof(int)+sizeof(points_comm_new)]);
+          
+        }     
+        AP_free(msg);      
+      }
+    
+    }      
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;
+  
+  }
+
+  
+  // -------------------------------------------------------------------
+  void UpdateInterfaces1(pMesh mesh, MDB_DataExchanger &de)
+  {
+    int nproc,myrank;
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+    int *sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+    pMeshDataId tagData   = MD_lookupMeshDataId("RemotePoint");
+    pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+    pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+    pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+ 
+    VIter vit = M_vertexIter(mesh);  
+    pVertex pv;
+    while ((pv = VIter_next(vit))) {
+      int tmp; 
+      int isChanged = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+      if(!isChanged) continue;
+      void *temp_ptr2; 
+      int is = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr2);
+      assert(is);
+      VectorOfCommonpVertex_type *recup2 = 
+        (VectorOfCommonpVertex_type *) temp_ptr2;
+      if((*recup2).size()==1) {
+   
+        EN_attachDataInt((pEntity) pv , tagChange,2);
+        continue;
+      }
+      assert((*recup2).size()>1);
+      /*est ce que je suis a la fin?*/
+      unsigned int i=0;
+      for(i=0 ; i< (*recup2).size(); i++){
+        if(myrank==(*recup2)[i].first) break;
+      }
+      if(i==(*recup2).size()) EN_attachDataInt((pEntity) pv , tagChange,3);
+     
+      void *temp_ptr; 
+      int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+    
+      int remoteID;
+    
+      if(isInterface) {
+        const VectorOfCommonpVertex_type *recup = 
+          (const VectorOfCommonpVertex_type *) temp_ptr;
+        int minproc = nproc + 10;
+        assert((*recup).size());
+        for(unsigned int i=0 ; i<(*recup).size() ; i++){
+          minproc =         std::min(minproc,(*recup)[i].first);
+        }
+        minproc = std::min(minproc,myrank);
+       
+        remoteID = nproc + 10 ;
+        for(unsigned int i=0 ; i<(*recup2).size() ; i++) {
+          remoteID =        std::min(remoteID,(*recup2)[i].first);
+        }
+        assert(remoteID<nproc && remoteID > -1);
+      
+        if(remoteID == myrank) {
+          EN_attachDataInt((pEntity) pv , tagMaster,1);
+          /*swap RemoteData and Data*/
+          VectorOfCommonpVertex_type temp ;
+          for(unsigned int i=0 ; i<(*recup).size() ; i++) {
+            int   num = (*recup)[i].first;
+            pVertex p = (*recup)[i].second;
+            temp.push_back(CommonpVertex_type(num,p));
+          }
+          assert((*recup2).size()>1);
+          VectorOfCommonpVertex_type temp2 ;
+          for(unsigned int i=0 ; i<(*recup2).size() ; i++) {
+            int   num = (*recup2)[i].first;
+            pVertex p = (*recup2)[i].second;
+            temp2.push_back(CommonpVertex_type(num,p));
+          }
+          delete recup2;
+          delete recup;
+          EN_attachDataPtr((pEntity) pv , tagData, 
+                           new VectorOfCommonpVertex_type(temp2));    
+          EN_attachDataPtr((pEntity) pv , tagRemote, 
+                           new VectorOfCommonpVertex_type(temp));           
+          continue;
+        }
+      
+        if(minproc != myrank) continue; 
+        assert(minproc==myrank);
+        int recupsize  = (*recup).size();
+        assert(recupsize);
+        int recupsize2 = (*recup2).size();
+        int i=0;
+        for(i=0 ; i< recupsize; i++){
+          if(remoteID==(*recup)[i].first) break;
+        }
+        if(i!=recupsize) continue;       /*proc remoteID already knows info*/
+        assert(i==recupsize);
+        /*send info to remoteID*/
+        int sizebuf;
+        void *msg = de.sendData ((pEntity) pv, remoteID, sizebuf );
+        void *buf = AP_alloc(remoteID,de.tag(),2*sizeof(int)+ recupsize 
+                             * sizeof(oldinterfaces_comm)
+                             + recupsize2 * sizeof(newinterfaces_comm)
+                             +  sizeof(coor_comm) + sizebuf);
+        char *castbuf = (char *) buf; 
+        memcpy(&castbuf[0],&(recupsize),sizeof(int));          
+        for(i=0 ; i<recupsize ; i++) {  
+          oldinterfaces_comm oldint;
+          oldint.oldnum = (*recup)[i].first;
+          oldint.oldpv  = (*recup)[i].second;          
+          memcpy(&castbuf[i*sizeof(oldinterfaces_comm) 
+                          + sizeof(int)],&oldint,sizeof(oldinterfaces_comm));
+        }
+        memcpy(&castbuf[recupsize*sizeof(oldinterfaces_comm) 
+                        + sizeof(int)],&(recupsize2),sizeof(int));           
+        for(i=0 ; i<recupsize2 ; i++) {
+          newinterfaces_comm newint;
+          newint.newproc = (*recup2)[i].first;
+          memcpy(&castbuf[i * sizeof(newinterfaces_comm) 
+                          + recupsize*sizeof(oldinterfaces_comm) + 2*sizeof(int)],
+                 &newint,sizeof(newinterfaces_comm));
+        }
+        coor_comm  coorcom;       
+        coorcom.X     = P_x(pv);
+        coorcom.Y     = P_y(pv);
+        coorcom.Z     = P_z(pv);
+        pGEntity  pg  = EN_whatIn(pv);
+        coorcom.tag   = GEN_tag(pg);
+        coorcom.dim   = GEN_type(pg);
+        coorcom.nproc = myrank;
+        coorcom.psend = pv;
+        memcpy(&castbuf[recupsize * sizeof(oldinterfaces_comm)
+                        + recupsize2 * sizeof(newinterfaces_comm) 
+                        + 2*sizeof(int)],&coorcom,sizeof(coor_comm));                    
+        memcpy(&castbuf[recupsize * sizeof(oldinterfaces_comm)
+                        + recupsize2 * sizeof(newinterfaces_comm) + 2*sizeof(int)
+                        + sizeof(coor_comm)],msg,sizebuf);                     
+        free(msg);
+        AP_send(buf);
+        sendcounts[remoteID]++; 
+      } else {    
+        remoteID = nproc + 10;
+        assert((*recup2).size() != 1);
+        for(unsigned int i=0 ; i<(*recup2).size() ; i++){ 
+          remoteID = std::min(remoteID,(*recup2)[i].first);
+        }
+        assert(remoteID<nproc);
+        if(remoteID == myrank) {
+          int tmp;
+          int is = EN_getDataInt((pEntity) pv , tagMaster,&tmp);
+          assert(!is);
+          EN_attachDataInt((pEntity) pv , tagMaster, 1);
+          /*swap RemoteData and Data*/
+          assert((*recup2).size()>1);
+          VectorOfCommonpVertex_type temp2 ;
+          for(unsigned int i=0 ; i<(*recup2).size() ; i++) {
+            int   num = (*recup2)[i].first;
+            pVertex p = (*recup2)[i].second;
+            temp2.push_back(CommonpVertex_type(num,p));
+          }
+          EN_attachDataPtr((pEntity) pv , tagData, 
+                           new VectorOfCommonpVertex_type(temp2));    
+          VectorOfCommonpVertex_type temp;
+          temp.push_back(CommonpVertex_type(myrank,pv));
+          EN_attachDataPtr((pEntity) pv , tagRemote, 
+                           new VectorOfCommonpVertex_type(temp));     
+           
+  
+          continue;
+        }   
+        /*send info to remoteID*/
+        int recupsize = 0;
+        int recupsize2 = (*recup2).size();
+        int sizebuf;
+        void *msg = de.sendData ((pEntity) pv, remoteID, sizebuf );
+        void *buf = AP_alloc(remoteID,de.tag(),2*sizeof(int)
+                             + recupsize2 * sizeof(newinterfaces_comm)
+                             +  sizeof(coor_comm) +sizebuf);
+        char *castbuf = (char *) buf; 
+        memcpy(&castbuf[0],&(recupsize),sizeof(int));          
+        memcpy(&castbuf[sizeof(int)],&(recupsize2),sizeof(int));           
+        for(int i=0 ; i<recupsize2 ; i++)            
+          memcpy(&castbuf[i * sizeof(newinterfaces_comm)  + 2*sizeof(int) ],
+                 &(*recup2)[i].first,sizeof(newinterfaces_comm));
+        coor_comm  coorcom;       
+        coorcom.X     = P_x(pv);
+        coorcom.Y     = P_y(pv);
+        coorcom.Z     = P_z(pv);
+        pGEntity  pg  = EN_whatIn(pv);
+        coorcom.tag   = GEN_tag(pg);
+        coorcom.dim   = GEN_type(pg);
+        coorcom.nproc = myrank;
+        coorcom.psend = pv;
+        memcpy(&castbuf[recupsize * sizeof(oldinterfaces_comm)
+                        + recupsize2 * sizeof(newinterfaces_comm) 
+                        + 2*sizeof(int) ],&coorcom,sizeof(coor_comm));                     
+        memcpy(&castbuf[2*sizeof(int)+  recupsize2 * sizeof(newinterfaces_comm)
+                        + sizeof(coor_comm)],msg,sizebuf);                     
+        free(msg);
+        AP_send(buf);
+        sendcounts[remoteID]++; 
+      }
+    }
+
+    VIter_delete(vit);   
+
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+
+    /*receive pointers*/
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        char * castbuf = (char *) msg;
+        VectorOfCommonpVertex_type oldRemoteData;
+        int sizeold = *((int *) &castbuf[0]);
+        for(int i=0 ; i<sizeold ; i++) {
+          oldinterfaces_comm * oldint = 
+            (oldinterfaces_comm *) &castbuf[sizeof(int)+ i*sizeof(oldinterfaces_comm)];
+          int    num = oldint->oldnum;
+          pVertex pv = oldint->oldpv;
+          oldRemoteData.push_back(CommonpVertex_type(num,pv));
+        }      
+        VectorOfCommonpVertex_type newRemoteData;
+        int sizenew = *((int *) &castbuf[sizeof(int) + sizeold 
+                                         * sizeof(oldinterfaces_comm)]);
+        assert(sizenew>1);
+        for(int i=0 ; i<sizenew ; i++) {
+          newinterfaces_comm * newint = 
+            (newinterfaces_comm *) &castbuf[2*sizeof(int)+ sizeold 
+                                            * sizeof(oldinterfaces_comm) + i * sizeof(newinterfaces_comm)];
+          int nn = newint->newproc; 
+          newRemoteData.push_back(CommonpVertex_type(nn,NULL));
+      
+        }
+        coor_comm * coorcom = (coor_comm * ) &castbuf[2*sizeof(int) 
+                                                      +sizeold*sizeof(oldinterfaces_comm) + 
+                                                      sizenew*sizeof(newinterfaces_comm)];
+        pGEntity pent;
+        int dim  = coorcom->dim;
+        int tag  = coorcom->tag;
+        if(dim == 0) {
+          pent = (pGEntity) GM_vertexByTag(mesh->model,tag);
+        } else if(dim==1) {
+          pent = (pGEntity) GM_edgeByTag(mesh->model,tag);     
+        } else if(dim==2) {
+          pent = (pGEntity) GM_faceByTag(mesh->model,tag);
+        } else if(dim==3) {
+          pent = (pGEntity) GM_regionByTag(mesh->model,tag);
+        } else {
+          printf("pbs**** %d\n",dim);
+          pent = (pGEntity) GM_vertexByTag(mesh->model,tag);
+        }
+        
+        //         double  X = coorcom->X;
+        //         double  Y = coorcom->Y;
+        //         double  Z = coorcom->Z;
+        //         pVertex pnew = M_createVP(mesh,X,Y,Z,-1,pent);
+        
+        double  XYZ[3] = {coorcom->X,coorcom->Y,coorcom->Z};
+        pVertex pnew = M_createV2(mesh,XYZ,-1,pent);
+        assert(pnew);
+        int procdep = coorcom->nproc;
+        //  if(sizeold!=0) assert(procdep==-1);
+        //   if(sizeold == 0) { 
+        //  assert(!oldRemoteData.size());     
+        pVertex pinit = coorcom->psend;
+        oldRemoteData.push_back(CommonpVertex_type(procdep,pinit));
+        //  }
+
+        EN_attachDataInt((pEntity) pnew , tagChange,1);
+        EN_attachDataInt((pEntity) pnew , tagMaster,1);
+        assert(newRemoteData.size()>1);
+       
+        EN_attachDataPtr((pEntity) pnew , tagData, 
+                         new VectorOfCommonpVertex_type(newRemoteData));
+        assert(oldRemoteData.size());     
+        EN_attachDataPtr((pEntity) pnew , tagRemote, 
+                         new VectorOfCommonpVertex_type(oldRemoteData));    
+            
+        de.receiveData (pnew,from, &castbuf[2*sizeof(int)+ sizeold * 
+                                            sizeof(oldinterfaces_comm)
+                                            + sizenew * sizeof(newinterfaces_comm)
+                                            + sizeof(coor_comm)]);
+
+        AP_free(msg);
+      }    
+    }  
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;
+
+  }
+
+  // -------------------------------------------------------------------
+  void UpdateInterfaces(pMesh mesh, MDB_DataExchanger &de) {
+
+#ifdef DEBUG
+    pMeshDataId tagData   = MD_lookupMeshDataId("RemotePoint");
+    pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+    pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+    pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+#endif
+
+    /*Phase 1 : send info to the smallest rank*/
+    UpdateInterfaces1(mesh,de);
+#ifdef DEBUG
+    checkRemotePointerChange(mesh,tagData,tagRemote,tagMaster);
+    puts("check third ok");
+#endif
+
+    /*Phase 2 : send info to all proc*/
+    UpdateInterfaces2(mesh,de);
+#ifdef DEBUG  
+    checkNew(mesh,tagData,tagChange);
+    puts("check forth ok");
+#endif  
+
+    /*Phase 3 : update info of smallest rank*/
+    UpdateInterfaces3(mesh);
+  
+    /*Phase 4 : update info of all proc*/
+    UpdateInterfaces4(mesh);
+  }
+
+
+  // -------------------------------------------------------------------
+  void UpdatePointerInterface(pMesh mesh) {
+    int nproc,myrank;
+  
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+    int *sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+    pMeshDataId tagData   = MD_lookupMeshDataId("RemotePoint");
+    pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+    pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+    pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+
+    VIter vit = M_vertexIter(mesh);  
+    pVertex pv;
+    while ((pv = VIter_next(vit))) {
+      int tmp; 
+      int isChanged = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+      if(!isChanged) continue;
+      if((tmp==2) || (tmp==10) || (tmp==11)) continue; //if 1 : interface new -- if 3 : must be deleted
+      assert(tmp==1 || tmp==3);
+      int isMaster = EN_getDataInt((pEntity) pv , tagMaster,&tmp);
+      if(!isMaster) continue;
+
+      void *temp_ptr2; 
+      int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr2);
+      assert(isInterface);
+      const VectorOfCommonpVertex_type *recup2 = 
+        (const VectorOfCommonpVertex_type *) temp_ptr2;
+      assert((*recup2).size());
+    
+      void *temp_ptr; 
+      int isInternal = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr);
+      assert(isInternal);
+      VectorOfCommonpVertex_type *recup = (VectorOfCommonpVertex_type *) temp_ptr;
+      int sizeold = (*recup).size();
+      if(sizeold==1){//old internal point
+        int remoteID = (*recup)[0].first;
+        if(remoteID==myrank) continue;
+        pVertex remoteP  = (*recup)[0].second;
+        assert(remoteP);
+        for(unsigned int i=0 ; i <(*recup2).size() ; i++) {
+          int newID    = (*recup2)[i].first;
+          pVertex newP = (*recup2)[i].second;
+          assert(newP);
+          void *buf = AP_alloc(remoteID,444,sizeof(points_comm_new));
+          points_comm_new *castbuf = (points_comm_new *) buf; 
+          castbuf->pdest  = remoteP;
+          castbuf->destID = remoteID;
+          castbuf->psend  = newP;
+          castbuf->sendID = newID;
+          AP_send(buf);
+          sendcounts[remoteID]++;     
+        }
+        void *buf = AP_alloc(remoteID,444,sizeof(points_comm_new));
+        points_comm_new *castbuf = (points_comm_new *) buf; 
+        castbuf->pdest  = remoteP;
+        castbuf->destID = remoteID;
+        castbuf->psend  = pv;
+        castbuf->sendID = myrank;
+        AP_send(buf);
+        sendcounts[remoteID]++;       
+      
+      } else { //old interface point
+        int *tabproc=new int[nproc];
+        for(int i=0 ; i<nproc ; i++) tabproc[i] = 0;
+        for(unsigned int i=0 ; i <(*recup2).size() ; i++) {
+          tabproc[(*recup2)[i].first] = 1;
+        }
+        for(unsigned int i=0 ; i <(*recup).size() ; i++) {
+          int remoteID = (*recup)[i].first;
+          if(tabproc[remoteID]) continue;
+          pVertex remoteP = (*recup)[i].second;
+          assert(remoteP);
+          for(unsigned int j=0 ; j <(*recup2).size() ; j++) {
+            int newID    = (*recup2)[j].first;
+            pVertex newP = (*recup2)[j].second;
+            assert(newID!=remoteID); assert(newID!=myrank);
+            assert(newP);
+            void *buf = AP_alloc(remoteID,444,sizeof(points_comm_new));
+            points_comm_new *castbuf = (points_comm_new *) buf; 
+            castbuf->pdest  = remoteP;
+            castbuf->destID = remoteID;
+            castbuf->psend  = newP;
+            castbuf->sendID = newID;
+            AP_send(buf);
+            sendcounts[remoteID]++;     
+          }
+          void *buf = AP_alloc(remoteID,444,sizeof(points_comm_new));
+          points_comm_new *castbuf = (points_comm_new *) buf; 
+          castbuf->pdest  = remoteP;
+          castbuf->destID = remoteID;
+          castbuf->psend  = pv;
+          castbuf->sendID = myrank;
+          AP_send(buf);
+          sendcounts[remoteID]++;         
+        }
+        delete []tabproc;
+      }
+     
+    }
+    VIter_delete(vit);   
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+
+    /*receive pointers*/
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        points_comm_new * pcn = (points_comm_new * ) msg;
+        pVertex precv = pcn->pdest;
+        assert(myrank == pcn->destID);
+        int procdep = pcn->sendID;
+        pVertex pv  = pcn->psend;
+        void *temp_ptr; 
+        int isInternal = EN_getDataPtr((pEntity) precv , tagRemote, &temp_ptr);
+        assert(isInternal);
+        VectorOfCommonpVertex_type *recup = (VectorOfCommonpVertex_type *) temp_ptr;
+#ifdef DEBUG
+        int tmp;
+        int isMaster = EN_getDataInt((pEntity) precv , tagMaster, &tmp);
+        assert(!isMaster);
+#endif
+        unsigned int i;
+        for(i=0 ; i<(*recup).size() ; i++) {
+          int remoteID = (*recup)[i].first;
+          if(remoteID == procdep) {
+            (*recup)[i].second = pv;
+            break;
+          }      
+        }
+        assert(i<(*recup).size());    
+        AP_free(msg);      
+      }
+    
+    }      
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;
+  
+  }
+  // -------------------------------------------------------------------
+  void UpdateoldInterface(pMesh mesh) {
+    int nproc,myrank;
+  
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+    pMeshDataId tagData   = MD_lookupMeshDataId("RemotePoint");
+    pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+    pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+    //   pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+
+    int *  sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+
+    VIter vit = M_vertexIter(mesh);  
+    pVertex pv;
+    while ((pv = VIter_next(vit))) {
+      int tmp; 
+      int isChanged = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+      if(!isChanged) continue;
+      if(!(tmp==2 || tmp==10 || tmp==11)) continue; //if 1 : interface new -- if 3 : must be deleted
+      void *temp_ptr2; 
+      int is = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr2);
+      assert(is);
+      VectorOfCommonpVertex_type *recup2 = (VectorOfCommonpVertex_type *) temp_ptr2;
+      assert((*recup2).size()==1);
+    
+      void *temp_ptr; 
+      int isoldInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+      if(!isoldInterface) continue;
+      const VectorOfCommonpVertex_type *recup = 
+        (const VectorOfCommonpVertex_type *) temp_ptr;
+      assert((*recup).size());
+    
+      int minproc = nproc + 10;
+      for(unsigned int i=0 ; i<(*recup).size() ; i++){
+        minproc = std::min(minproc,(*recup)[i].first);
+      }
+      minproc = std::min(minproc,myrank);
+      if(minproc!=myrank) continue;
+      int newID = (*recup2)[0].first;
+      pVertex newP = (*recup2)[0].second;
+      if(!newP) {
+        assert(newID==myrank);
+        newP = pv;
+      }
+    
+      for(unsigned i=0 ; i<(*recup).size() ; i++) {
+        int remoteID = (*recup)[i].first;
+        assert(remoteID!=myrank);
+        pVertex remoteP = (*recup)[i].second;
+        void *buf = AP_alloc(remoteID,444,sizeof(points_comm_new));
+        points_comm_new *castbuf = (points_comm_new *) buf; 
+        castbuf->pdest  = remoteP;
+        castbuf->destID = remoteID;
+        castbuf->psend  = newP;
+        castbuf->sendID = newID;
+        AP_send(buf);
+        sendcounts[remoteID]++;         
+      }
+    }
+    VIter_delete(vit);   
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+  
+
+    /*receive pointers*/
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        points_comm_new * pcn = (points_comm_new * ) msg;
+        pVertex precv = pcn->pdest;
+        assert(myrank == pcn->destID);
+        int procdep = pcn->sendID;
+        pVertex pv  = pcn->psend;
+        void *temp_ptr; 
+        int isInternal = EN_getDataPtr((pEntity) precv , tagRemote, &temp_ptr);
+        assert(isInternal);
+        VectorOfCommonpVertex_type *recup = (VectorOfCommonpVertex_type *) temp_ptr;
+#ifdef DEBUG
+        int tmp;
+        int isChange = EN_getDataInt((pEntity) precv , tagChange, &tmp);
+        assert(isChange);
+        //assert(tmp==2);
+        assert((*recup).size()==1);
+#endif
+        int remoteID = (*recup)[0].first;
+        assert(remoteID == procdep);
+        (*recup)[0].second = pv;
+        AP_free(msg);      
+      }
+    
+    }      
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;  
+
+
+  }
+
+  // -------------------------------------------------------------------
+  void UpdatePointerInternal(pMesh mesh) {
+    int nproc,myrank;
+  
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+    int *sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+    pMeshDataId tagData   = MD_lookupMeshDataId("RemotePoint");
+    pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+    pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+    //   pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+
+    VIter vit = M_vertexIter(mesh);  
+    pVertex pv;
+    while ((pv = VIter_next(vit))) {
+      int tmp; 
+      int isChanged = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+      if(!isChanged) continue;
+      if(!(tmp==10 || tmp==11)) continue; //if 1 : interface new -- if 3 : must be deleted
+
+      void *temp_ptr2; 
+      int is = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr2);
+      assert(is);
+      VectorOfCommonpVertex_type *recup2 = (VectorOfCommonpVertex_type *) temp_ptr2;
+      assert((*recup2).size()==1);
+    
+      if(tmp==10) {
+        int remoteID = (*recup2)[0].first;
+        if(remoteID==myrank) continue;
+        pVertex remoteP = (*recup2)[0].second;
+        assert(remoteP);
+        void *buf = AP_alloc(remoteID,444,sizeof(points_comm_new));
+        points_comm_new *castbuf = (points_comm_new *) buf; 
+        castbuf->pdest  = remoteP;
+        castbuf->destID = remoteID;
+        castbuf->psend  = pv;
+        castbuf->sendID = myrank;
+        AP_send(buf);
+        sendcounts[remoteID]++;
+      } else {
+        void *temp_ptr; 
+        is = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+        assert(is);
+        const VectorOfCommonpVertex_type *recup = 
+          (const VectorOfCommonpVertex_type *) temp_ptr;
+        assert((*recup).size());
+        int minproc = nproc + 10;
+        int ip ;
+        for(unsigned int i=0 ; i<(*recup).size() ; i++) {
+          if(minproc > (*recup)[i].first) {
+            minproc = (*recup)[i].first;
+            ip      = i;
+          }
+        }   
+        minproc = std::min(minproc,myrank);
+        if(minproc==myrank) continue;
+        void *buf = AP_alloc(minproc,444,sizeof(points_comm_new));
+        points_comm_new *castbuf = (points_comm_new *) buf; 
+        castbuf->pdest  = (*recup)[ip].second;
+        castbuf->destID =  minproc;
+        castbuf->psend  = pv;
+        castbuf->sendID = myrank;
+        AP_send(buf);
+        sendcounts[minproc]++;
+      }     
+    }
+    VIter_delete(vit);   
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+
+    /*receive pointers*/
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        points_comm_new * pcn = (points_comm_new * ) msg;
+        pVertex precv = pcn->pdest;
+        assert(myrank == pcn->destID);
+        int procdep = pcn->sendID;
+        pVertex pv  = pcn->psend;
+        void *temp_ptr; 
+        int isInternal = EN_getDataPtr((pEntity) precv , tagRemote, &temp_ptr);
+        assert(isInternal);
+        VectorOfCommonpVertex_type *recup = (VectorOfCommonpVertex_type *) temp_ptr;
+#ifdef DEBUG
+        int tmp;
+        int isChange = EN_getDataInt((pEntity) precv , tagChange, &tmp);
+        assert(isChange);
+        assert(tmp==2);
+        assert((*recup).size()==1);
+#endif
+        int remoteID = (*recup)[0].first;
+        assert(remoteID == procdep);
+        (*recup)[0].second = pv;
+        AP_free(msg);      
+      }
+    
+    }      
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;
+  
+    UpdateoldInterface(mesh);
+  }
+
+  // -------------------------------------------------------------------
+  void SendVertex(pMesh mesh, MDB_DataExchanger &de)
+  {
+    int nproc,myrank;
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+    int *sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+    pMeshDataId tagData   = MD_lookupMeshDataId("RemotePoint");
+    pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+    pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+
+    VIter vit = M_vertexIter(mesh);  
+    pVertex pv;
+    while ((pv = VIter_next(vit))) {
+      int tmp; 
+      int isChanged = EN_getDataInt((pEntity) pv , tagChange,&tmp);
+      if(!isChanged) continue;
+      if(tmp!=2) continue; //if 1 : interface new -- if 3 : must be deleted
+
+      void *temp_ptr2; 
+      int isInternal = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr2);
+      assert(isInternal);
+      VectorOfCommonpVertex_type *recup2 = 
+        (VectorOfCommonpVertex_type *) temp_ptr2;
+      assert((*recup2).size()==1);
+        
+      void *temp_ptr; 
+      int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+      if(isInterface){
+        /*send only if I'm minproc*/
+        const VectorOfCommonpVertex_type *recup = 
+          (const VectorOfCommonpVertex_type *) temp_ptr;
+        int minproc = nproc + 10;
+        int *tabproc=new int[nproc];
+        for(int i=0 ; i<nproc ; i++) tabproc[i] = 0;
+        for(unsigned int i=0 ; i<(*recup).size() ; i++) {
+          minproc = std::min(minproc,(*recup)[i].first);
+          tabproc[(*recup)[i].first] = 1;
+        }
+        minproc = std::min(minproc,myrank);
+      
+        int remoteID = (*recup2)[0].first;
+        if(remoteID==myrank)  {
+          EN_attachDataInt((pEntity) pv , tagChange,11);
+          continue;
+        }      
+      
+        if(minproc!=myrank) continue;
+      
+      
+        if(tabproc[remoteID]) continue; //remoteID already knows info
+        int sizebuf;
+        void *msg = de.sendData ((pEntity) pv, remoteID, sizebuf );
+        void *buf = AP_alloc(remoteID,de.tag(),sizeof(coor_comm)+sizebuf);
+
+        char *cast = (char *) buf;  
+        coor_comm castbuf; 
+        castbuf.X     = P_x(pv);
+        castbuf.Y     = P_y(pv);
+        castbuf.Z     = P_z(pv);
+        pGEntity  pg  = EN_whatIn(pv);
+        castbuf.tag   = GEN_tag(pg);
+        castbuf.dim   = GEN_type(pg);
+        castbuf.nproc = myrank;
+        castbuf.psend = pv;
+        memcpy(&cast[0],&castbuf,sizeof(coor_comm));           
+        memcpy(&cast[sizeof(coor_comm)],msg,sizebuf);          
+        free(msg);
+        AP_send(buf);
+        sendcounts[remoteID]++;    
+        delete []tabproc;
+      } else {
+        int remoteID = (*recup2)[0].first;
+        assert(remoteID!=myrank);
+        int sizebuf;
+        void *msg = de.sendData ((pEntity) pv, remoteID, sizebuf );
+        void *buf = AP_alloc(remoteID,de.tag(),sizeof(coor_comm)+sizebuf);
+        char *cast = (char *) buf;  
+        coor_comm castbuf ; 
+        castbuf.X     = P_x(pv);
+        castbuf.Y     = P_y(pv);
+        castbuf.Z     = P_z(pv);
+        pGEntity  pg   = EN_whatIn(pv);
+        castbuf.tag   = GEN_tag(pg);
+        castbuf.dim   = GEN_type(pg);
+        castbuf.nproc = myrank;
+        castbuf.psend = pv;
+        memcpy(&cast[0],&castbuf,sizeof(coor_comm));           
+        memcpy(&cast[sizeof(coor_comm)],msg,sizebuf);          
+        free(msg);
+        AP_send(buf);
+        sendcounts[remoteID]++;    
+      }
+    }
+    VIter_delete(vit);   
+
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+
+    /*receive pointers*/
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        char * castbuf = (char *) msg;
+        coor_comm * coorcom = (coor_comm * )  &castbuf[0];
+        pGEntity pent;
+        int dim  = coorcom->dim;
+        int tag  = coorcom->tag;
+        if(dim == 0) {
+          pent = (pGEntity) GM_vertexByTag(mesh->model,tag);
+        } else if(dim==1) {
+          pent = (pGEntity) GM_edgeByTag(mesh->model,tag);     
+        } else if(dim==2) {
+          pent = (pGEntity) GM_faceByTag(mesh->model,tag);
+        } else if(dim==3) {
+          pent = (pGEntity) GM_regionByTag(mesh->model,tag);
+        } else {
+          printf("pbs**** %d\n",dim);
+        }
+        //         double  X = coorcom->X;
+        //         double  Y = coorcom->Y;
+        //         double  Z = coorcom->Z;
+        //         pVertex pnew = M_createVP(mesh,X,Y,Z,-1,pent);
+        double  XYZ[3] = {coorcom->X,coorcom->Y,coorcom->Z};
+        pVertex pnew = M_createV2(mesh,XYZ,-1,pent);
+        assert(pnew);
+        int procdep = coorcom->nproc;
+        pVertex pv  = coorcom->psend;
+        EN_attachDataInt((pEntity) pnew , tagChange,10);
+        VectorOfCommonpVertex_type oldRemoteData;
+        oldRemoteData.push_back(CommonpVertex_type(procdep,pv));
+        EN_attachDataPtr((pEntity) pnew , tagRemote, 
+                         new VectorOfCommonpVertex_type(oldRemoteData));     
+
+        de.receiveData (pnew,from, &castbuf[sizeof(coor_comm)]);
+            
+        AP_free(msg);      
+      }
+    
+    }      
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;
+
+    UpdatePointerInterface(mesh);
+    UpdatePointerInternal(mesh);
+  }
+
+  // -------------------------------------------------------------------
+  struct tetra_comm {
+    pVertex pdest[4];
+    int tag,dim;
+  };
+
+  // -------------------------------------------------------------------
+  void SendTetra(pMesh mesh,pMeshDataId tagElt, MDB_DataExchanger &de) {
+    int nproc,myrank;
+  
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+    int *sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+    pMeshDataId tagData   = MD_lookupMeshDataId("RemotePoint");
+    pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+    pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+
+    RIter rit = M_regionIter(mesh);
+    pRegion pr;  
+    while ((pr = RIter_next(rit))) {
+      int dest;
+      int migre = EN_getDataInt((pEntity) pr ,tagElt, &dest);
+      if(!migre) continue;
+      dest--;
+      assert(dest!=myrank);
+      pVertex nod[4];
+      nod[0] = R_vertex(pr,0);
+      nod[1] = R_vertex(pr,1);
+      nod[2] = R_vertex(pr,2);
+      nod[3] = R_vertex(pr,3);
+      int sizebuf;
+      void *msg = de.sendData ((pEntity) pr, dest, sizebuf );
+      void *buf = AP_alloc(dest,de.tag(),sizeof(tetra_comm)+sizebuf);
+      char *cast = (char *) buf;  
+      tetra_comm castbuf ; 
+      pGEntity pg = EN_whatIn(pr);
+      castbuf.tag = GEN_tag(pg);
+      castbuf.dim = GEN_type(pg); 
+      for(int i = 0 ; i<4 ; i++) {
+        int tmp;
+        int isChanged = EN_getDataInt((pEntity) nod[i] ,tagChange, &tmp);
+        assert(isChanged);
+        void *temp_ptr2; 
+        int is = EN_getDataPtr((pEntity) nod[i] , tagRemote, &temp_ptr2);
+        assert(is);
+        VectorOfCommonpVertex_type *recup2 = (VectorOfCommonpVertex_type *) temp_ptr2;
+        if((*recup2).size()==1){
+          if((tmp==2) || (tmp==10)){
+            assert((*recup2)[0].first==dest);
+            castbuf.pdest[i] = (*recup2)[0].second;
+          } else {
+            void *temp_ptr; 
+            int is = EN_getDataPtr((pEntity) nod[i] , tagData, &temp_ptr);
+            assert(is);
+            const VectorOfCommonpVertex_type *recup = (const VectorOfCommonpVertex_type *) temp_ptr;
+            unsigned int j;
+            for(j=0 ; j<(*recup).size() ; j++) {
+              if((*recup)[j].first == dest) {
+                castbuf.pdest[i] = (*recup)[j].second;
+                break;
+              }
+            }
+            assert(j<(*recup).size());  
+          }
+        } else {
+          assert((tmp==1) || (tmp==3));
+          if(tmp==3) {
+            unsigned int j;
+            for(j=0 ; j<(*recup2).size() ; j++) {
+              if((*recup2)[j].first == dest) {
+                castbuf.pdest[i] = (*recup2)[j].second;
+                break;
+              }
+            }
+            assert(j<(*recup2).size());
+          } else {
+            void *temp_ptr; 
+            int is = EN_getDataPtr((pEntity) nod[i] , tagData, &temp_ptr);
+            assert(is);
+            const VectorOfCommonpVertex_type *recup = (const VectorOfCommonpVertex_type *) temp_ptr;
+            unsigned int j;
+            for(j=0 ; j<(*recup).size() ; j++) {
+              if((*recup)[j].first == dest) {
+                castbuf.pdest[i] = (*recup)[j].second;
+                break;
+              }
+            }
+            assert(j<(*recup).size());        
+          }
+        }       
+      }  
+      memcpy(&cast[0],&castbuf,sizeof(tetra_comm));             
+      memcpy(&cast[sizeof(tetra_comm)],msg,sizebuf);
+      free(msg);     
+      AP_send(buf);
+      sendcounts[dest]++;    
+    }
+    RIter_delete(rit);
+  
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+
+    /*receive pointers*/
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        char * castbuf = (char *) msg;
+        tetra_comm * regioncom = (tetra_comm * ) &castbuf[0];
+        pVertex  p1 = regioncom->pdest[0];
+        int tmp;
+        int isChanged = EN_getDataInt((pEntity) p1 ,tagChange, &tmp);
+        assert(isChanged);      
+        pVertex  p2 = regioncom->pdest[1];
+        isChanged = EN_getDataInt((pEntity) p2 ,tagChange, &tmp);
+        assert(isChanged);
+        pVertex  p3 = regioncom->pdest[2];
+        isChanged = EN_getDataInt((pEntity) p3 ,tagChange, &tmp);
+        assert(isChanged);
+        pVertex  p4 = regioncom->pdest[3];
+        isChanged = EN_getDataInt((pEntity) p4 ,tagChange, &tmp);
+        assert(isChanged);
+        pFace    pface[4];
+        pGEntity pg;
+        int dim  = regioncom->dim;
+        int tag  = regioncom->tag;
+        if(dim==2) {
+          pg = (pGEntity) GM_faceByTag(mesh->model,tag);
+        } else if(dim==3) {
+          pg = (pGEntity) GM_regionByTag(mesh->model,tag);
+        } else {
+          printf("----pbs faces**** %d\n",dim);
+        }
+        //         pface[0] =  F_exist(2,p1,p2,p3,0);
+        //         assert(pface[0]);
+        //         pface[1] =  F_exist(2,p1,p2,p4,0);
+        //         assert(pface[1]);
+        //         pface[2] =  F_exist(2,p2,p3,p4,0);
+        //         assert(pface[2]);
+        //         pface[3] =  F_exist(2,p1,p3,p4,0);
+        //         assert(pface[3]);
+        
+        pface[0] =  F_exist(p1,p2,p3,0);
+        assert(pface[0]);
+        pface[1] =  F_exist(p1,p2,p4,0);
+        assert(pface[1]);
+        pface[2] =  F_exist(p2,p3,p4,0);
+        assert(pface[2]);
+        pface[3] =  F_exist(p1,p3,p4,0);
+        assert(pface[3]);
+
+        pRegion pr = M_createR(mesh,4,pface,pg);
+        assert(pr);
+        de.receiveData (pr,from, &castbuf[sizeof(tetra_comm)]);
+             
+        AP_free(msg);      
+      }
+    
+    }      
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;
+
+  }
+  // -------------------------------------------------------------------
+  struct face_comm2 {
+    pVertex pdest[3];
+    int tag,dim;
+  };
+
+  // -------------------------------------------------------------------
+  void SendFaces(pMesh mesh,pMeshDataId tagElt, MDB_DataExchanger &de) {
+    int Dim = (mesh->tets.empty()) ? 2 : 3;
+    int nproc,myrank;
+  
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+    int *sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+    pMeshDataId tagData   = MD_lookupMeshDataId("RemotePoint");
+    pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+    pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+
+    if(Dim==2) {
+      FIter fit = M_faceIter(mesh);
+      pFace pface;  
+      while ((pface = FIter_next(fit))) {
+        int dest;
+        int migre = EN_getDataInt((pEntity) pface ,tagElt, &dest);
+        if(!migre) continue;
+        dest--;
+        assert(dest!=myrank);
+        pVertex nod[3];
+        pface->getNodes(nod);
+        int sizebuf;
+        void *msg = de.sendData ((pEntity) pface, dest, sizebuf );
+        void *buf = AP_alloc(dest,de.tag(),sizeof(face_comm2) +sizebuf);
+        char *cast = (char *) buf;  
+       
+        face_comm2 castbuf; 
+        pGEntity pg = EN_whatIn(pface);
+        castbuf.tag = GEN_tag(pg);
+        castbuf.dim = GEN_type(pg); 
+        for(int i = 0 ; i<3 ; i++) {
+          int tmp;
+          int isChanged = EN_getDataInt((pEntity) nod[i] ,tagChange, &tmp);
+          assert(isChanged);
+          void *temp_ptr2; 
+          int is = EN_getDataPtr((pEntity) nod[i] , tagRemote, &temp_ptr2);
+          assert(is);
+          VectorOfCommonpVertex_type *recup2 = 
+            (VectorOfCommonpVertex_type *) temp_ptr2;
+          if((*recup2).size()==1){
+            if((tmp==2) || (tmp==10)){
+              assert((*recup2)[0].first==dest);
+              castbuf.pdest[i] = (*recup2)[0].second;
+            } else {
+              void *temp_ptr; 
+              int is = EN_getDataPtr((pEntity) nod[i] , tagData, &temp_ptr);
+              assert(is);
+              const VectorOfCommonpVertex_type *recup = 
+                (const VectorOfCommonpVertex_type *) temp_ptr;
+              unsigned int j;
+              for(j=0 ; j<(*recup).size() ; j++) {
+                if((*recup)[j].first == dest) {
+                  castbuf.pdest[i] = (*recup)[j].second;
+                  break;
+                }
+              }
+              assert(j<(*recup).size());    
+            }
+          } else {
+            assert((tmp==1) || (tmp==3));
+            if(tmp==3) {
+              unsigned int j;
+              for(j=0 ; j<(*recup2).size() ; j++) {
+                if((*recup2)[j].first == dest) {
+                  castbuf.pdest[i] = (*recup2)[j].second;
+                  break;
+                }
+              }
+              assert(j<(*recup2).size());
+            } else {
+              void *temp_ptr; 
+              int is = EN_getDataPtr((pEntity) nod[i] , tagData, &temp_ptr);
+              assert(is);
+              const VectorOfCommonpVertex_type *recup = 
+                (const VectorOfCommonpVertex_type *) temp_ptr;
+              unsigned int j;
+              for(j=0 ; j<(*recup).size() ; j++) {
+                if((*recup)[j].first == dest) {
+                  castbuf.pdest[i] = (*recup)[j].second;
+                  break;
+                }
+              }
+              assert(j<(*recup).size());          
+            }
+          } 
+        }    
+        memcpy(&cast[0],&castbuf,sizeof(face_comm2));         
+        memcpy(&cast[sizeof(face_comm2)],msg,sizebuf);
+        free(msg);      
+        AP_send(buf);
+        sendcounts[dest]++;    
+      }
+      FIter_delete(fit);
+    } else {//Dim==3
+      if(Dim!=3) throw;
+      FIter fit = M_faceIter(mesh);
+      pFace pface;  
+      while ((pface = FIter_next(fit))) {
+        pPList prlist = F_regions(pface);
+        pRegion pr;
+        void* iter=0;
+        while( (pr =(pRegion) PList_next(prlist,&iter))){
+          int dest;
+          int migre = EN_getDataInt((pEntity) pr ,tagElt, &dest);
+          if(!migre) continue;
+          dest--;
+          assert(dest!=myrank);
+          ((MDB_Triangle*)pface)->del((MDB_Tet*)pr);   
+
+          pVertex nod[3];
+          pface->getNodes(nod);
+          int sizebuf;
+          void *msg = de.sendData ((pEntity) pface, dest, sizebuf );
+          void *buf = AP_alloc(dest,de.tag(),sizeof(face_comm2)+sizebuf);
+          char *cast = (char*) buf;
+          face_comm2 castbuf; 
+          pGEntity pg = EN_whatIn(pface);
+          castbuf.tag = GEN_tag(pg);
+          castbuf.dim = GEN_type(pg); 
+          for(int i = 0 ; i<3 ; i++) {
+            int tmp;
+            int isChanged = EN_getDataInt((pEntity) nod[i] ,tagChange, &tmp);
+            assert(isChanged);
+            void *temp_ptr2; 
+            int is = EN_getDataPtr((pEntity) nod[i] , tagRemote, &temp_ptr2);
+            assert(is);
+            VectorOfCommonpVertex_type *recup2 = 
+              (VectorOfCommonpVertex_type *) temp_ptr2;
+            if((*recup2).size()==1){
+              if((tmp==2) || (tmp==10)){
+                assert((*recup2)[0].first==dest);
+                castbuf.pdest[i] = (*recup2)[0].second;
+              } else {
+                void *temp_ptr; 
+                int is = EN_getDataPtr((pEntity) nod[i] , tagData, &temp_ptr);
+                assert(is);
+                const VectorOfCommonpVertex_type *recup = 
+                  (const VectorOfCommonpVertex_type *) temp_ptr;
+                unsigned int j;
+                for(j=0 ; j<(*recup).size() ; j++) {
+                  if((*recup)[j].first == dest) {
+                    castbuf.pdest[i] = (*recup)[j].second;
+                    break;
+                  }
+                }
+                assert(j<(*recup).size());    
+              }
+            } else {
+              assert((tmp==1) || (tmp==3));
+              if(tmp==3) {
+                unsigned int j;
+                for(j=0 ; j<(*recup2).size() ; j++) {
+                  if((*recup2)[j].first == dest) {
+                    castbuf.pdest[i] = (*recup2)[j].second;
+                    break;
+                  }
+                }
+                assert(j<(*recup2).size());
+              } else {
+                void *temp_ptr; 
+                int is = EN_getDataPtr((pEntity) nod[i] , tagData, &temp_ptr);
+                assert(is);
+                const VectorOfCommonpVertex_type *recup = 
+                  (const VectorOfCommonpVertex_type *) temp_ptr;
+                unsigned int j;
+                for(j=0 ; j<(*recup).size() ; j++) {
+                  if((*recup)[j].first == dest) {
+                    castbuf.pdest[i] = (*recup)[j].second;
+                    break;
+                  }
+                }
+                assert(j<(*recup).size());          
+              }
+            } 
+          }    
+          memcpy(&cast[0],&castbuf,sizeof(face_comm2));           
+          memcpy(&cast[sizeof(face_comm2)],msg,sizebuf);
+          free(msg);  
+          AP_send(buf);
+          sendcounts[dest]++;    
+        }
+      }
+      FIter_delete(fit);  
+    }
+  
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+
+    /*receive pointers*/
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        char * castbuf = (char *) msg;
+
+        face_comm2 * facecom = (face_comm2 * ) &castbuf[0];
+        pVertex  p1 = facecom->pdest[0];
+        int tmp;
+        int isChanged = EN_getDataInt((pEntity) p1 ,tagChange, &tmp);
+        assert(isChanged);      
+        pVertex  p2 = facecom->pdest[1];
+        isChanged = EN_getDataInt((pEntity) p2 ,tagChange, &tmp);
+        assert(isChanged);
+        pVertex  p3 = facecom->pdest[2];
+        isChanged = EN_getDataInt((pEntity) p3 ,tagChange, &tmp);
+        assert(isChanged);
+        pEdge    pe[3];
+        pGEntity pg;
+        int dim  = facecom->dim;
+        int tag  = facecom->tag;
+        if(dim==2) {
+          pg = (pGEntity) GM_faceByTag(mesh->model,tag);
+        } else if(dim==3) {
+          pg = (pGEntity) GM_regionByTag(mesh->model,tag);
+        } else {
+          printf("----pbs faces**** %d\n",dim);
+        }
+        pe[0] =  E_exist(p1,p2);
+        assert(pe[0]);
+        pe[1] =  E_exist(p2,p3);
+        assert(pe[1]);
+        pe[2] =  E_exist(p1,p3);
+        assert(pe[2]);
+       
+        //      pFace pface =F_exist(2,pe[0],pe[1],pe[2],0);
+        //      if(!pface) {
+        pFace  pface = M_createF(mesh,3,pe,pg);
+        assert(pface);
+        de.receiveData (pface,from, &castbuf[sizeof(face_comm2)]);
+       
+        AP_free(msg);      
+      }
+    
+    }      
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;
+
+  }
+
+  // -------------------------------------------------------------------
+  struct edge_comm {
+    pVertex pdest[2];
+    int tag,dim;
+  };
+
+  // -------------------------------------------------------------------
+  void SendEdges(pMesh mesh,pMeshDataId tagElt, MDB_DataExchanger &de) {
+    int Dim = (mesh->tets.empty()) ? 2 : 3;
+    int nproc,myrank;
+  
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+    int *sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+    pMeshDataId tagData   = MD_lookupMeshDataId("RemotePoint");
+    pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+    pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+  
+    if(Dim==2) {
+      EIter eit = M_edgeIter(mesh);
+      pEdge pedge;  
+      while ((pedge = EIter_next(eit))) {
+        pVertex p[2];
+        p[0] = pedge->p1;
+        p[1] = pedge->p2;
+        int tmp1;
+        int isChanged1 = EN_getDataInt((pEntity) p[0] ,tagChange, &tmp1);
+        int tmp2;
+        int isChanged2 = EN_getDataInt((pEntity) p[1] ,tagChange, &tmp2);
+        if(!isChanged1 || !isChanged2) continue;
+        int nbfaces = pedge->numfaces();
+        for(int k = 0 ; k < nbfaces ; k++) {
+          pFace pface = pedge->faces(k);
+          int dest;
+          int migre = EN_getDataInt((pEntity) pface ,tagElt, &dest);
+          if(!migre) continue;
+          dest--;
+          assert(dest!=myrank);
+          pedge->del((MDB_Triangle*)pface);  
+          int sizebuf;
+          void *msg = de.sendData ((pEntity) pedge, dest, sizebuf );
+    
+          void *buf = AP_alloc(dest,de.tag(),sizeof(edge_comm) + sizebuf);
+          char *cast = (char *) buf;  
+          edge_comm castbuf; 
+          pGEntity  pg = EN_whatIn(pedge);
+          castbuf.tag = GEN_tag(pg);
+          castbuf.dim = GEN_type(pg);
+          for(int i = 0 ; i< 2 ; i++) {
+            int tmp;
+            int isChanged = EN_getDataInt((pEntity) p[i] ,tagChange, &tmp);
+            assert(isChanged);
+            void *temp_ptr2; 
+            int is = EN_getDataPtr((pEntity) p[i] , tagRemote, &temp_ptr2);
+            assert(is);
+            VectorOfCommonpVertex_type *recup2 = 
+              (VectorOfCommonpVertex_type *) temp_ptr2;
+            if((*recup2).size()==1){
+              if((tmp==2) || (tmp==10)){
+                assert((*recup2)[0].first==dest);
+                castbuf.pdest[i] = (*recup2)[0].second;
+              } else {
+                void *temp_ptr; 
+                int is = EN_getDataPtr((pEntity) p[i] , tagData, &temp_ptr);
+                assert(is);
+                const VectorOfCommonpVertex_type *recup = 
+                  (const VectorOfCommonpVertex_type *) temp_ptr;
+                unsigned int j;
+                for(j=0 ; j<(*recup).size() ; j++) {
+                  if((*recup)[j].first == dest) {
+                    castbuf.pdest[i] = (*recup)[j].second;
+                    break;
+                  }
+                }
+                assert(j<(*recup).size());  
+              }
+            } else {
+              assert((tmp==1) || (tmp==3));
+              if(tmp==3) {
+                unsigned int j;
+                for(j=0 ; j<(*recup2).size() ; j++) {
+                  if((*recup2)[j].first == dest) {
+                    castbuf.pdest[i] = (*recup2)[j].second;
+                    break;
+                  }
+                }
+                assert(j<(*recup2).size());
+              } else {
+                void *temp_ptr; 
+                int is = EN_getDataPtr((pEntity) p[i] , tagData, &temp_ptr);
+                assert(is);
+                const VectorOfCommonpVertex_type *recup = 
+                  (const VectorOfCommonpVertex_type *) temp_ptr;
+                unsigned int j;
+                for(j=0 ; j<(*recup).size() ; j++) {
+                  if((*recup)[j].first == dest) {
+                    castbuf.pdest[i] = (*recup)[j].second;
+                    break;
+                  }
+                }
+                assert(j<(*recup).size());        
+              }
+            }   
+          }
+          memcpy(&cast[0],&castbuf,sizeof(edge_comm));           
+          memcpy(&cast[sizeof(edge_comm)],msg,sizebuf);
+          free(msg);  
+          AP_send(buf);
+          sendcounts[dest]++;      
+        }
+      } 
+      EIter_delete(eit); 
+    } else {//Dim==3
+      if(Dim!=3) throw;
+      EIter eit = M_edgeIter(mesh);
+      pEdge pedge;  
+      while ((pedge = EIter_next(eit))) {
+        pVertex p[2];
+        p[0] = pedge->p1;
+        p[1] = pedge->p2;
+        int tmp1;
+        int isChanged1 = EN_getDataInt((pEntity) p[0] ,tagChange, &tmp1);
+        int tmp2;
+        int isChanged2 = EN_getDataInt((pEntity) p[1] ,tagChange, &tmp2);
+        if(!isChanged1 || !isChanged2) continue;
+        pPList prlist = E_regions(pedge);
+        pRegion pr;
+        void* iter=0;
+        while( (pr =(pRegion) PList_next(prlist,&iter))){
+          int dest;
+          int migre = EN_getDataInt((pEntity) pr ,tagElt, &dest);
+          if(!migre) continue;
+          dest--;
+          assert(dest!=myrank);  
+          int sizebuf;
+          void *msg = de.sendData ((pEntity) pedge, dest, sizebuf );
+      
+          void *buf = AP_alloc(dest,de.tag(),sizeof(edge_comm) +sizebuf);
+          char *cast = (char *) buf;  
+ 
+          edge_comm castbuf; 
+          pGEntity  pg = EN_whatIn(pedge);
+          castbuf.tag = GEN_tag(pg);
+          castbuf.dim = GEN_type(pg);       
+        
+          for(int i = 0 ; i< 2 ; i++) {
+            int tmp;
+            int isChanged = EN_getDataInt((pEntity) p[i] ,tagChange, &tmp);
+            assert(isChanged);
+            void *temp_ptr2; 
+            int is = EN_getDataPtr((pEntity) p[i] , tagRemote, &temp_ptr2);
+            assert(is);
+            VectorOfCommonpVertex_type *recup2 = 
+              (VectorOfCommonpVertex_type *) temp_ptr2;
+            if((*recup2).size()==1){
+              if((tmp==2) || (tmp==10)){
+                assert((*recup2)[0].first==dest);
+                castbuf.pdest[i] = (*recup2)[0].second;
+              } else {
+                void *temp_ptr; 
+                int is = EN_getDataPtr((pEntity) p[i] , tagData, &temp_ptr);
+                assert(is);
+                const VectorOfCommonpVertex_type *recup = 
+                  (const VectorOfCommonpVertex_type *) temp_ptr;
+                unsigned int j;
+                for(j=0 ; j<(*recup).size() ; j++) {
+                  if((*recup)[j].first == dest) {
+                    castbuf.pdest[i] = (*recup)[j].second;
+                    break;
+                  }
+                }
+                assert(j<(*recup).size());  
+              }
+            } else {
+              assert((tmp==1) || (tmp==3));
+              if(tmp==3) {
+                unsigned int j;
+                for(j=0 ; j<(*recup2).size() ; j++) {
+                  if((*recup2)[j].first == dest) {
+                    castbuf.pdest[i] = (*recup2)[j].second;
+                    break;
+                  }
+                }
+                assert(j<(*recup2).size());
+              } else {
+                void *temp_ptr; 
+                int is = EN_getDataPtr((pEntity) p[i] , tagData, &temp_ptr);
+                assert(is);
+                const VectorOfCommonpVertex_type *recup = 
+                  (const VectorOfCommonpVertex_type *) temp_ptr;
+                unsigned int j;
+                for(j=0 ; j<(*recup).size() ; j++) {
+                  if((*recup)[j].first == dest) {
+                    castbuf.pdest[i] = (*recup)[j].second;
+                    break;
+                  }
+                }
+                assert(j<(*recup).size());        
+              }
+            }   
+          } 
+          memcpy(&cast[0],&castbuf,sizeof(edge_comm));           
+          memcpy(&cast[sizeof(edge_comm)],msg,sizebuf);
+          free(msg);  
+          AP_send(buf);
+          sendcounts[dest]++;  
+        } 
+      }   
+      EIter_delete(eit);
+    }
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+
+    /*receive pointers*/
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        char * castbuf = (char *) msg;
+        edge_comm * edgecom = (edge_comm * ) &castbuf[0];
+        pVertex  p1 = edgecom->pdest[0];
+        int tmp;
+        int isChanged = EN_getDataInt((pEntity) p1 ,tagChange, &tmp);
+        assert(isChanged);      
+        pVertex  p2 = edgecom->pdest[1];
+        isChanged = EN_getDataInt((pEntity) p2 ,tagChange, &tmp);
+        assert(isChanged);
+        pGEntity pg;
+        int dim  = edgecom->dim;
+        int tag  = edgecom->tag;
+        if(dim==1) {
+          pg = (pGEntity) GM_edgeByTag(mesh->model,tag);
+        } else if(dim==2) {
+          pg = (pGEntity) GM_faceByTag(mesh->model,tag);
+        } else if(dim==3) {
+          pg = (pGEntity) GM_regionByTag(mesh->model,tag);
+        } else {
+          printf("----pbs**** %d\n",dim);
+        }
+        pEdge     e = E_exist(p1,p2);
+        if (!e)   e = M_createE(mesh,p1,p2,pg);
+        de.receiveData (e,from, &castbuf[sizeof(edge_comm)]);
+
+        AP_free(msg);      
+      }
+    
+    }      
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;
+
+
+  }
+
+  // -------------------------------------------------------------------
+  void SendElt(pMesh mesh,pMeshDataId tagElt, MDB_DataExchanger &de) {
+
+    SendEdges(mesh,tagElt,de);
+  
+    SendFaces(mesh,tagElt,de);
+  
+    int dim = (mesh->tets.empty()) ? 2 : 3;
+    if(dim==3) SendTetra(mesh,tagElt,de);
+  }
+
+  // -------------------------------------------------------------------
+  void DeleteEntities(pMesh mesh,pMeshDataId tagElt) {
+    int nproc,myrank;
+    int Dim = (mesh->tets.empty()) ? 2 : 3;
+  
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);   
+
+    pMeshDataId tagData   = MD_lookupMeshDataId("RemotePoint");
+    pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+    pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+    pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+  
+    if(Dim==2) {
+      FIter fit = M_faceIter(mesh);
+      pFace pface;  
+      while ((pface = FIter_next(fit))) {
+        int dest;
+        int migre = EN_getDataInt((pEntity) pface ,tagElt, &dest);
+        if(!migre) continue;
+        dest--;
+        assert(dest!=myrank);
+        EN_deleteData((pEntity)pface, tagElt);
+        M_removeFace(mesh,pface);
+      }
+      FIter_delete(fit);
+      MD_deleteMeshDataId(tagElt);
+    } else {
+      RIter rit = M_regionIter(mesh);
+      pRegion pr;  
+      while ((pr = RIter_next(rit))) {
+        int dest;
+        int migre = EN_getDataInt((pEntity) pr ,tagElt, &dest);
+        if(!migre) continue;
+        dest--;
+        assert(dest!=myrank);
+        EN_deleteData((pEntity)pr, tagElt);
+        M_removeRegion(mesh,pr);
+      }
+      RIter_delete(rit);    
+      MD_deleteMeshDataId(tagElt);  
+    
+      FIter fit = M_faceIter(mesh);
+      pFace pface;  
+      while ((pface = FIter_next(fit))) {
+        int num = F_numRegions(pface);
+        if(!num) M_removeFace(mesh,pface);
+      }
+      FIter_delete(fit);
+    }
+  
+    EIter eit = M_edgeIter(mesh);
+    pEdge ped;  
+    while ((ped = EIter_next(eit))) {
+      int num = E_numFaces(ped);
+      if(!num)  M_removeEdge(mesh,ped);
+    }
+    EIter_delete(eit);
+
+    VIter vit = M_vertexIter(mesh);
+    pVertex pv;  
+    while ((pv = VIter_next(vit))) {
+      int tmp;
+      int isChanged = EN_getDataInt((pEntity) pv ,tagChange, &tmp);
+      if(!isChanged) continue;
+      void *temp_ptr2; 
+      int is2 = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr2);
+#ifdef DEBUG
+      if(tmp==10)assert(!is2);
+      if(tmp==1) assert(is2);
+#endif
+      void *temp_ptr; 
+      int is = EN_getDataPtr((pEntity) pv , tagRemote, &temp_ptr);
+    
+      
+      int num = V_numEdges(pv);
+      if(tmp==3 ) assert(!num); 
+      if(tmp==11) {
+        assert(num);
+        assert(is2);
+        EN_deleteData((pEntity)pv, tagData);
+      }  
+      if(tmp==2)  assert(!num); 
+      if(tmp==1) assert(num);
+      if(!num) assert(!V_numFaces(pv));
+    
+      if(is) EN_deleteData((pEntity)pv,tagRemote);
+      int isMaster = EN_getDataInt((pEntity) pv ,tagMaster, &tmp);
+
+      if(isMaster)  EN_deleteData((pEntity)pv, tagMaster);
+      EN_deleteData((pEntity)pv, tagChange);
+
+      if(!num) M_removeVertex(mesh,pv);
+    }
+    VIter_delete(vit);
+    MD_deleteMeshDataId(tagChange);
+    MD_deleteMeshDataId(tagRemote);  
+    MD_deleteMeshDataId(tagMaster);  
+  }
+  // -------------------------------------------------------------------
+  void DeleteEntitiesAndData(pMesh mesh, pMeshDataId tagElt, 
+                             MDB_DataExchanger &de )
+  {
+    int nproc,myrank;
+  
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);   
+    pMeshDataId tagRemote = MD_lookupMeshDataId("RemoteStructure");
+    pMeshDataId tagMaster = MD_lookupMeshDataId("isMaster");
+    pMeshDataId tagChange = MD_lookupMeshDataId("IsChange");
+    int Dim = (mesh->tets.empty()) ? 2 : 3; 
+    if(Dim==2) {
+      FIter fit = M_faceIter(mesh);
+      pFace pface;  
+      while ((pface = FIter_next(fit))) {
+        EN_deleteData((pEntity)pface, tagRemote);
+        EN_deleteData((pEntity)pface, tagMaster);
+        EN_deleteData((pEntity)pface, tagChange);
+        int dest;
+        int migre = EN_getDataInt((pEntity) pface ,tagElt, &dest);
+        if(!migre) continue;
+        dest--;
+        assert(dest!=myrank);
+        EN_deleteData((pEntity)pface, tagElt);
+        de.deleteExternalData( (pEntity) pface );
+        M_removeFace(mesh,pface);
+      }
+      FIter_delete(fit);
+      MD_deleteMeshDataId(tagElt);
+    } 
+    else {
+      RIter rit = M_regionIter(mesh);
+      pRegion pr;  
+      while ((pr = RIter_next(rit))) {
+        EN_deleteData((pEntity)pr, tagRemote);
+        EN_deleteData((pEntity)pr, tagMaster);
+        EN_deleteData((pEntity)pr, tagChange);
+        int dest;
+        int migre = EN_getDataInt((pEntity) pr ,tagElt, &dest);
+        if(!migre) continue;
+        dest--;
+        assert(dest!=myrank);
+        EN_deleteData((pEntity)pr, tagElt);
+        de.deleteExternalData( (pEntity) pr );
+        M_removeRegion(mesh,pr);
+      }
+      RIter_delete(rit);    
+      MD_deleteMeshDataId(tagElt);  
+    
+      FIter fit = M_faceIter(mesh);
+      pFace pface;  
+      while ((pface = FIter_next(fit))) {
+      
+        EN_deleteData((pEntity)pface, tagRemote);
+        EN_deleteData((pEntity)pface, tagMaster);
+        EN_deleteData((pEntity)pface, tagChange);
+        int num = F_numRegions(pface);
+        if(!num){
+          de.deleteExternalData( (pEntity) pface );
+          M_removeFace(mesh,pface);
+        }
+      }
+      FIter_delete(fit);
+    }
+  
+    EIter eit = M_edgeIter(mesh);
+    pEdge ped;  
+    while ((ped = EIter_next(eit))) {
+      EN_deleteData((pEntity)ped, tagRemote);
+      EN_deleteData((pEntity)ped, tagMaster);
+      EN_deleteData((pEntity)ped, tagChange);
+      int num = E_numFaces(ped);
+      if(!num){
+        de.deleteExternalData( (pEntity) ped );      
+        M_removeEdge(mesh,ped);
+      }
+    }
+    EIter_delete(eit);
+  
+    VIter vit = M_vertexIter(mesh);
+    pVertex pv;  
+    while ((pv = VIter_next(vit))) {
+      EN_deleteData((pEntity)pv, tagRemote);
+      EN_deleteData((pEntity)pv, tagMaster);
+      EN_deleteData((pEntity)pv, tagChange);
+      int num = V_numEdges(pv);
+      if(!num){
+        de.deleteExternalData( (pEntity) pv );   
+        M_removeVertex(mesh,pv);   
+      }
+    }
+    VIter_delete(vit);
+    MD_deleteMeshDataId(tagChange);
+    MD_deleteMeshDataId(tagRemote);  
+    MD_deleteMeshDataId(tagMaster);  
+  
+  }
+  // -------------------------------------------------------------------
+  void loadBalancing2(pMesh mesh, pMeshDataId tagElt, MDB_DataExchanger &de)
+  {
+    // 0 the destination of local subentitiees 
+    MarkEltSubEntities(mesh, tagElt);
+    // 1 entities Migration
+    pMeshDataId tagDest = MD_lookupMeshDataId("tagDestinations");
+    MigrateEntitiesAndData(mesh, tagDest, de);
+    // 2 delete entities
+    DeleteEntitiesAndData( mesh,tagElt, de );
+
+ 
+    pMeshDataId tagVertex = MD_lookupMeshDataId("RemotePoint");
+    MD_deleteMeshDataId(tagVertex);
+    MD_deleteMeshDataId(tagDest);
+    mesh->initializeIdData();
+  }
+  // -------------------------------------------------------------------
+  void loadBalancing(pMesh mesh, pMeshDataId tagElt, MDB_DataExchanger &de)
+  {
+#ifdef DEBUG
+    pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+    checkRemotePointer(mesh,tagData);
+    puts("check first ok");
+#endif
+    // 1) Mark local and distant vertices with their new proc(s)
+    MarkEltVertex(mesh,tagElt);
+
+#ifdef DEBUG  
+    checkRemotePointer(mesh,tagData);
+    puts("check second ok");
+#endif
+  
+    // 2) update and send new interfaces points
+    UpdateInterfaces(mesh,de);
+
+#ifdef DEBUG
+    checkRemotePointer2(mesh,tagData);
+    puts("check fifth ok");
+#endif
+  
+    // 3) send other points and update RemotePointer
+    SendVertex(mesh,de);
+  
+    // 4) send elt
+    SendElt(mesh,tagElt,de);
+  
+    //  // 5) delete entities
+    //  DeleteEntities(mesh,tagElt);
+    DeleteEntitiesAndData( mesh,tagElt, de );
+
+    //  // 6) classification 
+    mesh->classify_unclassified_entities();
+
+ 
+    pMeshDataId tagVertex = MD_lookupMeshDataId("RemotePoint");
+    MD_deleteMeshDataId(tagVertex);
+#ifdef PARALLEL
+
+    // ----------------------------------------------
+    // ------ Tagging inter-partition nodes
+    // ----------------------------------------------
+  
+    pMeshDataId tag = MD_lookupMeshDataId("RemotePoint");
+  
+    V_createInfoInterface(mesh,tag);
+    E_createInfoInterface(mesh,tag);
+    F_createInfoInterface(mesh,tag);
+    mesh->initializeIdData();
+  
+#endif
+
+#ifdef DEBUG  
+    checkRemotePointer(mesh,tagData);
+    puts("last check ok");
+#endif  
+
+  }
+  // -------------------------------------------------------------------
+
+} // End of namespace MAd
+
+#endif
diff --git a/Mesh/MeshDataBaseLoadBalancing.h b/Mesh/MeshDataBaseLoadBalancing.h
new file mode 100644
index 0000000..1c62230
--- /dev/null
+++ b/Mesh/MeshDataBaseLoadBalancing.h
@@ -0,0 +1,40 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef H_MESHDATABASELOADBALANCE
+#define H_MESHDATABASELOADBALANCE
+
+#ifdef PARALLEL
+
+namespace MAd {
+
+#ifdef DEBUG
+  void checkRemotePointer(pMesh mesh, pMeshDataId tagData );
+  void checkRemotePointer2(pMesh mesh, pMeshDataId tagData );
+  void checkRemotePointerChange(pMesh mesh, pMeshDataId tagData,pMeshDataId tagNew, pMeshDataId tagChange );
+  void checkNew(pMesh mesh, pMeshDataId tagData,pMeshDataId tagChange);
+#endif
+  void MarkedEltVertex(pMesh mesh,pMeshDataId tagElt);
+  void CommOldInterfaces(pMesh mesh);
+
+  void UpdateInterfaces(pMesh mesh, MDB_DataExchanger &de);
+  void SendVertex(pMesh mesh, MDB_DataExchanger &de);
+  void SendElt(pMesh mesh,pMeshDataId tagElt, MDB_DataExchanger &de);
+  void DeleteEntitiesAndData(pMesh mesh,pMeshDataId tagElt, MDB_DataExchanger &de );
+  void MarkEltSubEntities(pMesh mesh, pMeshDataId tagElt);
+  void MigrateEntitiesAndData(pMesh mesh, pMeshDataId tagDest, MDB_DataExchanger &de);
+
+}
+
+#endif
+#endif
diff --git a/Mesh/MeshDataBaseMessage.cc b/Mesh/MeshDataBaseMessage.cc
new file mode 100644
index 0000000..2fce545
--- /dev/null
+++ b/Mesh/MeshDataBaseMessage.cc
@@ -0,0 +1,150 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include <signal.h>
+#ifndef _WIN_
+#include <sys/time.h>
+#include <sys/resource.h>
+#else
+#include <windows.h>
+#include <psapi.h>
+#endif
+#include <stdio.h>
+#include <stdarg.h>
+#include "MeshDataBaseMessage.h"
+using std::string;
+
+namespace MAd {
+
+  // Handle signals. We should not use Msg functions in these...
+
+  void Signal(int sig_num)
+  {
+    switch (sig_num) {
+    case SIGSEGV:
+      Msg(MDB_FATAL, "Segmentation violation (invalid memory reference)");
+      break;
+    case SIGFPE:
+      Msg(MDB_FATAL, "Floating point exception (division by zero?)");
+      break;
+    case SIGINT:
+      Msg(MDB_FATAL, "Interrupt (generated from terminal special char)");
+      break;
+    default:
+      Msg(MDB_FATAL, "Unknown signal");
+      break;
+    }
+  }
+
+  // General purpose message routine
+
+  void Msg(int level, string fmt, ...)
+  {
+    va_list args;
+    va_start(args, fmt);
+
+    Msg_char(level, fmt.c_str(), args);
+
+    va_end(args);
+  }
+
+  void Msg_char(int level, const char *fmt, ...)
+  {
+    va_list args;
+    int abort = 0;
+
+    va_start(args, fmt);
+
+    switch (level) {
+
+    case MDB_PROGRESS:
+    case MDB_STATUS1N:
+    case MDB_STATUS2N:
+    case MDB_STATUS3N:
+      break;
+
+    case MDB_DIRECT:
+      vfprintf(stdout, fmt, args);
+      fprintf(stdout, "\n");
+      break;
+
+    case MDB_FATAL:
+    case MDB_FATAL3: abort = 1;
+    case MDB_FATAL1:
+    case MDB_FATAL2:
+      fprintf(stderr, MDB_FATAL_STR);
+      vfprintf(stderr, fmt, args);
+      fprintf(stderr, "\n");
+      break;
+
+    case MDB_GERROR:
+    case MDB_GERROR1:
+    case MDB_GERROR2:
+    case MDB_GERROR3:
+      fprintf(stderr, MDB_ERROR_STR);
+      vfprintf(stderr, fmt, args);
+      fprintf(stderr, "\n");
+      break;
+
+    case MDB_WARNING:
+    case MDB_WARNING1:
+    case MDB_WARNING2:
+    case MDB_WARNING3:
+      fprintf(stderr, MDB_WARNING_STR);
+      vfprintf(stderr, fmt, args);
+      fprintf(stderr, "\n");
+      break;
+
+      //   case DEBUG:
+      //   case DEBUG1:
+      //   case DEBUG2:
+      //   case DEBUG3:
+      //     fprintf(stderr, DEBUG_STR);
+      //     vfprintf(stderr, fmt, args);
+      //     fprintf(stderr, "\n");
+      //     break;
+    
+    default:
+      fprintf(stderr, MDB_INFO_STR);
+      vfprintf(stderr, fmt, args);
+      fprintf(stderr, "\n");
+      break;
+    }
+
+    va_end(args);
+
+    if(abort)
+      throw;
+  }
+
+  // CPU time computation
+
+  void GetResources(long *s, long *us, long *mem)
+  {
+#ifndef _WIN_
+    static struct rusage r;
+
+    getrusage(RUSAGE_SELF, &r);
+    *s = (long)r.ru_utime.tv_sec;
+    *us = (long)r.ru_utime.tv_usec;
+    *mem = (long)r.ru_maxrss;
+#else
+	PROCESS_MEMORY_COUNTERS counters;
+    if (GetProcessMemoryInfo (GetCurrentProcess(), &counters, sizeof (counters)))
+        *mem=counters.PagefileUsage;
+	SYSTEMTIME systime; 
+	GetSystemTime(&systime); 
+	*s=systime.wSecond;
+	*us=systime.wMilliseconds;
+#endif
+  }
+}
diff --git a/Mesh/MeshDataBaseMessage.h b/Mesh/MeshDataBaseMessage.h
new file mode 100644
index 0000000..d27ce1f
--- /dev/null
+++ b/Mesh/MeshDataBaseMessage.h
@@ -0,0 +1,74 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _MESSAGE_H_
+#define _MESSAGE_H_
+
+#include <stdarg.h>
+#include <string>
+
+#define MDB_FATAL          1  // Fatal error (causes Gmsh to exit)
+#define MDB_FATAL1         2  // First part of a multiline FATAL message 
+#define MDB_FATAL2         3  // Middle part of a multiline FATAL message
+#define MDB_FATAL3         4  // Last part of a multiline FATAL message  
+
+#define MDB_GERROR         5  // Error (but Gmsh can live with it)
+#define MDB_GERROR1        6  // First part of a multiline ERROR message 
+#define MDB_GERROR2        7  // Middle part of a multiline ERROR message
+#define MDB_GERROR3        8  // Last part of a multiline ERROR message  
+
+#define MDB_WARNING        9  // Warning
+#define MDB_WARNING1      10  // First part of a multiline WARNING message 
+#define MDB_WARNING2      11  // Middle part of a multiline WARNING message
+#define MDB_WARNING3      12  // Last part of a multiline WARNING message  
+
+#define MDB_INFO          13  // Long informations
+#define MDB_INFO1         14  // First part of a multiline INFO message 
+#define MDB_INFO2         15  // Middle part of a multiline INFO message
+#define MDB_INFO3         16  // Last part of a multiline INFO message  
+
+#define MDB_STATUS1       21  // Small information in status bar (left)
+#define MDB_STATUS2       22  // Small interaction in status bar (middle)
+#define MDB_STATUS3       23  // Small interaction in status bar (right)
+
+#define MDB_STATUS1N      24  // Same as STATUS1, but not going into the log file
+#define MDB_STATUS2N      25  // Same as STATUS2, but not going into the log file
+#define MDB_STATUS3N      26  // Same as STATUS3, but not going into the log file
+
+#define MDB_ONSCREEN      27  // Persistent on-screen message
+
+#define MDB_DIRECT        30  // Direct message (no special formatting)
+#define MDB_SOLVER        31  // Solver message
+#define MDB_SOLVERR       32  // Solver errors and warnings
+
+#define MDB_PROGRESS      40  // Progress indicator
+
+#define MDB_WHITE_STR          "        : "
+#define MDB_FATAL_STR          "Fatal   : "
+#define MDB_ERROR_STR          "Error   : "
+#define MDB_WARNING_STR        "Warning : "
+#define MDB_INFO_STR           "Info    : "
+/* #define MDB_DEBUG_STR          "Debug   : " */
+#define MDB_STATUS_STR         "Info    : "
+
+namespace MAd {
+
+  void   Signal(int signum);
+  void   Msg(int level, std::string fmt, ...);
+  void   Msg_char(int level, const char * fmt, ...);
+  double Cpu(void);
+  double GetValue(char *text, double defaultval);
+
+}
+
+#endif
diff --git a/Mesh/MeshDataBaseMigration.cc b/Mesh/MeshDataBaseMigration.cc
new file mode 100644
index 0000000..62b9254
--- /dev/null
+++ b/Mesh/MeshDataBaseMigration.cc
@@ -0,0 +1,626 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Josue Barboza
+// -------------------------------------------------------------------
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+#include "MeshDataBaseParallelInterface.h"
+#include "MeshDataBaseLoadBalancing.h"
+#include "assert.h"
+#include <iostream>
+
+namespace MAd {
+
+  typedef std::set< int >                     SetOfDestination_type;
+  // ------------------------------------------------------------------- 
+  // -------------------------------------------------------------------
+  struct coor_comm2
+  {
+    double   X,Y,Z;
+    int tag,dim;
+    int id;
+  }; 
+
+  // -------------------------------------------------------------------
+  void MarkVertex( pVertex pv,  pMeshDataId tagD ,int d_proc )
+  {
+    void *temp_ptr;
+    SetOfDestination_type *recup = NULL;
+    int is = EN_getDataPtr((pEntity) pv, tagD, &temp_ptr);    
+    if( !is ){
+      recup = new SetOfDestination_type;
+      EN_attachDataPtr((pEntity) pv , tagD, recup);
+    }else
+      { 
+        recup = reinterpret_cast< SetOfDestination_type *> (temp_ptr);     
+      }
+    recup->insert( d_proc );
+  }
+  // -------------------------------------------------------------------
+  void MarkEdge( pEdge pe,  pMeshDataId tagD ,int d_proc )
+  {
+    void *temp_ptr;
+    SetOfDestination_type *recup = NULL;
+    int is = EN_getDataPtr((pEntity) pe, tagD, &temp_ptr);    
+    if( !is ){
+      recup = new SetOfDestination_type;
+      EN_attachDataPtr((pEntity) pe, tagD, recup);
+    }else { 
+      recup = reinterpret_cast<SetOfDestination_type *> (temp_ptr);     
+    }
+    recup->insert(d_proc);
+    pVertex  nod[2];
+    nod[0] = E_vertex(pe,0);
+    nod[1] = E_vertex(pe,1);
+    MarkVertex( nod[0], tagD, d_proc);
+    MarkVertex( nod[1], tagD, d_proc);
+  }
+  // -------------------------------------------------------------------
+  void MarkFace( pFace pf,  pMeshDataId tagD ,int d_proc )
+  {
+    void *temp_ptr;
+    SetOfDestination_type *recup = NULL;
+    int is = EN_getDataPtr((pEntity) pf, tagD, &temp_ptr);    
+    if( !is ){
+      recup = new SetOfDestination_type;
+      EN_attachDataPtr((pEntity) pf, tagD, recup);
+    }else { 
+      recup = reinterpret_cast<SetOfDestination_type *> (temp_ptr);     
+    }
+    recup->insert(d_proc);
+    for( int i = 0; i<(pf->getNbEdges()); i++) {
+      MarkEdge( F_edge( pf,i ), tagD, d_proc );
+    }
+  }
+  // -------------------------------------------------------------------
+  void MarkRegion( pRegion pr,  pMeshDataId tagD ,int d_proc )
+  {
+    void *temp_ptr;
+    SetOfDestination_type *recup = NULL;
+    int is = EN_getDataPtr((pEntity) pr, tagD, &temp_ptr);    
+    if( !is ){
+      recup = new SetOfDestination_type;
+      EN_attachDataPtr((pEntity) pr, tagD, recup);
+    }else { 
+      recup = reinterpret_cast<SetOfDestination_type *> (temp_ptr);     
+    }
+    recup->insert(d_proc);
+    for( int i = 0; i<(pr->getNbFace()); i++) {
+      MarkFace( R_face( pr,i ), tagD, d_proc );
+    }
+  }
+
+  // -------------------------------------------------------------------
+  void MarkEltSubEntities( pMesh mesh, pMeshDataId tagElt )
+  {
+    pMeshDataId tagDest = MD_lookupMeshDataId("tagDestinations");
+    MD_deleteMeshDataId(tagDest);
+  
+    int dim = (mesh->tets.empty()) ? 2 : 3;
+    if( dim == 2 ){
+      FIter fit = M_faceIter(mesh);
+      pFace pface;  
+      while ((pface = FIter_next(fit))) {
+        int dest; 
+        int migre = EN_getDataInt((pEntity) pface, tagElt, &dest);
+        if(!migre) continue;    
+        MarkFace( pface, tagDest ,dest-1 );      
+      }
+      FIter_delete(fit);    
+    }
+    else {
+      if(dim!=3) throw;
+      RIter rit = M_regionIter(mesh);
+      pRegion pr;  
+      while ((pr = RIter_next(rit))) {
+        int dest; 
+        int migre = EN_getDataInt((pEntity) pr, tagElt, &dest);
+        if(!migre) continue;  
+        MarkRegion( pr, tagDest ,dest-1 );         
+      }    
+      RIter_delete(rit);
+    }
+  }
+  // -------------------------------------------------------------------
+  void * VertexAndDataPackaging( pVertex pv, int d, MDB_DataExchanger &de)
+  {
+    int sizebuf;
+    void *msg = de.sendData ((pEntity) pv, d, sizebuf );
+    void *buf = AP_alloc(d,de.tag(),sizeof(coor_comm2)+sizebuf);
+
+    char *cast = reinterpret_cast< char *> (buf);  
+    coor_comm2 castbuf; 
+    castbuf.X     = P_x(pv);
+    castbuf.Y     = P_y(pv);
+    castbuf.Z     = P_z(pv);
+    pGEntity  pg  = EN_whatIn(pv);
+    castbuf.tag   = GEN_tag(pg);
+    castbuf.dim   = GEN_type(pg);
+    castbuf.id = EN_id( pv );
+    memcpy(&cast[0],&castbuf,sizeof(coor_comm2));           
+    memcpy(&cast[sizeof(coor_comm2)],msg,sizebuf);          
+    free(msg);
+    return buf;
+  }
+  // -------------------------------------------------------------------
+  void VertexAndDataUnpackaging(  pMesh mesh, void *msg, int from, 
+                                  MDB_DataExchanger &de)
+  {
+    char * castbuf = reinterpret_cast< char *> ( msg );
+    coor_comm2 * coorcom = reinterpret_cast< coor_comm2 *> (castbuf);
+    pGEntity pg = NULL;
+    int dim  = coorcom->dim;
+    int tag  = coorcom->tag;
+    if(dim == 0) {
+      pg = (pGEntity) GM_vertexByTag(mesh->model,tag);
+    } else if(dim==1) {
+      pg = (pGEntity) GM_edgeByTag(mesh->model,tag);     
+    } else if(dim==2) {
+      pg = (pGEntity) GM_faceByTag(mesh->model,tag);
+    } else if(dim==3) {
+      pg = (pGEntity) GM_regionByTag(mesh->model,tag);
+    } 
+    pVertex pnew =  mesh->find_point(coorcom->id);
+    if( !pnew ){
+      
+      //       double  X = coorcom->X;
+      //       double  Y = coorcom->Y;
+      //       double  Z = coorcom->Z;
+      //       pnew = M_createVP(mesh,X,Y,Z,coorcom->id,pg);
+      
+      double  XYZ[3] = {coorcom->X,coorcom->Y,coorcom->Z};
+      pnew = M_createV2(mesh,XYZ,coorcom->id,pg);
+    }
+    de.receiveData (pnew,from, &castbuf[sizeof(coor_comm2)]);
+  
+  }
+  // -------------------------------------------------------------------
+  void MigrateVerticesAndData( pMesh mesh, pMeshDataId tagDest, 
+                               MDB_DataExchanger &de)
+  {
+    int nproc,myrank;
+  
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+    int *sendcounts = new int[nproc];
+    for( int i=0; i<nproc; i++){
+      sendcounts[i]= 0;
+    }
+    VIter vit = M_vertexIter(mesh);
+    pVertex pv;  
+    while ((pv = VIter_next(vit))) {
+      void *temp_ptr;
+      int migre = EN_getDataPtr((pEntity) pv, tagDest, &temp_ptr);
+      if(!migre) continue;
+      const SetOfDestination_type *recup =
+        reinterpret_cast< const SetOfDestination_type* > (temp_ptr);
+      assert( (recup->size())>0 );
+      SetOfDestination_type::const_iterator itd = recup->begin();
+      for(; itd!=recup->end(); itd ++) {
+        int dest = *itd;
+        assert(dest!=myrank);
+        void *buf = VertexAndDataPackaging( pv, dest, de );    
+        AP_send(buf);
+        sendcounts[dest]++; 
+      } 
+    }    
+    VIter_delete(vit);
+  
+
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+  
+    /*receive Vertices and data*/
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        VertexAndDataUnpackaging( mesh, msg, from, de);
+        AP_free(msg);    
+      }
+    }
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;  
+  }
+  // -------------------------------------------------------------------
+  void * EdgeAndDataPackaging( pEdge pe, int d, MDB_DataExchanger &de)
+  {
+    int sizebuf;
+    void *msg = de.sendData ((pEntity) pe, d, sizebuf );
+    int castbuf[4];
+    int sizeOfcastbuf = sizeof(int) *4;
+    void *buf = AP_alloc(d,de.tag(), sizeOfcastbuf +sizebuf );
+    char *cast = reinterpret_cast< char *> (buf);  
+    pGEntity pg = EN_whatIn( pe );
+    castbuf[0] = GEN_tag( pg );
+    castbuf[1] = GEN_type( pg ); 
+    castbuf[2] = EN_id( E_vertex( pe, 0 ) );
+    castbuf[3] = EN_id( E_vertex( pe, 1 ) ); 
+    memcpy( &cast[0], castbuf, sizeOfcastbuf );             
+    memcpy( &cast[sizeOfcastbuf],msg,sizebuf);
+    free(msg);     
+    return buf;      
+  }
+  // -------------------------------------------------------------------
+  void EdgeAndDataUnpackaging(  pMesh mesh, void *msg, int from, 
+                                MDB_DataExchanger &de)
+  {
+    char* castbuf = reinterpret_cast<char*> (msg);
+    int * Edge_comm = reinterpret_cast<int*> (castbuf);
+    int tag = *(Edge_comm++);
+    int dim = *(Edge_comm++);
+    pGEntity pg = NULL;
+    if(dim==2) {
+      pg = (pGEntity) GM_faceByTag(mesh->model,tag);
+    } else if(dim==3) {
+      pg = (pGEntity) GM_regionByTag(mesh->model,tag);
+    }
+  
+    pVertex pv[2];
+    pv[0]= mesh->find_point( *(Edge_comm++) );
+    pv[1]= mesh->find_point( *(Edge_comm++) );
+
+
+    pEdge pe =  E_exist(pv[0],pv[1]);
+    if( !pe ) {
+      pe = M_createE(mesh,pv[0],pv[1],pg);
+    }
+    assert(pe);
+    de.receiveData (pe,from, &castbuf[sizeof(int)*4]);
+  }
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  void MigrateEdgesAndData(pMesh mesh, pMeshDataId tagDest,
+                           MDB_DataExchanger &de)
+  {
+    int nproc,myrank;
+  
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+    int *sendcounts = new int[nproc];
+    for( int i=0; i<nproc; i++){
+      sendcounts[i]= 0;
+    }
+    EIter eit = M_edgeIter(mesh);
+    pEdge pe;  
+    while ((pe = EIter_next(eit))) {
+      void *temp_ptr;
+      int migre = EN_getDataPtr((pEntity) pe, tagDest, &temp_ptr);
+      if(!migre) continue;
+      const SetOfDestination_type *recup =
+        reinterpret_cast< const SetOfDestination_type* > (temp_ptr);
+      assert( (recup->size())>0 );
+      SetOfDestination_type::const_iterator itd = recup->begin();
+      for(; itd!=recup->end(); itd ++) {
+        int dest = *itd;
+        assert(dest!=myrank);
+        void *buf = EdgeAndDataPackaging( pe, dest, de );    
+        AP_send(buf);
+        sendcounts[dest]++; 
+      } 
+    }    
+    EIter_delete(eit);
+  
+
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+  
+    /*receive Edges and data*/
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        EdgeAndDataUnpackaging( mesh, msg, from, de);
+        AP_free(msg);    
+      }
+    }
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;  
+  }
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  void * FaceAndDataPackaging( pFace pf, int d, MDB_DataExchanger &de )
+  {
+    int sizebuf;
+    void *msg = de.sendData ((pEntity) pf, d, sizebuf );
+    int nV = F_numVertices( pf );
+    int nComm = nV+3;
+    int *castbuf = new int[nComm];
+    int sizeOfcastbuf = sizeof(int) * nComm;
+    void *buf = AP_alloc(d,de.tag(), sizeOfcastbuf +sizebuf );
+    char *cast = reinterpret_cast< char *> (buf);  
+    pGEntity pg = EN_whatIn( pf );
+    castbuf[0] = GEN_tag( pg );
+    castbuf[1] = GEN_type( pg ); 
+    castbuf[2] = nV;
+    for( int i = 0; i< nV; i++) {
+      int vId = EN_id( F_vertex( pf, i ) );
+      castbuf[3+i]= vId ;
+    }   
+    memcpy( &cast[0], castbuf, sizeOfcastbuf );             
+    memcpy( &cast[sizeOfcastbuf],msg,sizebuf );
+    delete [] castbuf;
+    free(msg);     
+    return buf;    
+  }
+  // -------------------------------------------------------------------
+  void FaceAndDataUnpackaging(  pMesh mesh, void *msg, int from, 
+                                MDB_DataExchanger &de )
+  {
+    /*! \TODO: only triangle is taken into account. Should be extended to other*/
+    char* castbuf = reinterpret_cast< char* >( msg );
+    int* pf_com = reinterpret_cast< int* > (castbuf);
+    int tag = pf_com[0];
+    int dim = pf_com[1];
+    int nbV = pf_com[2];
+    if( nbV != 3 ) {
+      std::cout<<"Unpackaging Face that is diff. form triangle is not implemented: "
+               <<nbV<<std::endl;
+      assert(0);
+    }
+    pGEntity pg = NULL;
+    if(dim==2) {
+      pg = (pGEntity) GM_faceByTag(mesh->model,tag);
+    } else if(dim==3) {
+      pg = (pGEntity) GM_regionByTag(mesh->model,tag);
+    }
+  
+    pVertex *ListOfpVertex = new pVertex[nbV];
+    for( int i = 0; i< nbV; i++ ) {
+      ListOfpVertex[i] = mesh->find_point( pf_com[3+i] );
+    }
+    pEdge    pe[3];
+    pe[0] =  E_exist(ListOfpVertex[0],ListOfpVertex[1]);
+    assert(pe[0]);
+    pe[1] =  E_exist(ListOfpVertex[1],ListOfpVertex[2]);
+    assert(pe[1]);
+    pe[2] =  E_exist(ListOfpVertex[0],ListOfpVertex[2]);
+    assert(pe[2]);
+
+    // pFace pface =  F_exist(2,pe[0],pe[1],pe[2],0);
+    pFace pface =  F_exist(pe[0],pe[1],pe[2],0);
+    if( !pface ) {
+      pface = M_createF(mesh,3,pe,pg);
+    }
+    assert(pface);
+    de.receiveData (pface,from, &castbuf[sizeof(int)*(nbV+3)]);
+
+    delete []  ListOfpVertex ;
+  }
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  void MigrateFacesAndData( pMesh mesh, pMeshDataId tagDest, 
+                            MDB_DataExchanger &de)
+  {
+    int nproc,myrank;
+  
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+    int *sendcounts = new int[nproc];
+    for( int i=0; i<nproc; i++){
+      sendcounts[i]= 0;
+    }
+    FIter fit = M_faceIter(mesh);
+    pFace pf;  
+    while ((pf = FIter_next(fit))) {
+      void *temp_ptr;
+      int migre = EN_getDataPtr((pEntity) pf, tagDest, &temp_ptr);
+      if(!migre) continue;
+      const SetOfDestination_type *recup =
+        reinterpret_cast< const SetOfDestination_type* > (temp_ptr);
+      assert( (recup->size())>0 );
+      SetOfDestination_type::const_iterator itd = recup->begin();
+      for(; itd!=recup->end(); itd ++) {
+        int dest = *itd;
+        assert(dest!=myrank);
+        void *buf = FaceAndDataPackaging( pf, dest, de );    
+        AP_send(buf);
+        sendcounts[dest]++; 
+      }
+    }    
+    FIter_delete(fit);
+  
+
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+  
+    /*receive Faces and data*/
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        FaceAndDataUnpackaging( mesh, msg, from, de);
+        AP_free(msg);    
+      }
+    }
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;  
+  }
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  void * RegionAndDataPackaging( pRegion pr, int d, MDB_DataExchanger &de)
+  {
+    int sizebuf;
+    void *msg = de.sendData ((pEntity) pr, d, sizebuf );
+    int nV = R_numVertices( pr );
+    int nComm = nV+3;
+    int *castbuf = new int[nComm];
+    int sizeOfcastbuf = sizeof(int) * nComm;
+    void *buf = AP_alloc(d,de.tag(), sizeOfcastbuf +sizebuf );
+    char *cast = reinterpret_cast<char *> (buf);  
+    pGEntity pg = EN_whatIn( pr );
+    castbuf[0] = GEN_tag( pg );
+    castbuf[1] = GEN_type( pg ); 
+    castbuf[2] = nV;
+    for( int i = 0; i< nV; i++) {
+      int vId = EN_id( R_vertex( pr, i ) );
+      castbuf[3+i]= vId ;
+    } 
+    memcpy( &cast[0], castbuf, sizeOfcastbuf );             
+    memcpy( &cast[sizeOfcastbuf],msg,sizebuf);
+    delete [] castbuf;
+    free(msg);     
+    return buf;  
+  }
+  // -------------------------------------------------------------------
+  void RegionAndDataUnpackaging( pMesh mesh, void *msg, int from, 
+                                 MDB_DataExchanger &de)
+  {
+    /*! \TODO: only tethra is taken into account. Should be extended to other*/
+    char* castbuf = reinterpret_cast<char*> (msg);
+    int * Region_comm = reinterpret_cast<int*> (castbuf);
+    int tag = *(Region_comm++);
+    int dim = *(Region_comm++);
+    int nbVertices = *(Region_comm++);
+    if( nbVertices != 4 ) {
+      std::cout<<"Unpackaging Region that is diff. form tethra is not implemented"
+               <<nbVertices<<std::endl;
+      assert(0);
+    }
+    pGEntity pg = NULL;
+    if(dim==2) {
+      pg = (pGEntity) GM_faceByTag(mesh->model,tag);
+    } else if(dim==3) {
+      pg = (pGEntity) GM_regionByTag(mesh->model,tag);
+    }
+  
+    pVertex *ListOfpVertex = new pVertex[nbVertices];
+    for( int i = 0; i< nbVertices; i++ ) {
+      ListOfpVertex[i] = mesh->find_point( *(Region_comm++) );
+    }
+
+
+    pFace    pface[4];
+    
+    //     pface[0] =  F_exist(2,ListOfpVertex[0],ListOfpVertex[1],ListOfpVertex[2],0);
+    //     assert(pface[0]);
+    //     pface[1] =  F_exist(2,ListOfpVertex[0],ListOfpVertex[1],ListOfpVertex[3],0);
+    //     assert(pface[1]);
+    //     pface[2] =  F_exist(2,ListOfpVertex[1],ListOfpVertex[2],ListOfpVertex[3],0);
+    //     assert(pface[2]); 
+    //     pface[3] =  F_exist(2,ListOfpVertex[0],ListOfpVertex[2],ListOfpVertex[3],0);
+    //     assert(pface[3]);
+    
+    pface[0] =  F_exist(ListOfpVertex[0],ListOfpVertex[1],ListOfpVertex[2],0);
+    assert(pface[0]);
+    pface[1] =  F_exist(ListOfpVertex[0],ListOfpVertex[1],ListOfpVertex[3],0);
+    assert(pface[1]);
+    pface[2] =  F_exist(ListOfpVertex[1],ListOfpVertex[2],ListOfpVertex[3],0);
+    assert(pface[2]);
+    pface[3] =  F_exist(ListOfpVertex[0],ListOfpVertex[2],ListOfpVertex[3],0);
+    assert(pface[3]);
+    
+   
+    pRegion pr = M_createR(mesh,4,pface,pg);
+    assert(pr);
+    de.receiveData (pr,from, &castbuf[sizeof(int)*(nbVertices+3)]);
+
+    delete []  ListOfpVertex ;
+  }
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  void MigrateRegionsAndData( pMesh mesh, pMeshDataId tagDest, 
+                              MDB_DataExchanger &de)
+  {
+    int nproc,myrank;
+  
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+    int *sendcounts = new int[nproc];
+    for( int i=0; i<nproc; i++){
+      sendcounts[i]= 0;
+    }
+    RIter rit = M_regionIter(mesh);
+    pRegion pr;  
+    while ((pr = RIter_next(rit))) {
+      void *temp_ptr;
+      int migre = EN_getDataPtr((pEntity) pr, tagDest, &temp_ptr);
+      if(!migre) continue;
+      const SetOfDestination_type *recup =
+        reinterpret_cast< const SetOfDestination_type*> (temp_ptr);
+      assert( (recup->size())>0 );
+      int dest = *(recup->begin());
+      assert(dest!=myrank);
+      void *buf = RegionAndDataPackaging( pr, dest, de );    
+      AP_send(buf);
+      sendcounts[dest]++; 
+    }    
+    RIter_delete(rit);
+  
+
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+  
+    /*receive Regions and data*/
+    int message=0;
+    int count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      recv = AP_recv(MPI_ANY_SOURCE, de.tag(), AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        message++;
+        RegionAndDataUnpackaging( mesh, msg, from, de);
+        AP_free(msg);    
+      }
+    }
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;
+  }
+  // -------------------------------------------------------------------
+  // ------------------------------------------------------------------- 
+  // ------------------------------------------------------------------- 
+  void MigrateEntitiesAndData(pMesh mesh, pMeshDataId tagDest, 
+                              MDB_DataExchanger &de)
+  {
+    MigrateVerticesAndData( mesh, tagDest, de);
+    MigrateEdgesAndData( mesh, tagDest, de);
+    MigrateFacesAndData( mesh, tagDest, de);
+    MigrateRegionsAndData( mesh, tagDest, de);
+  }
+
+}
+
+#endif
+
diff --git a/Mesh/MeshDataBaseMiniMesh.cc b/Mesh/MeshDataBaseMiniMesh.cc
new file mode 100644
index 0000000..8c503e9
--- /dev/null
+++ b/Mesh/MeshDataBaseMiniMesh.cc
@@ -0,0 +1,60 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "MeshDataBaseMiniMesh.h"
+
+namespace MAd {
+
+  size_t MDB_MiniMesh::size_buf () const
+  {
+    return sizeof(int) * ( 2 + nbInfos ) + sizeof(double) * 3 * nbVertex + sizeof(int) * nbVertex;
+  }
+
+  MDB_MiniMesh::~MDB_MiniMesh()
+  {
+    if (nbVertex)
+      {
+        if (coords) delete [] coords;
+        delete [] infos;
+        delete [] ids;
+      }
+  }
+
+  void MDB_MiniMesh::_load ( FILE *f )
+  {
+    if (nbVertex != 0)
+      {
+        if (coords) { delete [] coords; coords=NULL; }
+        delete [] infos;
+        delete [] ids;
+      }
+    fread ( &nbVertex , sizeof(int)   , 1, f );
+    fread ( &nbInfos  , sizeof(int)   , 1, f );
+    coords = new double [3 * nbVertex];
+    infos  = new int    [nbInfos     ];
+    ids    = new int    [nbVertex    ];
+    fread ( coords    , sizeof(double), nbVertex * 3, f );
+    fread ( infos     , sizeof(int)   , nbInfos, f );
+    fread ( ids       , sizeof(int)   , nbVertex, f );
+  }
+
+  void MDB_MiniMesh::_flush ( FILE *f ) const
+  {
+    if (nbVertex == 0) throw;
+    fwrite ( &nbVertex , sizeof(int)   , 1, f );
+    fwrite ( &nbInfos  , sizeof(int)   , 1, f );
+    fwrite ( coords    , sizeof(double), nbVertex * 3, f );
+    fwrite ( infos     , sizeof(int)   , nbInfos, f );
+    fwrite ( ids       , sizeof(int)   , nbVertex, f );
+  }
+
+}
diff --git a/Mesh/MeshDataBaseMiniMesh.h b/Mesh/MeshDataBaseMiniMesh.h
new file mode 100644
index 0000000..4012c88
--- /dev/null
+++ b/Mesh/MeshDataBaseMiniMesh.h
@@ -0,0 +1,39 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _MESHDATABASE_MINIMESH_
+#define _MESHDATABASE_MINIMESH_
+
+#include <stdio.h>
+
+namespace MAd {
+
+  class MDB_MiniMesh
+  {
+  protected:
+    int nbVertex;
+    double * coords;
+    int nbInfos;
+    int *infos;
+    int *ids;
+    void _flush ( FILE *F ) const;
+    void _load  ( FILE *F );
+    size_t size_buf () const;
+  public:
+    virtual ~MDB_MiniMesh ();
+    MDB_MiniMesh () : nbVertex (0) , coords(0), nbInfos (0), infos(0), ids(0) {}
+  };
+
+}
+
+#endif
diff --git a/Mesh/MeshDataBaseParallelIO.cc b/Mesh/MeshDataBaseParallelIO.cc
new file mode 100644
index 0000000..77d7c42
--- /dev/null
+++ b/Mesh/MeshDataBaseParallelIO.cc
@@ -0,0 +1,1415 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Cecile Dobrzynski, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "MeshDataBase.h"
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseIO.h"
+#include "MeshDataBaseMessage.h"
+#include "MeshDataBaseGEntity2Physical.h"
+#ifndef _WIN_
+#include <unistd.h>
+#endif
+#include "MshTags.h"
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+#include "fcntl.h"
+#include "MeshDataBaseParallelInterface.h"
+#endif
+
+#include <cstdlib>
+#include <cstring>
+// #include <set>
+// #include <utility>
+
+extern int getNumVerticesForElementTypeMSH(int type);
+
+namespace MAd {
+
+#ifdef PARALLEL
+  // -------------------------------------------------------------------
+  // -------------------- SaveGmshMeshParallel -------------------------
+  // -------------------------------------------------------------------
+
+  // Save a mesh (for parallel only) with format msh1 or msh2 \ingroup parallel
+  // GCRMK: now vertex ids are unique: we can use the ids directly and simplify this function
+  void SaveGmshMeshParallel (const pMesh mesh, const char *filename, int version)
+  {
+    // ***************** update ID interface ***************
+    pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+    V_createInfoInterface(mesh, tagData);   
+    MPI_Barrier(MPI_COMM_WORLD);
+
+    int nbModelVertex = 0;
+    int myrank,nproc;
+
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+    if(myrank==0) {
+      FILE * nop =  fopen(filename,"w");
+      fclose(nop);
+    }
+    MPI_Barrier(MPI_COMM_WORLD); 
+
+    int npt = 0;
+  
+    VIter vit = M_vertexIter(mesh); 
+    while (VIter_next(vit)){}
+    VIter_reset(vit);
+    pVertex pv;  
+    int NN = 0,nssint = 0;;
+    while ((pv = VIter_next(vit)))
+      { 
+        if(pv->g)
+          {
+            NN++;
+            void *temp_ptr; 
+            int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);    
+            int j =0,size= 0;
+            if(isInterface) {
+              const std::vector<std::pair<int , MDB_Point*> > *recup = 
+                (const std::vector<std::pair<int , MDB_Point*> > *) temp_ptr;
+              size = (*recup).size() ;
+              for(j=0 ; j<size; j++) {
+                int remoteID  = (*recup)[j].first;
+                assert(remoteID!=myrank);
+                if(remoteID < myrank) break;
+              }
+            }
+            if(j == size) {
+              nssint++;
+            } 
+          } else {
+          throw;
+        }
+      }
+    if (NN != mesh->nbPoints) 
+      {
+        printf("%d != %d\n",NN,mesh->nbPoints);
+        throw;
+      }
+    VIter_delete(vit); 
+    int *tab=new int[nproc];
+    int sendnum = nssint; 
+    if(myrank) {
+      MPI_Send(&sendnum,1,MPI_INT,0,myrank,MPI_COMM_WORLD);   
+    } else {
+      MPI_Status status;
+      tab[0] = sendnum;
+      for(int i=1 ; i<nproc ; i++) {
+        MPI_Recv(&tab[i],1,MPI_INT,i,i,MPI_COMM_WORLD,&status);
+      }
+    }
+  
+    MPI_Bcast(&tab[0],nproc,MPI_INT,0,MPI_COMM_WORLD);
+  
+    int *tabmax=new int[nproc];
+    sendnum = mesh->maxId; 
+    if(myrank) {
+      MPI_Send(&sendnum,1,MPI_INT,0,myrank,MPI_COMM_WORLD);   
+    } else {
+      MPI_Status status;
+      tabmax[0] = sendnum;
+      for(int i=1 ; i<nproc ; i++) {
+        MPI_Recv(&tabmax[i],1,MPI_INT,i,i,MPI_COMM_WORLD,&status);
+      }
+    }
+  
+    MPI_Bcast(&tabmax[0],nproc,MPI_INT,0,MPI_COMM_WORLD);
+  
+    // --------------------------------------------------
+    // Defines a control point for a sequential writting:
+    //    Proc n+1 does not continue while proc n is 
+    //    not at the next control point
+    int send = 0,recv = 0;
+    if(!myrank) recv = 1;
+    MPI_Status status;
+    while(!recv) {  
+      if(myrank!=(nproc-1)) MPI_Send(&send,1,MPI_INT,(myrank+1)%nproc,(myrank+1)%nproc,MPI_COMM_WORLD);
+      MPI_Recv(&recv,1,MPI_INT,(myrank+nproc-1)%nproc,myrank,MPI_COMM_WORLD,&status);
+    }
+    int nseek = recv;
+    int nplace = nseek;
+    if (!myrank) nplace = 0;
+    // --------------------------------------------------
+
+    int nop = open(filename,O_WRONLY);
+  
+
+    // ----------------------------------------------------
+    // Write format (for msh2 only)
+    // ----------------------------------------------------
+  
+    if ( !myrank && version != 1 ) {
+      char format[256];
+      sprintf(format, "$MeshFormat\n2 0 8\n$EndMeshFormat\n");
+      int size = strlen(format);
+      write(nop,format,size);
+      nplace += size;
+    }
+
+    // ----------------------------------------------------
+    // Write partitionning of nodes (for msh1 only)
+    // ----------------------------------------------------
+
+    if ( version == 1 ) {
+ 
+      if(!myrank) {
+        write(nop,"$PARALLELNOD\n",sizeof("$PARALLELNOD"));
+        nplace += sizeof("$PARALLELNOD");
+        char nb[256];
+        int nbtot = 0;
+        for(int i=0 ; i<nproc ; i++) nbtot +=tab[i];
+        sprintf(nb,"%d\n",nbtot);
+        int size = strlen(nb);
+        nplace += size;
+        write(nop,nb,size);
+      }
+      //    int IdGlobal = 0;
+      if(myrank) {
+        lseek(nop,nseek,0);
+        //      for(int j=0 ; j<myrank; j++) IdGlobal += tabmax[j];
+      }  
+      vit = M_vertexIter(mesh); 
+      while (VIter_next(vit)){}
+      VIter_reset(vit);  
+      NN = 0;
+      while ((pv = VIter_next(vit)))
+        { 
+          if(pv->g)
+            {
+              NN++;
+              if (pv->deleted)printf("ouuch\n");
+              void *temp_ptr; 
+              int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);    
+              int j =0,size= 0/*,nId = IdGlobal*/;
+              if(isInterface) {
+                const std::vector<std::pair<int , MDB_Point*> > *recup = (const std::vector<std::pair<int , MDB_Point*> > *) temp_ptr;
+                size = (*recup).size() ;
+                for(j=0 ; j<size; j++) {
+                  int remoteID  = (*recup)[j].first;
+                  if(remoteID < myrank) break;
+                }
+              }
+              if(j == size) {
+                nssint++;
+  
+                char nb[256];
+                if(size) sprintf(nb,"%d %d %d ",pv->iD /*+ nId*/, size + 1,myrank);
+                else     sprintf(nb,"%d %d %d \n",pv->iD /*+ nId*/, size + 1,myrank);
+                for(j=0 ; j<size; j++) {
+                  const std::vector<std::pair<int , MDB_Point*> > *recup = (const std::vector<std::pair<int , MDB_Point*> > *) temp_ptr;
+                  char nbtmp[256];
+                  if(j == (size-1) )  sprintf(nbtmp,"%d \n",(*recup)[j].first); 
+                  else                sprintf(nbtmp,"%d ",(*recup)[j].first); 
+                  int sizetmp = strlen(nbtmp);  
+                  strncat(nb,nbtmp,sizetmp);    
+                } 
+  
+                int size = strlen(nb);
+                nplace += size;
+                write(nop,nb,size);
+              } 
+            } else {
+            throw;
+          }
+        }
+      if (NN != mesh->nbPoints) 
+        {
+          printf("%d != %d\n",NN,mesh->nbPoints);
+          throw;
+        }
+      VIter_delete(vit);    
+  
+      MPI_Send(&nplace,1,MPI_INT,(myrank+1)%nproc,(myrank+1)%nproc,MPI_COMM_WORLD);
+  
+      if(!myrank) MPI_Recv(&npt,1,MPI_INT,(myrank+nproc-1)%nproc,myrank,MPI_COMM_WORLD,&status);
+    
+      MPI_Barrier(MPI_COMM_WORLD);
+
+      send = 0,recv = 0;
+      if(!myrank) recv = 1;
+  
+      while(!recv) {  
+        if(myrank!=(nproc-1)) MPI_Send(&send,1,MPI_INT,(myrank+1)%nproc,(myrank+1)%nproc,MPI_COMM_WORLD);
+        MPI_Recv(&recv,1,MPI_INT,(myrank+nproc-1)%nproc,myrank,MPI_COMM_WORLD,&status);
+      }
+  
+      nseek = recv;
+      nplace = nseek;
+  
+      if(!myrank) {
+        nplace = npt;
+        lseek(nop,nplace,0);
+        write(nop,"$ENDPARALLELNOD\n",sizeof("$ENDPARALLELNOD"));
+        nplace += sizeof("$ENDPARALLELNOD");
+      }
+
+    }
+
+    // ----------------------------------------------------
+    // Write nodes
+    // ----------------------------------------------------
+
+    if(!myrank) {
+      char nb[256];
+      if ( version == 1 ) sprintf(nb,"$NOD\n");
+      else                sprintf(nb,"$Nodes\n");
+      int size = strlen(nb);
+      nplace += size;
+      write(nop,nb,size);
+    }
+    if(!myrank) {    
+      char nb[256];
+      int nbtot = 0;
+      for(int i=0 ; i<nproc ; i++) nbtot +=tab[i];
+      sprintf(nb,"%d\n",nbtot);
+      int size = strlen(nb);
+      nplace += size;
+      write(nop,nb,size);
+    }
+    //  int IdGlobal = 0;
+    if(myrank) {
+      lseek(nop,nseek,0);
+      //    for(int j=0 ; j<myrank; j++) IdGlobal += tabmax[j];
+    }  
+    vit = M_vertexIter(mesh); 
+    while (VIter_next(vit)){}
+    VIter_reset(vit);  
+    NN = 0;
+    while ((pv = VIter_next(vit)))
+      { 
+        if(pv->g)
+          {
+            NN++;
+            int dim = GEN_type(pv->g); 
+
+            if (pv->deleted)printf("ouuch\n");
+            void *temp_ptr; 
+            int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);    
+            int j =0,size= 0/*,nId = IdGlobal*/;
+            if(isInterface) {
+              const std::vector<std::pair<int , MDB_Point*> > *recup = 
+                (const std::vector<std::pair<int , MDB_Point*> > *) temp_ptr;
+              size = (*recup).size() ;
+              for(j=0 ; j<size; j++) {
+                int remoteID  = (*recup)[j].first;
+                if(remoteID < myrank) break;
+              }
+            }
+            if(j == size) {
+              nssint++;
+              if(dim == 0)
+                nbModelVertex++;
+  
+              char nb[256];
+              sprintf(nb,"%d %g %g %g\n",pv->iD /*+ nId*/, pv->X, pv->Y, pv->Z);
+              int size = strlen(nb);
+              nplace += size;
+              write(nop,nb,size);
+            } 
+          } else {
+          throw;
+        }
+      }
+    if (NN != mesh->nbPoints) 
+      {
+        printf("%d != %d\n",NN,mesh->nbPoints);
+        throw;
+      }
+    VIter_delete(vit);    
+  
+    // --------------------------------------------------
+    // End of the control point
+    MPI_Send(&nplace,1,MPI_INT,(myrank+1)%nproc,(myrank+1)%nproc,MPI_COMM_WORLD);
+  
+    if(!myrank) MPI_Recv(&npt,1,MPI_INT,(myrank+nproc-1)%nproc,myrank,MPI_COMM_WORLD,&status);
+    
+    MPI_Barrier(MPI_COMM_WORLD);
+    // --------------------------------------------------
+
+    //  pMeshDataId tagGlob = MD_lookupMeshDataId("IdGlobal");
+    //  UpdateIDGlobal(mesh,IdGlobal);    
+    //  MPI_Barrier(MPI_COMM_WORLD);
+
+    pMeshDataId tagEdge = MD_lookupMeshDataId("WriteEdge"); 
+    E_createInfoInterface(mesh,tagEdge);    
+    MPI_Barrier(MPI_COMM_WORLD);
+
+    pMeshDataId tagFaceInterface = MD_lookupMeshDataId("FaceInterface"); 
+    F_createInfoInterface(mesh,tagFaceInterface);
+  
+    // *****************ecriture des elt******************* 
+    int nbClasEdges = 0;
+    int nbClasFaces = 0;
+ 
+    pMeshDataId tagFace = MD_newMeshDataId("WriteFace"); 
+ 
+    {
+      EIter eit = M_edgeIter(mesh);
+      pEdge pe;  
+      while ((pe = EIter_next(eit)))
+        {
+          int dim = GEN_type(pe->g); 
+          if(dim == 1) {
+            void * tmpptr;
+            int is = EN_getDataPtr((pEntity) pe , tagEdge,&tmpptr);
+            if(!is){
+              nbClasEdges++;
+            } else {
+              std::map<int,pEdge> *recup = (std::map<int,pEdge> *) tmpptr;
+              int minproc = myrank;
+              for( std::map<int,pEdge>::const_iterator iter=(*recup).begin() ; 
+                   iter!=(*recup).end() ; iter++){
+                minproc = std::min(minproc,(*iter).first);
+              }
+              if(minproc==myrank) {
+                nbClasEdges++;
+              } 
+            }
+          }   
+        }
+      EIter_delete(eit);
+    }    
+    {
+      FIter fit = M_faceIter(mesh);
+      pFace pface;  
+      while ((pface = FIter_next(fit)))
+        {
+          int dim = GEN_type(pface->g);   
+          if(dim == 2){
+            void * list;
+            int is = EN_getDataPtr((pEntity) pface , tagFaceInterface,&list);
+            if(!is){
+              nbClasFaces++;
+              EN_attachDataInt((pEntity) pface,tagFace,1);
+            } else {
+              std::vector<int> *recup = (std::vector<int> *) list;
+              int minproc = myrank;
+              for(unsigned int i=0 ; i<(*recup).size() ; i++){
+                minproc = std::min(minproc,(*recup)[i]);
+              }
+              if(minproc==myrank) {
+                nbClasFaces++;
+                EN_attachDataInt((pEntity) pface,tagFace,1);
+              } 
+            }
+          }
+        }
+      FIter_delete(fit);
+    } 
+
+    sendnum = nbClasEdges + nbModelVertex + nbClasFaces + mesh->nbTets;
+
+    // the first proc collects the number of elements from the others...
+    if(myrank) {
+      MPI_Send(&sendnum,1,MPI_INT,0,myrank,MPI_COMM_WORLD);   
+    } else {
+      MPI_Status status;
+      tab[0] = sendnum;
+      for(int i=1 ; i<nproc ; i++) {
+        MPI_Recv(&tab[i],1,MPI_INT,i,i,MPI_COMM_WORLD,&status);
+      }
+    }
+  
+    // printf("Before:  Proc %d: tab:\t%d\t%d\n",myrank,tab[0],tab[1]);
+
+    // ... and sends its results to everyone
+    MPI_Bcast(&tab[0],nproc,MPI_INT,0,MPI_COMM_WORLD);   
+
+    //  printf("After:   Proc %d: tab:\t%d\t%d\n",myrank,tab[0],tab[1]);
+
+  
+    // --------------------------------------------------
+    // Defines a control point for a sequential writting:
+    //    Proc n+1 does not continue while proc n is 
+    //    not at the next control point
+    send = 0,recv = 0;
+    if(!myrank) recv = 1;
+  
+    while(!recv) {  
+      if(myrank!=(nproc-1)) MPI_Send(&send,1,MPI_INT,(myrank+1)%nproc,(myrank+1)%nproc,MPI_COMM_WORLD);
+      MPI_Recv(&recv,1,MPI_INT,(myrank+nproc-1)%nproc,myrank,MPI_COMM_WORLD,&status);
+    }
+  
+    nseek = recv;
+    nplace = nseek;
+    // --------------------------------------------------
+  
+    if(!myrank) {
+      nplace = npt;
+      lseek(nop,nplace,0);
+      char nb[256];
+      if ( version == 1 ) sprintf(nb,"$ENDNOD\n");
+      else                sprintf(nb,"$EndNodes\n");
+      int size = strlen(nb);
+      write(nop,nb,size);
+      nplace += size;
+    }
+
+    // ----------------------------------------------------
+    // Write partitionning of elements (for msh1 only)
+    // ----------------------------------------------------
+
+    if ( version == 1 ) {
+
+      if(!myrank) {
+        write(nop,"$PARALLELELM\n",sizeof("$PARALLELELM"));
+        nplace += sizeof("$PARALLELELM");
+        char nb[256];
+        int nbtot = 0;
+        for(int i=0 ; i<nproc ; i++) nbtot +=tab[i];
+        sprintf(nb,"%d\n",nbtot);
+        int size = strlen(nb);
+        nplace += size;
+        write(nop,nb,size);
+      }
+      if(myrank) {
+        lseek(nop,nseek,0);
+      }
+
+      int k = 1;
+      if(myrank) {
+        for(int i=0 ; i<myrank ; i++) k+= tab[i];
+      }  
+      {
+        VIter vit = M_vertexIter(mesh);
+        pVertex pv;  
+        while ((pv = VIter_next(vit)))
+          {
+            int dim = GEN_type(pv->g); 
+            if(dim == 0) {
+              char nb[256];
+              void *temp_ptr; 
+              int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+              if(isInterface) {
+                const std::vector<std::pair<int, MDB_Point*> > *recup = (const std::vector<std::pair<int, MDB_Point*> > *) temp_ptr;
+                int minproc = nproc + 10;
+                for(unsigned int j=0 ; j<(*recup).size() ; j++) minproc = std::min(minproc,(*recup)[j].first);
+                minproc = std::min(myrank,minproc);
+                if(minproc!=myrank) continue;    
+                int size = (*recup).size();
+                for(int j=0 ; j<size ; j++) {
+                  sprintf(nb,"%d %d %d ",k++, size + 1,myrank);
+                  char nbtmp[256];
+                  if(j == (size-1) )  sprintf(nbtmp,"%d \n",(*recup)[j].first); 
+                  else                sprintf(nbtmp,"%d ",(*recup)[j].first); 
+                  int sizetmp = strlen(nbtmp); 
+                  strncat(nb,nbtmp,sizetmp);
+                }  
+              } else {
+                sprintf(nb,"%d %d %d \n",k++, 1,myrank);
+              }
+              int size = strlen(nb);
+              nplace += size;
+              write(nop,nb,size);
+            }
+          }
+        VIter_delete(vit);   
+      }
+      { 
+        EIter eit = M_edgeIter(mesh);
+        pEdge pe;  
+        while ((pe = EIter_next(eit)))
+          {
+            int dim = GEN_type(pe->g); 
+            if(dim == 1) {
+              void* tmpptr;
+              int isMarked = EN_getDataPtr((pEntity) pe,tagEdge,&tmpptr);
+              char nb[256];
+              if(!isMarked) {
+                sprintf(nb,"%d %d %d \n", k++, 1,myrank);
+              } else {
+                std::map<int,pEdge> *recup = (std::map<int,pEdge> *) tmpptr;
+                int minproc = myrank;
+                for(std::map<int,pEdge>::const_iterator iter=(*recup).begin() ;
+                    iter!=(*recup).end() ; iter++){
+                  minproc = std::min(minproc,(*iter).first);
+                }
+                if(minproc!=myrank) continue;
+                sprintf(nb,"%d %d %d ", k++, (*recup).size() + 1,myrank);
+                for(std::map<int,pEdge>::const_iterator iter=(*recup).begin() ;
+                    iter!=(*recup).end() ; iter++) {
+                  char nbtmp[256];
+                  if((*iter).first == ((*recup).size()-1) ){
+                    sprintf(nbtmp,"%d \n",(*iter).first);
+                  } else{
+                    sprintf(nbtmp,"%d ",(*iter).first);
+                  }
+                  int sizetmp = strlen(nbtmp); 
+                  strncat(nb,nbtmp,sizetmp);  
+                }
+              }
+              int size = strlen(nb);
+              nplace += size;
+              write(nop,nb,size);
+            }  
+          }
+        EIter_delete(eit);
+      }
+      {
+        FIter fit = M_faceIter(mesh);
+        pFace pf;  
+        while ((pf = FIter_next(fit)))
+          {
+            int ntmp;
+            int isMarked = EN_getDataInt((pEntity) pf,tagFace,&ntmp);
+            if(!isMarked) continue;
+            int dim = GEN_type(pf->g); 
+            if(dim == 2) {
+              void* tmpptr;
+              int isInt = EN_getDataPtr((pEntity) pf,tagFaceInterface,&tmpptr);
+              char nb[256];
+              if(!isInt) {
+                sprintf(nb, "%d %d %d \n", k++, 1,myrank);
+              } else {
+                std::vector<int> *recup = (std::vector<int> *) tmpptr;
+                int size = (*recup).size();    
+                sprintf(nb,"%d %d %d ", k++, size + 1,myrank);
+                for(int j=0 ; j<size ; j++) {
+                  char nbtmp[256];
+                  if(j == (size-1) )  sprintf(nbtmp,"%d \n",(*recup)[j]); 
+                  else                sprintf(nbtmp,"%d ",(*recup)[j]); 
+                  int sizetmp = strlen(nbtmp); 
+                  strncat(nb,nbtmp,sizetmp);
+                }  
+              }  
+              int size = strlen(nb);
+              nplace += size;
+              write(nop,nb,size);
+            }  
+          }
+        FIter_delete(fit);
+      } 
+      {
+        RIter rit = M_regionIter(mesh);
+        pRegion pr;  
+        while ((pr = RIter_next(rit))) {
+          char nb[256];
+          sprintf(nb,"%d %d %d \n", k++,1,myrank );
+          int size = strlen(nb);
+          nplace += size;
+          write(nop,nb,size);
+        }
+        RIter_delete(rit);
+      }
+ 
+      // --------------------------------------------------
+      // End of the control point
+      MPI_Send(&nplace,1,MPI_INT,(myrank+1)%nproc,(myrank+1)%nproc,MPI_COMM_WORLD);
+    
+      if(!myrank) MPI_Recv(&npt,1,MPI_INT,(myrank+nproc-1)%nproc,myrank,MPI_COMM_WORLD,&status);
+    
+      MPI_Barrier(MPI_COMM_WORLD);
+      // --------------------------------------------------
+
+      // --------------------------------------------------
+      // Defines a control point for a sequential writting:
+      //    Proc n+1 does not continue while proc n is 
+      //    not at the next control point
+      send = 0,recv = 0;
+      if(!myrank) recv = 1;
+    
+      while(!recv) {  
+        if(myrank!=(nproc-1)) MPI_Send(&send,1,MPI_INT,(myrank+1)%nproc,(myrank+1)%nproc,MPI_COMM_WORLD);
+        MPI_Recv(&recv,1,MPI_INT,(myrank+nproc-1)%nproc,myrank,MPI_COMM_WORLD,&status);
+      }
+    
+      nseek = recv;
+      nplace = nseek;
+      // --------------------------------------------------
+       
+      if(!myrank) {
+        nplace = npt;
+        lseek(nop,nplace,0);
+        write(nop,"$ENDPARALLELELM\n",sizeof("$ENDPARALLELELM"));
+        nplace += sizeof("$ENDPARALLELELM");
+      }
+
+    }
+
+    // ----------------------------------------------------
+    // Write elements
+    // ----------------------------------------------------
+
+    if(!myrank) {
+      char nb[256];
+      if ( version == 1 ) { sprintf(nb,"$ELM\n"); }
+      else                { sprintf(nb,"$Elements\n"); }
+      int size = strlen(nb);
+      write(nop,nb,size);
+      nplace += size;
+    }
+    if(!myrank) {
+      char nb[256];
+      int nbtot = 0;
+      for(int i=0 ; i<nproc ; i++) nbtot += tab[i];
+      sprintf(nb,"%d\n",nbtot);
+      int size = strlen(nb);
+      nplace += size;
+      write(nop,nb,size);
+    }
+    if(myrank) {
+      lseek(nop,nseek,0);
+    }
+
+    int k = 1;
+    // Create a reverse map of physical tags
+    GEntity2Physical gentity2phys(mesh->geomFeatures_Tags);
+    if(myrank) {
+      for(int i=0 ; i<myrank ; i++) k+= tab[i];
+    }
+    // --- Nodes ---
+    {
+      VIter vit = M_vertexIter(mesh);
+      pVertex pv;  
+      while ((pv = VIter_next(vit)))
+        {
+          int dim = GEN_type(pv->g); 
+          int tag = GEN_tag (pv->g); 
+          int phys = gentity2phys.get_first_tag(pv->g);
+          if(dim == 0) {
+            char nb[256];
+            //int nId = IdGlobal;
+            void *temp_ptr; 
+            int isInterface = EN_getDataPtr((pEntity) pv, tagData, &temp_ptr);
+            if(isInterface) {
+              const std::vector<std::pair<int , MDB_Point*> > *recup = (const std::vector<std::pair<int , MDB_Point*> > *) temp_ptr;
+              int minproc = nproc + 10;
+              for(unsigned int j=0 ; j<(*recup).size() ; j++) minproc = std::min(minproc,(*recup)[j].first);
+              minproc = std::min(myrank,minproc);
+              if(minproc!=myrank) continue;    
+            }
+            if ( version == 1 ) {
+              sprintf(nb,"%d %d %d %d %d %d\n",
+                      k++, 15, phys, tag, 1, pv->iD /*+ nId*/);
+            } else {
+              int nbTags = 3;
+              sprintf(nb,"%d %d %d %d %d %d %d\n",
+                      k++, 15, nbTags, phys, tag, myrank+1, pv->iD /*+ nId*/);
+            }
+            int size = strlen(nb);
+            nplace += size;
+            write(nop,nb,size);
+          }
+        }
+      VIter_delete(vit);   
+    }
+    // --- Edges ---
+    { 
+      EIter eit = M_edgeIter(mesh);
+      pEdge pe;  
+      while ((pe = EIter_next(eit)))
+        {
+          int dim = GEN_type(pe->g); 
+          int tag = GEN_tag (pe->g); 
+          int phys = gentity2phys.get_first_tag(pe->g);
+          if(dim == 1) {
+            char nb[256];
+            pVertex p1 = pe->p1;
+            pVertex p2 = pe->p2;
+            //int nId1 = pe->p1->iD /*+ IdGlobal*/,nId2 = pe->p2->iD /*+ IdGlobal*/;
+            //void *temp_ptr1,*temp_ptr2; 
+            //int isInterface1 = EN_getDataPtr((pEntity) p1 , tagData, &temp_ptr1);
+            //int isInterface2 = EN_getDataPtr((pEntity) p2 , tagData, &temp_ptr2);
+            //if(isInterface1) {
+            //  int isGlob;
+            //  int is = EN_getDataInt((pEntity) p1, tagGlob, &isGlob);
+            //  assert(is);
+            //  nId1 = --isGlob;
+            //}
+            //if(isInterface2) {
+            //  int isGlob;
+            //  int is = EN_getDataInt((pEntity) p2, tagGlob, &isGlob);
+            //  assert(is);
+            //  nId2 = --isGlob;
+            //}
+            void * tmpptr;
+            int isMarked = EN_getDataPtr((pEntity) pe, tagEdge, &tmpptr);
+            if(!isMarked) {
+              if ( version == 1 ) {
+                sprintf(nb,"%d %d %d %d %d %d %d\n", 
+                        k++, 1, phys, tag, 2,p1->iD, p2->iD /* nId1, nId2*/);
+              } else {
+                int nbTags = 3;
+                sprintf(nb,"%d %d %d %d %d %d %d %d\n",
+                        k++, 1, nbTags, phys, tag, myrank+1,p1->iD, p2->iD /* nId1, nId2*/);
+              }
+            } else {
+              const std::map<int,pEdge> *recup = (const std::map<int,pEdge> *) tmpptr;
+              int minproc = myrank;
+              for(std::map<int,pEdge>::const_iterator iter=(*recup).begin() ;
+                  iter!=(*recup).end() ; iter++){
+                minproc = std::min(minproc,(*iter).first);
+              }
+              if(minproc!=myrank) continue;
+              if ( version == 1 ) {
+                sprintf(nb,"%d %d %d %d %d %d %d\n", 
+                        k++, 1, phys, tag, 2, p1->iD, p2->iD /* nId1, nId2*/);
+              } else {
+                int nbTags = 3;
+                sprintf(nb,"%d %d %d %d %d %d %d %d\n",
+                        k++, 1, nbTags, phys, tag, myrank+1,p1->iD, p2->iD /* nId1, nId2*/);
+              }
+            }
+            int size = strlen(nb);
+            nplace += size;
+            write(nop,nb,size);
+          }  
+        }
+      EIter_delete(eit);
+    }
+    // --- Faces ---
+    {
+      FIter fit = M_faceIter(mesh);
+      pFace pf;  
+      while ((pf = FIter_next(fit)))
+        {
+          int ntmp;
+          int isMarked = EN_getDataInt((pEntity) pf,tagFace,&ntmp);
+          if(!isMarked) continue;
+          MDB_Point *nod[3];
+          int dim = GEN_type(pf->g); 
+          int tag = GEN_tag (pf->g); 
+          int phys = gentity2phys.get_first_tag(pf->g);
+          pf->getNodes(nod);
+          if(dim == 2) {
+            char nb[256];
+            //int nId[3];
+            pf->getNodes(nod);
+            //void *temp_ptr1;
+            //for(int j=0 ; j<3 ; j++){ 
+            //  int isInterface = EN_getDataPtr((pEntity) nod[j], tagData, &temp_ptr1);
+            //  if(isInterface) {
+            //    int isGlob;
+            //    int is = EN_getDataInt((pEntity) nod[j], tagGlob, &isGlob);
+            //    assert(is);
+            //    nId[j] = --isGlob;
+            //  }
+            //  else nId[j] = nod[j]->iD + IdGlobal;
+            //}
+            if ( version == 1 ) {
+              sprintf(nb, "%d %d %d %d %d %d %d %d\n",
+                      k++, 2, phys,tag, 3, nod[0]->iD, nod[1]->iD,nod[2]->iD/*nId[0],  nId[1],  nId[2]*/);
+            } else {
+              int nbTags = 3;
+              sprintf(nb, "%d %d %d %d %d %d %d %d %d\n",
+                      k++, 2, nbTags, phys, tag, myrank+1, nod[0]->iD, nod[1]->iD,nod[2]->iD/* nId[0],  nId[1],  nId[2]*/);
+            }
+            int size = strlen(nb);
+            nplace += size;
+            write(nop,nb,size);
+          }  
+        }
+      FIter_delete(fit);
+    }
+    // --- Regions ---
+    {
+      RIter rit = M_regionIter(mesh);
+      pRegion pr;  
+      while ((pr = RIter_next(rit)))
+        {
+          MDB_Point *nod[4];
+          int tag = GEN_tag (pr->g);  
+          int phys = gentity2phys.get_first_tag(pr->g);
+          pPList ll = R_vertices(pr);       
+          nod[0] =  (pVertex)PList_item(ll, 0);
+          nod[1] =  (pVertex)PList_item(ll, 1);
+          nod[2] =  (pVertex)PList_item(ll, 2);
+          nod[3] =  (pVertex)PList_item(ll, 3);
+          PList_delete(ll);
+          char nb[256];
+          // int nId[4];
+          // void *temp_ptr1;
+          // for(int j=0 ; j<4 ; j++){ 
+          //  int isInterface = EN_getDataPtr((pEntity) nod[j] , tagData, &temp_ptr1);
+          //   if(isInterface){
+          //     int isGlob;
+          //     int is = EN_getDataInt((pEntity) nod[j] , tagGlob , &isGlob);
+          //     assert(is); 
+          //     nId[j] = --isGlob;
+          //   }  
+          //   else nId[j] = nod[j]->iD + IdGlobal;
+          // }
+          if ( version == 1 ) {
+            sprintf(nb, "%d %d %d %d %d %d %d %d %d\n",
+                    k++, 4, phys, tag, 4, nod[0]->iD, nod[1]->iD,nod[2]->iD,nod[3]->iD/* nId[0], nId[1], nId[2], nId[3]*/);
+          } else {
+            int nbTags = 3;
+            sprintf(nb, "%d %d %d %d %d %d %d %d %d %d\n",
+                    k++, 4, nbTags, phys, tag, myrank+1, nod[0]->iD, nod[1]->iD,nod[2]->iD,nod[3]->iD/*nId[0], nId[1], nId[2], nId[3]*/);
+          }
+          int size = strlen(nb);
+          nplace += size;
+          write(nop,nb,size);
+        }
+      RIter_delete(rit);
+    }
+    
+    // --------------------------------------------------
+    // End of the control point
+    MPI_Send(&nplace,1,MPI_INT,(myrank+1)%nproc,(myrank+1)%nproc,MPI_COMM_WORLD);
+  
+    if(!myrank) MPI_Recv(&npt,1,MPI_INT,(myrank+nproc-1)%nproc,myrank,MPI_COMM_WORLD,&status);
+    
+    MPI_Barrier(MPI_COMM_WORLD);  
+    // --------------------------------------------------  
+
+    if(!myrank) {
+      nplace = npt;
+      lseek(nop,nplace,0);
+      char nb[256];
+      if ( version == 1 ) { sprintf(nb,"$ENDELM\n"); }
+      else                { sprintf(nb,"$EndElements\n"); }
+      int size = strlen(nb);
+      write(nop,nb,size);
+      nplace += size;
+    }    
+        
+    close(nop);
+  
+    //vit = M_vertexIter(mesh); 
+    //while ((pv=VIter_next(vit))){
+    //  int isGlob;
+    //  int is = EN_getDataInt((pEntity) pv , tagGlob , &isGlob);
+    //  if(is) EN_deleteData((pEntity) pv,tagGlob); 
+    //}
+    //VIter_reset(vit);  
+    //  MD_deleteMeshDataId(tagGlob);
+
+    EIter eit = M_edgeIter(mesh);
+    pEdge pe; 
+    while ((pe=EIter_next(eit))){
+      void* is;
+      int isMarked = EN_getDataPtr((pEntity) pe , tagEdge , &is);
+      if(isMarked) EN_deleteData((pEntity) pe,tagEdge); 
+    }
+    EIter_reset(eit);  
+    MD_deleteMeshDataId(tagEdge);
+  
+    FIter fit = M_faceIter(mesh); 
+    pFace pface;
+    while ((pface=FIter_next(fit))){
+      int is;
+      int isMarked = EN_getDataInt((pEntity) pface , tagFace , &is);
+      if(isMarked) EN_deleteData((pEntity) pface,tagFace); 
+      void* isp;
+      isMarked = EN_getDataPtr((pEntity) pface , tagFaceInterface , &isp);
+      if(isMarked) EN_deleteData((pEntity) pface,tagFaceInterface); 
+    }
+    FIter_reset(fit);  
+    MD_deleteMeshDataId(tagFace);  
+    MD_deleteMeshDataId(tagFaceInterface); 
+    delete []tab;
+    delete []tabmax;
+  }
+
+#endif  
+
+}
+
+// -------------------------------------------------------------------
+// ---------------- LoadGmshParallelOld ------------------------------
+// -------------------------------------------------------------------
+/*
+void LoadGmshParallelOld (pMesh m,const char *filename,const int numproc,int version)
+{  
+  FILE *fp = fopen(filename, "r");
+  if(!fp)
+    {
+      Msg(MDB_FATAL,"Unknown File %s\n",filename);
+    }
+  char String[256];
+  //  if (!m->model)
+  m->model = new NullModel; 
+  int  Nbr_local = 0;
+  int *tabelt = NULL;
+#ifdef PARALLEL 
+  pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+#endif 
+  int nread = 0;    
+  // Interfaces NODES
+  while(1) {
+    do {
+      if(!fgets(String, sizeof(String),fp))
+        break;
+      if(feof(fp))
+        break;
+    } while(String[0] != '$' || 
+            strncmp(&String[1], "PARALLELNOD",3));
+   
+    if(feof(fp) || (nread==2)){ 
+      break;
+    }
+    else {   
+      if(!strncmp(&String[1], "PARALLELNOD", 11)) {
+        nread ++;
+        int Nbr_NodesInterfaces,Num,Nb;
+        fscanf(fp, "%d", &Nbr_NodesInterfaces);
+        for(int i_Node = 0; i_Node < Nbr_NodesInterfaces; i_Node++) {
+          fscanf(fp, "%d %d", &Num, &Nb);
+          if(Nb == 1) {
+            int nproc;
+            fscanf(fp,"%d",&nproc);
+            if(nproc == numproc) {
+              Nbr_local++;
+              m->add_point(Num,0.,0.,0.);
+            }
+          } else {
+            int *listproc=new int[Nb];
+            int ismine = 0;
+            for(int j=0 ; j < Nb ; j++) {
+              int nproc;
+              fscanf(fp,"%d",&nproc);
+              listproc[j] = nproc;
+              if(nproc == numproc) {
+                Nbr_local++;
+                ismine++;
+                m->add_point(Num,0.,0.,0.);
+              }
+            }
+#ifdef PARALLEL
+            if(ismine) {
+              std::vector<std::pair<int , MDB_Point*> > remotePoints;
+              for(int j=0 ; j < Nb ; j++) {
+                if(listproc[j]!=numproc) {
+                  (remotePoints).push_back(std::pair <int , MDB_Point*>(listproc[j],NULL));
+                }  
+              }
+              // attach remotePoints
+              assert(remotePoints.size()==(unsigned int)(Nb-1));
+              MDB_Point * vt = m->find_point(Num);
+              EN_attachDataPtr((pEntity) vt , tagData, 
+                               new std::vector<std::pair<int , MDB_Point*> >(remotePoints));
+            }
+#endif    
+            delete []listproc;
+          }
+        }
+        printf("%d Nodes in this partition\n",Nbr_local);
+        if(!Nbr_local) Nbr_local++;
+      } else if(!strncmp(&String[1], "PARALLELELM", 11)) {
+        nread++;
+        int Nbr_Elt_local = 0,Num,Nb,Nbr_Elt;
+        fscanf(fp, "%d", &Nbr_Elt);
+        tabelt = (int *) calloc(Nbr_Elt,sizeof(int));
+        for(int i = 0; i < Nbr_Elt; i++) {
+          fscanf(fp, "%d %d", &Num, &Nb);
+          tabelt[i] = -1;
+          if(Nb == 1) {
+            int nproc;
+            fscanf(fp,"%d",&nproc);
+            if(nproc == numproc) {
+              Nbr_Elt_local++;
+              tabelt[i] = Num;
+            }
+          } else {
+            int *listproc=new int[Nb];
+            for(int j=0 ; j < Nb ; j++) {
+              int nproc;
+              fscanf(fp,"%d",&nproc);
+              listproc[j] = nproc;
+              if(nproc == numproc) {
+                Nbr_Elt_local++;
+                tabelt[i] = Num;
+              }
+            }  
+            delete []listproc;
+          }
+        }
+        printf("%d Elt in this partition\n",Nbr_Elt_local);
+      }
+    }   
+  }
+
+  fseek(fp,0,SEEK_SET);
+  while(1) {
+    do {
+      if(!fgets(String, sizeof(String), fp))
+  break;
+      if(feof(fp))
+        break;
+    } while(String[0] != '$');
+    
+    if(feof(fp))
+      break;
+    
+    
+    // NODES
+    if(!strncmp(&String[1], "NOD", 3) ||
+       !strncmp(&String[1], "NOE", 3) ||
+       !strncmp(&String[1], "Nodes", 5)) {
+      
+      int Nbr_Nodes,Num,ncurc = 0;
+      double x,y,z;
+      fscanf(fp, "%d", &Nbr_Nodes);
+      for(int i_Node = 0; i_Node < Nbr_Nodes; i_Node++) {
+        fscanf(fp, "%d %lf %lf %lf", &Num, &x, &y, &z);
+  if(Nbr_local) {
+    MDB_Point * p = m->find_point(Num);
+          if(p) {
+      ncurc++;
+      p->X = x;
+      p->Y = y;
+      p->Z = z;
+    }  
+  } else {
+    m->add_point(Num,x,y,z);
+  }
+      }
+    }
+    
+    // ELEMENTS    
+    else if(!strncmp(&String[1], "ELM", 3) ||
+      !strncmp(&String[1], "Elements", 8)) {
+      int Nbr_Elements, NbTags, verts[256],Tag;
+      int Num, Type, Physical, Elementary, Nbr_Nodes, Partition;
+      fscanf(fp, "%d", &Nbr_Elements);
+      for(int i_Element = 0; i_Element < Nbr_Elements; i_Element++) {
+  
+  if(version == 1){
+    fscanf(fp, "%d %d %d %d %d",
+     &Num, &Type, &Physical, &Elementary, &Nbr_Nodes);
+    Partition = 1;
+  }
+  else{
+    fscanf(fp, "%d %d %d", &Num, &Type, &NbTags);
+    Elementary = Physical = Partition = 1;
+    for(int j = 0; j < NbTags; j++){
+      fscanf(fp, "%d", &Tag);     
+      if(j == 0)
+        Physical = Tag;
+      else if(j == 1)
+        Elementary = Tag;
+      else if(j == 2)
+        Partition = Tag;
+      // ignore any other tags for now
+    }
+    Nbr_Nodes = getNumVerticesForElementTypeMSH(Type);
+  }
+        //  int myrank;
+  //      MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+        for(int j = 0; j < Nbr_Nodes; j++)
+          fscanf(fp, "%d", &verts[j]);
+
+  GEntity *geom = 0;
+        switch (Type) {
+
+          // -------------------------------------------------------------------
+          // linear elements
+          // -------------------------------------------------------------------
+          
+        case MSH_LIN_2:
+    {
+      if(Nbr_local) {
+        if(tabelt[i_Element]>=0) {
+          if(tabelt[i_Element]!=Num) printf(" %d tab %d num %d\n",i_Element,tabelt[i_Element],Num);
+    assert(tabelt[i_Element]==Num);
+                for (int k=0;k<2;k++) assert(m->find_point(verts[k]));
+                geom = m->model->edgeByTag(Elementary);
+          m->add_edge(verts[0],verts[1],geom);  
+        }       
+      } else {
+        GEdge* geom = m->model->edgeByTag(Elementary);
+              m->add_edge(verts[0],verts[1],geom);  
+      }  
+    }
+    break;
+        case MSH_LIN_3:
+    {
+      if(Nbr_local) {
+        if(tabelt[i_Element]>=0) {
+          if(tabelt[i_Element]!=Num) printf(" %d tab %d num %d\n",i_Element,tabelt[i_Element],Num);
+    assert(tabelt[i_Element]==Num);
+                assert(m->find_point(verts[0]) && m->find_point(verts[1]) && m->find_point(verts[2]));
+                geom = m->model->edgeByTag(Elementary);
+                m->add_edge(3,geom,verts[0],verts[2],verts[1]);
+        }       
+      } else {
+        geom = m->model->edgeByTag(Elementary);
+        m->add_edge(3,geom,verts[0],verts[2],verts[1]);
+      }  
+    }
+    break;
+          
+        case MSH_LIN_4:
+    {
+      if(Nbr_local) {
+        if(tabelt[i_Element]>=0) {
+          if(tabelt[i_Element]!=Num) printf(" %d tab %d num %d\n",i_Element,tabelt[i_Element],Num);
+    assert(tabelt[i_Element]==Num);
+                assert(m->find_point(verts[0]) && m->find_point(verts[1]));
+                geom = m->model->edgeByTag(Elementary);
+        m->add_edge(4,geom, verts[0],verts[2],verts[3],verts[1]);
+        }       
+      } else {
+        geom = m->model->edgeByTag(Elementary);
+          m->add_edge(4,geom, verts[0],verts[2],verts[3],verts[1]);
+      }  
+    }
+    break;
+        case MSH_LIN_5:
+    {
+      if(Nbr_local) {
+        if(tabelt[i_Element]>=0) {
+          if(tabelt[i_Element]!=Num) printf(" %d tab %d num %d\n",i_Element,tabelt[i_Element],Num);
+    assert(tabelt[i_Element]==Num);
+                assert(m->find_point(verts[0]) && m->find_point(verts[1]));
+                geom = m->model->edgeByTag(Elementary);
+        m->add_edge(5,geom, verts[0],verts[2],verts[3],verts[4],verts[1]);
+        }       
+      } else {
+        geom = m->model->edgeByTag(Elementary);
+          m->add_edge(5,geom, verts[0],verts[2],verts[3],verts[4],verts[1]);
+      }  
+    }
+    break;
+        case MSH_LIN_6:
+    {
+      if(Nbr_local) {
+        if(tabelt[i_Element]>=0) {
+          if(tabelt[i_Element]!=Num) printf(" %d tab %d num %d\n",i_Element,tabelt[i_Element],Num);
+    assert(tabelt[i_Element]==Num);
+                assert(m->find_point(verts[0]) && m->find_point(verts[1]));
+                geom = m->model->edgeByTag(Elementary);
+        m->add_edge(6,geom, verts[0],verts[2],verts[3],verts[4],verts[5],verts[1]);
+        }       
+      } else {
+        geom = m->model->edgeByTag(Elementary);
+          m->add_edge(6,geom, verts[0],verts[2],verts[3],verts[4],verts[5],verts[1]);
+      }  
+    }
+    break;
+          
+          // -------------------------------------------------------------------
+          // TRIANGLES
+          // -------------------------------------------------------------------
+          
+        case MSH_TRI_3:
+    {
+      if(Nbr_local) {
+        if(tabelt[i_Element]>=0) {
+          assert(tabelt[i_Element]==Num);
+          assert(m->find_point(verts[0]) && m->find_point(verts[1]) && m->find_point(verts[2]));
+                 geom = m->model->faceByTag(Elementary);
+          m->add_triangle(verts[0],verts[1],verts[2],geom);   
+        }
+      } else {
+        geom = m->model->faceByTag(Elementary);
+        m->add_triangle(verts[0],verts[1],verts[2],geom);
+      }   
+    }
+    break;
+
+          // order 2 
+          
+        case MSH_TRI_6:
+    { 
+      if(Nbr_local) {
+        if(tabelt[i_Element]>=0) {
+          assert(tabelt[i_Element]==Num);
+          assert(m->find_point(verts[0]) && m->find_point(verts[1]) && m->find_point(verts[2]));
+                geom = m->model->faceByTag(Elementary);
+        m->add_triangle(2,0,geom,verts[0],verts[3],verts[1],verts[4],verts[2],verts[5]); 
+        }
+      } else {
+        geom = m->model->faceByTag(Elementary);
+          m->add_triangle(2,0,geom,verts[0],verts[3],verts[1],verts[4],verts[2],verts[5]); 
+      }   
+    }
+    break;
+
+          // order 3
+          
+        case MSH_TRI_9:
+          {       
+            if (Nbr_local) {
+              
+        if(tabelt[i_Element]>=0) {
+          assert(tabelt[i_Element]==Num);
+                for (int i=0;i<9;i++) assert(m->find_point(verts[i]));
+                geom = m->model->faceByTag(Elementary);
+                m->add_triangle(3,false,geom,verts[0],verts[3],verts[4],verts[1],verts[5],verts[6],verts[2],verts[7],verts[8]); 
+        }
+      }
+            else {
+              geom = m->model->faceByTag(Elementary);
+              m->add_triangle(3,false,geom,verts[0],verts[3],verts[4],verts[1],verts[5],verts[6],verts[2],verts[7],verts[8]); 
+      }  
+            break;
+          }
+
+          // Serendipity order 4
+          
+        case MSH_TRI_12:
+          {
+            if (Nbr_local) {
+              
+        if(tabelt[i_Element]>=0) {
+          assert(tabelt[i_Element]==Num);
+                for (int i=0;i<12;i++) assert(m->find_point(verts[i]));
+                geom = m->model->faceByTag(Elementary);
+                m->add_triangle(4,false,geom,verts[0],verts[3],verts[4],verts[5],verts[1],verts[6],verts[7],verts[8],verts[2],verts[9],verts[10],verts[11]); 
+        }
+      }
+            else {
+              geom = m->model->faceByTag(Elementary);
+              m->add_triangle(4,false,geom,verts[0],verts[3],verts[4],verts[5],verts[1],verts[6],verts[7],verts[8],verts[2],verts[9],verts[10],verts[11]); 
+      }  
+            break;
+          }
+
+          // Complete 
+          
+        case MSH_TRI_15:
+          {
+            if (Nbr_local) {
+  
+        if(tabelt[i_Element]>=0) {
+          assert(tabelt[i_Element]==Num);
+                for (int i=0;i<24;i++) assert(m->find_point(verts[i]));
+                geom = m->model->faceByTag(Elementary);
+                m->add_triangle(4,true,geom,verts[0],verts[3],verts[4],verts[5],verts[6],verts[1],verts[7],verts[8],verts[9],verts[10],verts[2],verts[11],verts[12],verts[13],verts[14]); 
+        }
+      }
+            else {
+              geom = m->model->faceByTag(Elementary);
+              m->add_triangle(4,true,geom,verts[0],verts[3],verts[4],verts[5],verts[6],verts[1],verts[7],verts[8],verts[9],verts[10],verts[2],verts[11],verts[12],verts[13],verts[14]); 
+      }
+            break;
+          }
+          
+          // -------------------------------------------------------------------
+          // Tetrahedra
+          // -------------------------------------------------------------------
+          
+          // linear
+          
+        case MSH_TET_4:
+          {
+            
+            if(Nbr_local) {
+              if(tabelt[i_Element]>=0) {
+                assert(tabelt[i_Element]==Num);
+                assert(m->find_point(verts[0]) && m->find_point(verts[1]) && m->find_point(verts[2]) &&m->find_point(verts[3]));
+                geom = m->model->regionByTag(Elementary);
+                m->add_tet(verts[0],verts[1],verts[2],verts[3],geom); 
+        }
+            } else {
+              geom = m->model->regionByTag(Elementary);
+              m->add_tet(verts[0],verts[1],verts[2],verts[3],geom); 
+            }  
+          }
+          break;
+
+          // quadratic
+          
+        case MSH_TET_10:
+          {
+            if (Nbr_local) {
+  
+        if(tabelt[i_Element]>=0) {
+          assert(tabelt[i_Element]==Num);
+                for (int i=0;i<10;i++) assert(m->find_point(verts[i]));
+                geom = m->model->regionByTag(Elementary);
+                m->add_tet(geom,2,false,verts);
+        }
+      }
+            else {
+              geom = m->model->regionByTag(Elementary);
+              m->add_tet(geom,2,false,verts);
+      }
+            break;
+          }
+          // -------------------------------------------------------------------
+          // Hexahedra
+          // -------------------------------------------------------------------
+        
+        case MSH_HEX_8:
+          {
+            
+            if(Nbr_local) { cout << "not yet implemented!!!" << endl; throw; }
+            geom = m->model->regionByTag(Elementary);
+            m->add_hex(verts[0],verts[1],verts[2],verts[3],
+                       verts[4],verts[5],verts[6],verts[7],geom); 
+          }
+          break;
+
+          // -------------------------------------------------------------------
+          // Prisms
+          // -------------------------------------------------------------------
+          
+        case MSH_PRI_6:
+          {
+            
+            if(Nbr_local) { cout << "not yet implemented!!!" << endl; throw; }
+            geom = m->model->regionByTag(Elementary);
+            m->add_prism(verts[0],verts[1],verts[2],
+                         verts[3],verts[4],verts[5],geom); 
+          }
+          break;
+          
+          // -------------------------------------------------------------------
+          // node 
+          // -------------------------------------------------------------------
+          
+        case 15:
+    {
+      if(Nbr_local) {
+        MDB_Point *p = m->find_point(verts[0]);
+        if(p) {
+          assert(tabelt[i_Element]==Num);
+          GVertex *gv = m->model->vertexByTag(Elementary);
+    p->g = gv;
+        }
+      } else {
+        geom = m->model->vertexByTag(Elementary);
+        MDB_Point *p = m->find_point(verts[0]);
+        p->g = geom;
+      }  
+    }
+    break;
+        default:
+    throw;
+        }
+  if (geom)
+    {
+      bool find = false;
+      for (std::multimap<int, pGEntity>::iterator it = m->geomFeatures_Tags.lower_bound(Physical);
+     it != m->geomFeatures_Tags.upper_bound(Physical);++it)
+        if (it->second == geom)find = true;
+      if (!find)
+        m->geomFeatures_Tags.insert(std::pair<int,pGEntity>(Physical, geom));
+    }
+      }
+    }
+    
+    do {
+      if(!fgets(String, sizeof(String), fp))
+  throw;
+      if(feof(fp))
+  throw;
+    } while(String[0] != '$');    
+  }
+
+  m->classify_unclassified_entities();
+    
+#ifdef PARALLEL   
+//   linkRemotePoints(m);
+  pMeshDataId tagVertex = MD_lookupMeshDataId("RemotePoint");
+  V_createInfoInterface(m, tagVertex);
+#endif
+}
+*/
+
diff --git a/Mesh/MeshDataBaseParallelIO.h b/Mesh/MeshDataBaseParallelIO.h
new file mode 100644
index 0000000..13b1660
--- /dev/null
+++ b/Mesh/MeshDataBaseParallelIO.h
@@ -0,0 +1,37 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _LOADPARALLELGMSHMESH_H_
+#define _LOADPARALLELGMSHMESH_H_
+
+#include "MeshDataBaseInterface.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+
+#ifdef PARALLEL
+  // Save a mesh (for parallel only) \ingroup parallel
+  //   - msh1 or msh2
+  // GCTODO: merge serial and parallel versions
+  void SaveGmshMeshParallel (const pMesh, const char *filename, int version=2);
+#endif
+
+  // Load a Gmsh mesh written in msh1 (deprecated)
+  // void LoadGmshParallelOld (pMesh, const char *, const int numproc, int version=1);
+
+  // -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Mesh/MeshDataBaseParallelInterface.cc b/Mesh/MeshDataBaseParallelInterface.cc
new file mode 100644
index 0000000..5c1ea38
--- /dev/null
+++ b/Mesh/MeshDataBaseParallelInterface.cc
@@ -0,0 +1,1737 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: J.-F. Remacle, C. Dobrzynski, K. Hillewaert, G. Compere
+// -------------------------------------------------------------------
+
+#include "assert.h"
+#include "MeshDataBase.h"
+#include "MeshDataBaseIO.h"
+#include "MSops.h"
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseParallelInterface.h"
+#include "MeshDataBaseParallelIO.h"
+#include "MeshDataBaseMessage.h"
+#include "MeshDataBaseCommCheck.h"
+#include "MeshDataBaseComm.h"
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+#endif
+
+// #include <sstream>
+// using std::ostringstream;
+// #include <fstream>
+// using std::ofstream;
+#include <set>
+#include <iterator>
+#include <algorithm>
+
+namespace MAd {
+
+  struct point_comm
+  {
+    pVertex p;     // local pointer
+    int nID;       // myrank
+    int numGlobal; // Id global for the vertex
+  };
+  
+  struct edge_comm {
+    int distProc;  // remote processor 
+    pEdge pe;      // edge 
+    pVertex p1,p2; // vertices on remote processor
+    int id1,id2;   // local identity tags
+  };  
+  
+  struct face_comm
+  {
+    int     distProc;        // remote processor 
+    pFace   pf;              // face
+    pVertex p1,p2,p3,p4;     // vertices on remote processor
+    int     id1,id2,id3,id4; // local identity tags 
+  };
+
+  // -------------------------------------------------------------------
+  /*! \brief write mesh in parallel format \ingroup internal */
+#ifdef PARALLEL
+  void M_writeParallel(pMesh m, const char * filename, int version)
+  {
+    SaveGmshMeshParallel(m, filename, version);
+  }
+#endif
+
+  // -------------------------------------------------------------------
+  /*! \brief flags true if entity pe is on a partition boundary \ingroup internal
+    \warning only valid after creation of interface exchange information (based
+    on data with tag "RemotePoint") */
+  
+  bool EN_isInterface(pEntity pe)
+  {
+    pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+    void *temp_ptr;
+    int isInterface = EN_getDataPtr(pe, tagData, &temp_ptr);
+    if (isInterface) return true;
+    return false;
+  }
+  
+  // -------------------------------------------------------------------
+  /*! \brief flags true if vertex pv is on a partition boundary \ingroup parallel
+    \warning only valid after V_createInfoInterface (based on EN_isInterface) */
+  
+  bool V_isInterface(pVertex pv) { return EN_isInterface((pEntity) pv);}
+  
+  // -------------------------------------------------------------------
+  /*! \brief flags true if edge pe is on a partition boundary \ingroup parallel
+    \warning only valid after E_createInfoInterface (based on EN_isInterface)  */
+  
+  bool E_isInterface(pEdge pe)   { return EN_isInterface((pEntity) pe);}
+  
+  // -------------------------------------------------------------------
+  /*! \brief flags true if face pf is on a partition boundary \ingroup parallel
+    \warning only valid after F_createInfoInterface  (based on EN_isInterface) */
+
+  bool F_isInterface(pFace pf)   { return EN_isInterface((pEntity) pf);}
+
+  // -------------------------------------------------------------------
+  /*!  \brief Lists all processors on which the vertex pv has a copy \ingroup internal 
+    The data with tag "RemotePoint" is created during
+    V_createInfoInterface and stores a list of pairs consisting of processor
+    id and vertex pointer
+  */
+  
+  int V_listInterface(pVertex pv, std::vector<int>* distProcs)
+  {
+    pMeshDataId tagVertex = MD_lookupMeshDataId("RemotePoint");
+    
+    void *temp_ptr;
+    int isInterface = EN_getDataPtr((pEntity) pv, tagVertex, &temp_ptr);
+    if(isInterface) {
+      const std::vector<std::pair<int,pVertex> > *recup = 
+        (const std::vector<std::pair<int,pVertex> > *) temp_ptr;
+      
+      std::set<int> parts;
+      std::vector<std::pair<int,pVertex> >::const_iterator pIter = recup->begin();
+      for (;pIter!=recup->end();++pIter) parts.insert(pIter->first);
+      
+      distProcs->insert(distProcs->begin(),parts.begin(),parts.end());
+      
+    }
+    return distProcs->size();
+  }
+  
+  // -------------------------------------------------------------------
+  /*!  \brief Returns true if the node is a (periodic) copy of the node with global id rId \ingroup internal */
+  /*! This information is based on data read with the mesh and hence will always be correct */
+  
+  bool V_corresponds(pVertex pv,int rId) 
+  {
+    if (EN_id((pEntity) pv) == rId) return true;
+    
+    pMeshDataId tagVertex = MD_lookupMeshDataId("PeriodicVertexID");
+    void* tmpptr = NULL;
+    if (!EN_getDataPtr((pEntity) pv,tagVertex,&tmpptr)) return false;
+    std::map<int,std::vector<int> >* conn = (std::map<int,std::vector<int> >*) tmpptr;
+    return (conn->find(rId) != conn->end());
+  }
+
+  // -------------------------------------------------------------------
+  
+  /*! \brief return true if the edge corresponds (possibly) \ingroup internal */
+  /*! \warning error for edges transformed onto oneself */
+  
+  bool E_corresponds(pEdge pe,int rv1,int rv2) {
+
+    pVertex pv1 = E_vertex(pe,0);
+    pVertex pv2 = E_vertex(pe,1);
+
+
+    int lv1 = EN_id((pEntity) pv1);
+    int lv2 = EN_id((pEntity) pv2);
+    
+    int lmin = std::min(lv1,lv2);
+    int lmax = std::max(lv1,lv2);
+
+    int rmin = std::min(rv1,rv2);
+    int rmax = std::max(rv1,rv2);
+
+    // identical edge - most of the cases
+    
+    if (lmin == rmin && lmax == rmax) return true;
+
+    // only one shared node -> problems
+    
+    if (lmin == rmax && lmax != rmax) return false;
+    if (lmin != rmin && lmax == rmax) return false;
+    
+    // all other cases should be ok ? (Koen)
+    
+    if (V_corresponds(pv1,rv1) && V_corresponds(pv2,rv2)) return true;
+    if (V_corresponds(pv1,rv2) && V_corresponds(pv2,rv1)) return true;
+    
+  }
+
+  // -------------------------------------------------------------------
+  /*! \brief return true if the face corresponds \ingroup internal */
+  /*! \warning not yet fully functional outside of F_createInfoInterface */
+  /*! <ul>
+      <li> we do not really verify periodic nodes 
+      <li> error for edges transformed onto oneself
+      </ul>
+  */  
+
+  bool F_corresponds(pFace pf,int rv1,int rv2,int rv3,int rv4) {
+    
+    std::set<int> lverts;
+
+    for (int i=0;i<F_numVertices(pf);i++) {
+      lverts.insert(EN_id((pEntity) F_vertex(pf,i)));
+    }
+    
+    std::set<int> rverts;
+    rverts.insert(rv1);
+    rverts.insert(rv2);
+    rverts.insert(rv3);
+    if (rv4 != -1) rverts.insert(rv4);
+    
+    // obvious checks ... 
+    if (rverts.size() != lverts.size()) return false;
+
+    // same face ... 
+    if (rverts == lverts) return true;
+
+    // only some shared nodes is not ok ? 
+    std::set<int> nonShared;
+    std::set_difference(lverts.begin(),lverts.end(),
+                        rverts.begin(),rverts.end(),
+                        std::insert_iterator< std::set<int> > (nonShared,
+                                                               nonShared.begin()));
+    
+    if (nonShared.size() != lverts.size()) return false;
+    return true;
+  }
+
+  // -------------------------------------------------------------------
+  /*!  \brief Returns true if the node is a (periodic) copy of the node with global id rId \ingroup parallel 
+    
+    This information is based on data read with the mesh and hence will always
+    be correct; only valid for check on local partition */
+  
+  bool V_corresponds(pVertex p1,pVertex p2) 
+  {
+    return (V_corresponds(p1,EN_id((pEntity) p2)) && 
+            V_corresponds(p2,EN_id((pEntity) p1)));
+  }
+
+  // --------------------------------------------------------------------
+
+  /*! \brief returns true if the node is flagged as periodic \ingroup parallel
+
+    This information is based on data read with the mesh and hence will always
+    be correct */
+
+  bool V_isPeriodic(pVertex pv) {
+    
+    pMeshDataId tagVertex = MD_lookupMeshDataId("PeriodicVertexID");
+    void* tmpptr = NULL;
+    if (!EN_getDataPtr((pEntity) pv,tagVertex,&tmpptr)) return false;
+    return true;
+  }
+    
+  // -------------------------------------------------------------------
+  /*!\brief  An edge flagged as potentially on a parallel interface  \ingroup internal
+
+    \warning the check is not correct for 2D meshes with internal edges */    
+  
+  bool E_isPotentialInterface(pMesh mesh, pEdge pe)
+  {
+    int dim = (mesh->tets.empty()) ? 2 : 3;
+
+    switch (dim) {
+    case 2:
+      {     
+      
+        // --- check that the edge has less than two neighbouring faces ---
+        
+        int numf = pe->numfaces();
+        if( numf == 2 ) return false;
+        
+        // --- check that the edge is not alone or
+        //     with multiple neighbouring faces (debug) ---
+        
+        assert(numf == 1);
+        return true;
+        
+        // KH: for the moment an edge is always classified on an edge ... (nullmodel)
+        //     hence the following check is not usable ... 
+        /// 
+        // if edge is classified on an edge, still two possibilities
+        // 
+        //   1. periodic edge: check whether or not nodes are periodic - ok
+        //   2. internal edge: not yet treated correctly
+        
+        
+        if ( E_whatInType(pe) == 1 ) {
+          for (int i=0;i<2;i++) if (!V_isPeriodic(E_vertex(pe,i))) return false;
+          return true;
+        }
+        
+      
+        break;
+      }
+    case 3:
+      {
+        // --- check that the edge has at least one neighbouring face that is potentially shared ---
+        
+        int numf = pe->numfaces();
+        for (int iF=0; iF < numf; iF++) {
+          if ( F_isPotentialInterface(mesh,E_face(pe,iF))) return true;
+        }
+        break;
+      }
+    }
+
+    return false;
+  }
+  
+  // -------------------------------------------------------------------
+
+//   bool E_isInterface(pMesh mesh, pEdge pe, int * distProc, 
+//                      std::vector<pVertex>* distVt)
+//   {
+//     if (distProc) *distProc = -1;
+//     if (distVt)   (*distVt).clear();
+
+//     if ( !E_isPotentialInterface(mesh,pe) ) return false;
+
+//     // GCREMARK: the rest of the function gives informations about the 
+//     //           distant partition(s) but is just a cross-check.
+
+//     // --- check that the two nodes are on a parallel boundary ---
+//     // KHREMARK :
+//     // - this is not conclusive, we should verify that the edge exists on the other partitions
+//     // - on the other hand, if the edge is possibly on more than two partitions,
+//     //   we will not flag all remote partitions
+  
+//     pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+//     pVertex pv1 = pe->p1;
+//     pVertex pv2 = pe->p2;
+//     void * temp_ptr1, *temp_ptr2;
+//     int isInterface1 = EN_getDataPtr((pEntity) pv1 , tagData, &temp_ptr1);
+//     int isInterface2 = EN_getDataPtr((pEntity) pv2 , tagData, &temp_ptr2);
+//     if( !(isInterface1 && isInterface2) ) {
+//       Msg(MDB_FATAL,"Error: found an edge which nodes are not both on a parallel boundary although it fits the conditions to be a parallel boundary edge\n");
+//     }
+
+//     // --- check that the two nodes are on the same parallel boundary ---
+//     const std::vector<std::pair<int,pVertex> > *recup1 = 
+//       (const std::vector<std::pair<int,pVertex> > *) temp_ptr1;
+//     const std::vector<std::pair<int,pVertex> > *recup2 = 
+//       (const std::vector<std::pair<int,pVertex> > *) temp_ptr2;
+        
+//     std::vector<std::pair<int,pVertex> >::const_iterator rIter1 = recup1->begin();
+//     std::vector<std::pair<int,pVertex> >::const_iterator rIter2 = recup2->begin();
+        
+//     for (; rIter1 != recup1->end(); rIter1++) {
+//       for (; rIter2 != recup2->end(); rIter2++) {
+//         if ( (*rIter1).first == (*rIter2).first ) {
+//           if (distProc) *distProc = (*rIter1).first;
+//           if (distVt) {
+//             (*distVt).clear();
+//             (*distVt).push_back((*rIter1).second);
+//             (*distVt).push_back((*rIter2).second);
+//           }
+//           return true;
+//         }
+//       }
+//       rIter2 = recup2->begin();
+//     }
+
+//     Msg(MDB_FATAL,"Error: found an edge which nodes have no common parallel boundary although it fits the conditions to be a parallel boundary edge\n");
+
+//     return false;
+//   }
+
+
+  // ---------------------------------------------------------------------------
+  /*!\brief Verifies whether edge pe is located at a parallel interface boundary 
+    and provides information about all possible copies \ingroup internal */
+  
+  bool E_isPotentialInterface(pMesh mesh, pEdge pe, std::vector<edge_comm>& distVt)
+
+  {
+    distVt.clear();
+    
+    if ( !E_isPotentialInterface(mesh,pe) ) return false;
+
+    pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+    pVertex pv1 = pe->p1;
+    pVertex pv2 = pe->p2;
+    void * temp_ptr1, *temp_ptr2;
+    int isInterface1 = EN_getDataPtr((pEntity) pv1 , tagData, &temp_ptr1);
+    int isInterface2 = EN_getDataPtr((pEntity) pv2 , tagData, &temp_ptr2);
+  
+    if( !(isInterface1 && isInterface2) ) return false;
+
+    // --- check that the two nodes are on the same parallel boundary ---
+    const std::vector<std::pair<int,pVertex> > *recup1 = 
+      (const std::vector<std::pair<int,pVertex> > *) temp_ptr1;
+    const std::vector<std::pair<int,pVertex> > *recup2 = 
+      (const std::vector<std::pair<int,pVertex> > *) temp_ptr2;
+
+    std::vector<std::pair<int,pVertex> >::const_iterator rIter1 = recup1->begin();
+    std::vector<std::pair<int,pVertex> >::const_iterator rIter2 = recup2->begin();
+  
+    for (; rIter1 != recup1->end(); rIter1++) {
+      for (; rIter2 != recup2->end(); rIter2++) {  
+        if ( (*rIter1).first == (*rIter2).first ) {
+          edge_comm ee;
+          ee.distProc = (*rIter1).first;
+          ee.p1 = (*rIter1).second;
+          ee.p2 = (*rIter2).second;
+          ee.id1 = EN_id((pEntity) E_vertex(pe,0));
+          ee.id2 = EN_id((pEntity) E_vertex(pe,1));
+          ee.pe = pe;
+          distVt.push_back(ee);
+        }
+      }
+      rIter2 = recup2->begin();
+    }
+    return (!distVt.empty());
+  }
+
+  // -------------------------------------------------------------------
+  /*! \brief Verify whether pf may potentially be an interface \ingroup internal 
+    \warning will flag false for internal boundaries !!! */ 
+  
+  // -------------------------------------------------------------------
+
+  bool F_isPotentialInterface(pMesh mesh, pFace pf)
+  {
+    // bool check = true;
+    //     for (size_t i=0;i<F_numVertices(pf);i++) check = check && V_isInterface(F_vertex(pf,i));
+    //     return check;
+
+    // --- check that the mesh is 3D ---
+
+    if (mesh->tets.empty()) return false;
+  
+    // --- check that the face has less than two neighbouring regions ---
+
+    int numtet = pf->getNbRegions();
+    if (numtet == 2) return false;
+    return true;
+
+    // OK : for the moment a face is always classified on a geometric face (nullmodel ...)
+    
+    // --- if the face is classified on a topological face, we can still have 
+    //     1. a periodic face: all nodes are periodic - ok
+    //     2. an internal boundary - check is not ok 
+    
+    int modelDim = GEN_type(pf->g);
+
+    if (modelDim == 2) {
+      for (int i=0;i<F_numVertices(pf);i++) {
+        if (!V_isPeriodic(F_vertex(pf,i))) return false;
+      }
+      return true;
+    }
+    
+    // --- check that the face is not alone (debug) ---
+    assert(numtet);
+    return true;
+  }
+
+
+  // -------------------------------------------------------------------
+#ifdef PARALLEL
+  // bool F_isInterface(pMesh mesh, pFace pface, int * distProc,
+  //                    std::vector<pVertex>* distVt)
+  // {
+  //   if (distProc) *distProc = -1;
+  //   if (distVt)   (*distVt).clear();
+
+  //   if ( !F_isInterface(mesh,pface) ) return false;
+
+  //   // GCREMARK: the rest of the function gives informations about the 
+  //   //           distant partition but is just a cross-check.
+
+  //   // --- check that the three nodes are on a parallel boundary ---
+  //   pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+  //   pVertex nod[4];
+
+
+  //   switch (pface->getNbNodes()) {
+
+  //   case 3:
+  //     {
+  //       pface->getNodes(nod);
+  //       void * temp_ptr1, *temp_ptr2, *temp_ptr3;
+  //       int isInterface1 = EN_getDataPtr((pEntity) nod[0], tagData, &temp_ptr1);
+  //       int isInterface2 = EN_getDataPtr((pEntity) nod[1], tagData, &temp_ptr2);
+  //       int isInterface3 = EN_getDataPtr((pEntity) nod[2], tagData, &temp_ptr3);
+      
+      
+  //       if( !(isInterface1 && isInterface2 && isInterface3) ) {
+  //         Msg(MDB_FATAL,"Error: found a face which nodes are not all on a parallel boundary although it fits the conditions to be a parallel boundary face\n");
+  //       }
+      
+  //       // --- check that the three nodes are on the same parallel boundary ---
+  //       const std::vector<std::pair<int,pVertex> > *recup1 = 
+  //         (const std::vector<std::pair<int,pVertex> > *) temp_ptr1;
+  //       const std::vector<std::pair<int,pVertex> > *recup2 = 
+  //         (const std::vector<std::pair<int,pVertex> > *) temp_ptr2;
+  //       const std::vector<std::pair<int,pVertex> > *recup3 = 
+  //         (const std::vector<std::pair<int,pVertex> > *) temp_ptr3;
+  //       std::vector<std::pair<int,pVertex> >::const_iterator rIter1 = recup1->begin();
+  //       std::vector<std::pair<int,pVertex> >::const_iterator rIter2 = recup2->begin();
+  //       std::vector<std::pair<int,pVertex> >::const_iterator rIter3 = recup3->begin();
+  //       for (; rIter1 != recup1->end(); rIter1++) {
+  //         for (; rIter2 != recup2->end(); rIter2++) {
+  //           for (; rIter3 != recup3->end(); rIter3++) {
+  //             if ( (*rIter1).first == (*rIter2).first &&
+  //                  (*rIter2).first == (*rIter3).first ) {
+  //               if (distProc) *distProc = (*rIter1).first;
+  //               if (distVt) {
+  //                 (*distVt).push_back((*rIter1).second);
+  //                 (*distVt).push_back((*rIter2).second);
+  //                 (*distVt).push_back((*rIter3).second);
+  //               }
+  //               return true;
+  //             }
+  //           }
+  //           rIter3 = recup3->begin();
+  //         }
+  //         rIter2 = recup2->begin();
+  //       }
+  //       break;
+  //     }
+    
+  //   case 4:
+  //     {
+  //       pface->getNodes(nod);
+  //       void * temp_ptr1, *temp_ptr2, *temp_ptr3, *temp_ptr4;
+  //       int isInterface1 = EN_getDataPtr((pEntity) nod[0], tagData, &temp_ptr1);
+  //       int isInterface2 = EN_getDataPtr((pEntity) nod[1], tagData, &temp_ptr2);
+  //       int isInterface3 = EN_getDataPtr((pEntity) nod[2], tagData, &temp_ptr3);
+  //       int isInterface4 = EN_getDataPtr((pEntity) nod[3], tagData, &temp_ptr4);
+      
+    
+  //       if( !(isInterface1 && isInterface2 && isInterface3 && isInterface4) ) {
+  //         Msg(MDB_FATAL,"Error: found a face which nodes are not all on a parallel boundary although it fits the conditions to be a parallel boundary face\n");
+  //       }
+    
+  //       // --- check that the three nodes are on the same parallel boundary ---
+  //       const std::vector<std::pair<int,pVertex> > *recup1 = 
+  //         (const std::vector<std::pair<int,pVertex> > *) temp_ptr1;
+  //       const std::vector<std::pair<int,pVertex> > *recup2 = 
+  //         (const std::vector<std::pair<int,pVertex> > *) temp_ptr2;
+  //       const std::vector<std::pair<int,pVertex> > *recup3 = 
+  //         (const std::vector<std::pair<int,pVertex> > *) temp_ptr3;
+  //       const std::vector<std::pair<int,pVertex> > *recup4 = 
+  //         (const std::vector<std::pair<int,pVertex> > *) temp_ptr4;
+  //       std::vector<std::pair<int,pVertex> >::const_iterator rIter1 = recup1->begin();
+  //       std::vector<std::pair<int,pVertex> >::const_iterator rIter2 = recup2->begin();
+  //       std::vector<std::pair<int,pVertex> >::const_iterator rIter3 = recup3->begin();
+  //       std::vector<std::pair<int,pVertex> >::const_iterator rIter4 = recup4->begin();
+  //       for (; rIter1 != recup1->end(); rIter1++) {
+  //         for (; rIter2 != recup2->end(); rIter2++) {
+  //           for (; rIter3 != recup3->end(); rIter3++) {
+  //             for (; rIter4 != recup4->end(); rIter4++) {
+  //               if ( (*rIter1).first == (*rIter2).first &&
+  //                    (*rIter2).first == (*rIter3).first &&
+  //                    (*rIter3).first == (*rIter4).first ) {
+  //                 if (distProc) *distProc = (*rIter4).first;
+  //                 if (distVt) {
+  //                   (*distVt).push_back((*rIter1).second);
+  //                   (*distVt).push_back((*rIter2).second);
+  //                   (*distVt).push_back((*rIter3).second);
+  //                   (*distVt).push_back((*rIter4).second);
+  //                 }
+  //                 return true;
+  //               }
+  //             }
+  //             rIter4 = recup4->begin();
+  //           }
+  //           rIter3 = recup3->begin();
+  //         }
+  //         rIter2 = recup2->begin();
+  //       }
+  //       break;
+  //     }
+  //   }
+    
+  //   Msg(MDB_FATAL,"Error: found a face which nodes have no common parallel boundary although it fits the conditions to be a parallel boundary face\n");
+
+  //   return false;
+  // }
+
+#endif
+
+  /*! \brief flag face pface as potential interface and list possible communications \ingroup internal */
+
+  bool F_isPotentialInterface(pMesh mesh, pFace pface, std::vector<face_comm>& distFace)
+  {
+
+    if ( !F_isPotentialInterface(mesh,pface) ) return false;
+
+    // GCREMARK: the rest of the function gives informations about the 
+    //           distant partition but is just a cross-check.
+
+    // --- check that the three nodes are on a parallel boundary ---
+    pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+    pVertex nod[4];
+
+    distFace.clear();
+
+
+    switch (pface->getNbNodes()) {
+
+    case 3:
+      {
+        pface->getNodes(nod);
+        void * temp_ptr1, *temp_ptr2, *temp_ptr3;
+        int isInterface1 = EN_getDataPtr((pEntity) nod[0], tagData, &temp_ptr1);
+        int isInterface2 = EN_getDataPtr((pEntity) nod[1], tagData, &temp_ptr2);
+        int isInterface3 = EN_getDataPtr((pEntity) nod[2], tagData, &temp_ptr3);
+      
+        int id1 = EN_id((pEntity) nod[0]);
+        int id2 = EN_id((pEntity) nod[1]);
+        int id3 = EN_id((pEntity) nod[2]);
+
+        if( !(isInterface1 && isInterface2 && isInterface3) ) {
+          return false;
+          //Msg(MDB_FATAL,"Error: found a face which nodes are not all on a parallel boundary although it fits the conditions to be a parallel boundary face\n");
+        }
+      
+        // --- check that the three nodes are on the same parallel boundary ---
+        const std::vector<std::pair<int,pVertex> > *recup1 = 
+          (const std::vector<std::pair<int,pVertex> > *) temp_ptr1;
+        const std::vector<std::pair<int,pVertex> > *recup2 = 
+          (const std::vector<std::pair<int,pVertex> > *) temp_ptr2;
+        const std::vector<std::pair<int,pVertex> > *recup3 = 
+          (const std::vector<std::pair<int,pVertex> > *) temp_ptr3;
+        std::vector<std::pair<int,pVertex> >::const_iterator rIter1 = recup1->begin();
+        std::vector<std::pair<int,pVertex> >::const_iterator rIter2 = recup2->begin();
+        std::vector<std::pair<int,pVertex> >::const_iterator rIter3 = recup3->begin();
+        for (; rIter1 != recup1->end(); rIter1++) {
+          for (; rIter2 != recup2->end(); rIter2++) {
+            for (; rIter3 != recup3->end(); rIter3++) {
+              if ( (*rIter1).first == (*rIter2).first &&
+                   (*rIter2).first == (*rIter3).first ) {
+
+                face_comm fc;
+              
+                fc.distProc = (*rIter1).first;
+
+                fc.p1 = (*rIter1).second;
+                fc.p2 = (*rIter2).second;
+                fc.p3 = (*rIter3).second;
+                fc.p4 = NULL;
+                
+                fc.id1 = id1;
+                fc.id2 = id2;
+                fc.id3 = id3;
+                fc.id4 = -1;
+
+                fc.pf = pface;
+              
+                distFace.push_back(fc);
+              }
+            }
+            rIter3 = recup3->begin();
+          }
+          rIter2 = recup2->begin();
+        }
+        break;
+      }
+    
+    case 4:
+      {
+        pface->getNodes(nod);
+        void * temp_ptr1, *temp_ptr2, *temp_ptr3, *temp_ptr4;
+        int isInterface1 = EN_getDataPtr((pEntity) nod[0], tagData, &temp_ptr1);
+        int isInterface2 = EN_getDataPtr((pEntity) nod[1], tagData, &temp_ptr2);
+        int isInterface3 = EN_getDataPtr((pEntity) nod[2], tagData, &temp_ptr3);
+        int isInterface4 = EN_getDataPtr((pEntity) nod[3], tagData, &temp_ptr4);
+        
+        int id1 = EN_id((pEntity) nod[0]);
+        int id2 = EN_id((pEntity) nod[1]);
+        int id3 = EN_id((pEntity) nod[2]);
+        int id4 = EN_id((pEntity) nod[3]);
+    
+        if( !(isInterface1 && isInterface2 && isInterface3 && isInterface4) ) {
+          Msg(MDB_FATAL,"Error: found a face which nodes are not all on a parallel boundary although it fits the conditions to be a parallel boundary face\n");
+        }
+    
+        // --- check that the three nodes are on the same parallel boundary ---
+        const std::vector<std::pair<int,pVertex> > *recup1 = 
+          (const std::vector<std::pair<int,pVertex> > *) temp_ptr1;
+        const std::vector<std::pair<int,pVertex> > *recup2 = 
+          (const std::vector<std::pair<int,pVertex> > *) temp_ptr2;
+        const std::vector<std::pair<int,pVertex> > *recup3 = 
+          (const std::vector<std::pair<int,pVertex> > *) temp_ptr3;
+        const std::vector<std::pair<int,pVertex> > *recup4 = 
+          (const std::vector<std::pair<int,pVertex> > *) temp_ptr4;
+        std::vector<std::pair<int,pVertex> >::const_iterator rIter1 = recup1->begin();
+        std::vector<std::pair<int,pVertex> >::const_iterator rIter2 = recup2->begin();
+        std::vector<std::pair<int,pVertex> >::const_iterator rIter3 = recup3->begin();
+        std::vector<std::pair<int,pVertex> >::const_iterator rIter4 = recup4->begin();
+        for (; rIter1 != recup1->end(); rIter1++) {
+          for (; rIter2 != recup2->end(); rIter2++) {
+            for (; rIter3 != recup3->end(); rIter3++) {
+              for (; rIter4 != recup4->end(); rIter4++) {
+                if ( (*rIter1).first == (*rIter2).first &&
+                     (*rIter2).first == (*rIter3).first &&
+                     (*rIter3).first == (*rIter4).first ) {
+                
+                  face_comm fc;
+                
+                  fc.distProc = (*rIter1).first;
+
+                  fc.p1 = (*rIter1).second;
+                  fc.p2 = (*rIter1).second;
+                  fc.p3 = (*rIter2).second;
+                  fc.p4 = (*rIter3).second;
+                  
+                  fc.id1 = id1;
+                  fc.id2 = id2;
+                  fc.id3 = id3;
+                  fc.id4 = id4;
+
+                  fc.pf = pface;
+                
+                  distFace.push_back(fc);
+                
+                }
+              }
+              rIter4 = recup4->begin();
+            }
+            rIter3 = recup3->begin();
+          }
+          rIter2 = recup2->begin();
+        }
+        break;
+      }
+    }
+    
+    // Msg(MDB_FATAL,"Error: found a face which nodes have no common parallel boundary although it fits the conditions to be a parallel boundary face\n");
+
+    return (distFace.size() != 0);
+  }
+
+  // -------------------------------------------------------------------
+  /*! \brief Flag region if located at an interface. \ingroup parallel
+    \warning As we partition along edges in 2D and faces in 3D, the answer is
+    always no  */
+
+  bool R_isInterface(pRegion pr) {
+    return false;
+  }
+
+  // -------------------------------------------------------------------
+  // do a tentative connection - since we send all potential interface nodes
+  // to all processors, we send the minimum information : the node id 
+  // 
+  // result is that we store the connected partitions for a shared node
+  // more detailed communication follows 
+  
+  
+  void createRemotePointLists (pMesh mesh, pMeshDataId tagVertex)
+  {
+    int myrank = 0;
+    int nbproc = 1;
+    
+    std::set<pVertex> bdryNodes;
+    std::set<int>     bdryNodeId;
+
+#ifdef PARALLEL
+    MPI_Comm_size(MPI_COMM_WORLD, &nbproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+    // --- list local nodes on parallel boundaries ---
+    
+    int meshDim = (mesh->tets.empty()) ? 2 : 3;
+    if ( meshDim == 3 ) {
+      FIter fit = M_faceIter(mesh);
+      while ( pFace pf = FIter_next(fit) ) {
+        if ( F_isPotentialInterface(mesh,pf) ) {
+          for (int iv = 0; iv < F_numVertices(pf); iv++) {
+            pVertex pv = F_vertex(pf,iv);
+            bdryNodes .insert(pv);
+            bdryNodeId.insert(pv->iD);
+          }
+        }
+      }
+    } else {
+      EIter eit = M_edgeIter(mesh);
+      while ( pEdge pe = EIter_next(eit) ) {
+        if ( E_isPotentialInterface(mesh,pe) ) {
+          for (int iv = 0; iv < 2; iv++) {
+            pVertex pv = E_vertex(pe,iv);            
+            bdryNodes.insert(pv);
+            bdryNodeId.insert(pv->iD);
+          }
+        }
+      }
+    }
+#endif
+
+    /* KH : temporary ? addition of all periodic nodes */ 
+    
+    pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicVertexID");  
+    
+    VIter vit = M_vertexIter(mesh);
+    
+    while (pVertex pv = VIter_next(vit)) {
+      
+      void* tmp_periodic = NULL;
+      int isPeriodic = EN_getDataPtr((pEntity) pv,tagPeriodic,&tmp_periodic);
+
+      if (isPeriodic) {
+      
+        void* tmp_remote = NULL;
+        int hasRemote  = EN_getDataPtr((pEntity) pv,tagVertex,&tmp_remote);
+        
+        if (!hasRemote) {
+          std::vector<std::pair<int,pVertex> >* remote = new std::vector<std::pair<int,pVertex> >;
+          EN_attachDataPtr((pEntity) pv,tagVertex,remote);
+        }
+        else {
+          std::vector<std::pair<int,pVertex> >* remote = (std::vector<std::pair<int,pVertex> >*) tmp_remote;
+          remote->clear();
+        }
+        
+        std::map<int,std::vector<int> > * conn = (std::map<int,std::vector<int> > *) tmp_periodic;
+        std::map<int,std::vector<int> >::iterator citer = conn->begin();
+        bdryNodes.insert(pv);
+        for (;citer != conn->end();++citer) bdryNodeId.insert(citer->first);
+      }
+    }
+    
+#ifdef PARALLEL
+    MPI_Barrier(MPI_COMM_WORLD);
+    
+    // --- send list ---
+    
+    int* sendcounts = new int[nbproc];
+    int size = bdryNodeId.size()*sizeof(int);
+    
+    void* msg = malloc(size);
+    int * bufCast = reinterpret_cast<int *>(msg);
+    std::set<int>::const_iterator cIter = bdryNodeId.begin();
+    std::set<int>::const_iterator cLast = bdryNodeId.end();
+    for (;cIter!=cLast;++cIter) *(bufCast++) = *cIter;
+    
+    for (int iProcDest=0; iProcDest < nbproc; iProcDest++) {
+      if ( iProcDest == myrank ) {
+        sendcounts[iProcDest] = 0;
+        continue;    
+      }
+      else {
+        sendcounts[iProcDest] = 1;
+        void *buf = AP_alloc(iProcDest,669,size);
+        memcpy(buf,msg,size);
+        AP_send(buf);
+      }
+    }
+
+    free(msg);
+
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+    AP_flush();
+
+    // --- receive lists ---
+
+    int message = 0;
+    int count;
+    while (!AP_recv_count(&count) || message < count) {
+
+      void *msg;
+      int from;
+      int tag;
+      int size;
+      int rc;
+    
+      rc = AP_recv (MPI_ANY_SOURCE, 669, AP_BLOCKING|AP_DROPOUT,
+                    &msg, &size, &from, &tag);
+    
+      if (rc) {
+    
+        int* msgCast = reinterpret_cast<int*>(msg);
+
+        std::set<int> distNodes;
+        int nbDistNodes = size / sizeof(int);
+        for (int iDistN = 0; iDistN < nbDistNodes; iDistN++) {
+          distNodes.insert(msgCast[iDistN]);
+        }
+        
+        std::set<pVertex>::const_iterator vIter = bdryNodes.begin();
+        std::set<pVertex>::const_iterator vLast = bdryNodes.end();
+        
+        for (;vIter!=vLast;++vIter) {
+
+          pVertex pv = *vIter;
+          int     id = EN_id((pEntity) pv);
+
+          if (distNodes.find(id) != distNodes.end()) {
+            void *temp_ptr;
+            int exist = EN_getDataPtr((pEntity) pv, tagVertex, &temp_ptr);
+            std::vector<std::pair<int,pVertex> > * parts = NULL;
+            if (exist) {
+              parts = reinterpret_cast<std::vector<std::pair<int,pVertex> >*>(temp_ptr);
+            } else if (!exist) {
+              parts = new std::vector<std::pair<int,pVertex> >;
+              EN_attachDataPtr((pEntity) pv, tagVertex, parts);
+            }
+            parts->push_back(std::pair <int, MDB_Point*>(from,NULL));
+          }
+        } 
+        message++;
+        AP_free(msg);
+      }
+    }
+    
+    // --- wait until all have finished sending ---
+  
+    AP_check_sends(AP_WAITALL);
+    delete [] sendcounts;
+    
+    // GCDEBUG
+    //   MPI_Barrier(MPI_COMM_WORLD);
+#endif
+  }
+  
+  // -------------------------------------------------------------------
+  
+  void V_createInfoInterface(pMesh mesh, pMeshDataId tagVertex)
+  {
+        
+    int mysize = 1;
+    int myrank = 0;
+
+    size_t nbConnections = 0;
+    
+#ifdef PARALLEL
+    MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+#endif
+
+    // --- Delete previous information ---
+    VIter vit = M_vertexIter(mesh);
+    while ( pVertex pv = VIter_next(vit) ) {
+      void * tmp_ptr;
+      if( EN_getDataPtr((pEntity) pv, tagVertex, &tmp_ptr) ) {
+        EN_deleteData((pEntity) pv, tagVertex);
+      }
+    }
+    VIter_delete(vit);
+
+    // --- Create lists of distant procs ---
+
+    createRemotePointLists(mesh, tagVertex);
+
+    // --- Send node pointers ---
+    int *sendcounts = new int[mysize];
+    for(int i=0; i<mysize; i++) sendcounts[i] = 0;
+    
+    pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicVertexID");
+    pMeshDataId tagTransfo  = MD_lookupMeshDataId("PeriodicTransformation");
+  
+    vit = M_vertexIter(mesh);
+    while ( pVertex pv = VIter_next(vit) ) {
+
+      std::vector<int> distProcTab;
+      int nbDistProc = V_listInterface(pv, &distProcTab);
+
+      std::set<int> distProcs;
+      distProcs.insert(distProcTab.begin(),distProcTab.end());
+      
+      void* tmp_remote = NULL;
+      int haveRemote = EN_getDataPtr((pEntity) pv,tagVertex,&tmp_remote);
+      std::vector<std::pair<int,pVertex> >* remote = NULL;
+      if (haveRemote) {
+        remote  = (std::vector<std::pair<int,pVertex> >*) (tmp_remote);
+        remote->clear();
+      }
+      
+      void* tmp_periodic = NULL;
+      int havePeriodic = EN_getDataPtr((pEntity) pv,tagPeriodic,&tmp_periodic);
+      std::map<int,std::vector<int> >* periodic = NULL;
+
+      if (havePeriodic) {
+        
+        if (!haveRemote) {
+          Msg_char(MDB_FATAL,"Periodic node %d without connection table",EN_id((pEntity) pv));
+        }
+        
+        // allocate and attach transformation table 
+        
+        //         int haveTransfo = EN_getDataPtr((pEntity) cvtx, tagTransfo, &tmp_transfo);
+        //         std::map<std::pair<int,pEntity>,std::vector<int> >* trafo = NULL; 
+        //         if (haveTransfo) {
+        //           trafo = (std::map<std::pair<int,pEntity>,std::vector<int> > *) tmp_transfo;
+        //           trafo->clear();
+        //         } 
+        //         else {
+        //           trafo = new std::map<std::pair<int,pEntity>,std::vector<int> >;
+        //           EN_attachDataPtr((pEntity) cvtx,periodicTransfoTag,trafo);
+        //         }
+        
+        // insert data on local processor
+        
+        periodic = (std::map<int,std::vector<int> >*) tmp_periodic;
+        std::map<int,std::vector<int> >::const_iterator citer = periodic->begin();
+        for (;citer!=periodic->end();++citer) {
+          pVertex cvtx = mesh->find_point(citer->first);
+          if (cvtx && cvtx != pv) {
+            remote->push_back(std::make_pair(myrank,cvtx));
+            nbConnections++;
+            //     trafo->insert(std::make_pair(std::make_pair(myRank,cvtx),citer->second));
+          }
+        }
+      }
+      
+#ifdef PARALLEL
+      
+      int nbConnections = 1;
+      if (periodic) nbConnections += periodic->size();
+      int msgSize = sizeof(pVertex) + (3 + nbConnections ) * sizeof(int);
+      void* tmp = malloc(msgSize);
+      
+      pVertex *vbuf = (pVertex *) tmp;
+
+      int lId = EN_id((pEntity) pv);
+      
+      *(vbuf++) = pv;
+      int* iv = (int*) (vbuf);
+      
+      *(iv++) = GEN_tag (V_whatIn(pv));
+      *(iv++) = GEN_type(V_whatIn(pv));
+      *(iv++) = nbConnections;
+      *(iv++) = lId;
+      
+      if (periodic) {
+        std::map<int,std::vector<int> >::const_iterator cIter = periodic->begin();
+        for (;cIter!=periodic->end();++cIter) {
+          int rId = cIter->first;
+          *(iv++) = (rId == lId) ? -rId : rId; // avoid sending once again to oneself
+        }
+      }
+      
+      // make sure that we send only once to different processors
+
+      std::set<int>::iterator dIter = distProcs.begin();
+      for (;dIter!=distProcs.end();++dIter) {
+
+        int distProc = *dIter;
+        if (distProc != myrank) {    
+          void *buf = AP_alloc(distProc,445,msgSize);
+          memcpy(buf,tmp,msgSize);
+          AP_send(buf);
+          sendcounts[distProc]++;
+        }
+      }
+      
+      free(tmp);
+#endif
+    }
+    VIter_delete(vit);
+    
+#ifdef PARALLEL
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+    AP_flush();
+
+    // --- Receive node pointers ---
+    int message=0, count;
+    while (!AP_recv_count(&count) || message<count) {
+      
+      void *msg;
+      int  from;
+      int  tag;
+      int  size;
+      int  recv;
+      
+      recv = AP_recv(MPI_ANY_SOURCE, 445, AP_BLOCKING|AP_DROPOUT,
+                     &msg, &size, &from, &tag);
+      if(recv) {
+        
+        message++;
+        pVertex* vbuf = reinterpret_cast<pVertex*>(msg);
+        pVertex precv = *(vbuf++);
+        int* ibuf = reinterpret_cast<int*>(vbuf);
+        
+        int gTag   = *(ibuf++);
+        int gDim   = *(ibuf++);
+        int nbConn = *(ibuf++);
+        
+        
+        for (int iConn=0;iConn<nbConn;iConn++) {
+          
+          int pId = *(ibuf++);
+          pVertex vtx = mesh->find_point(pId);
+          
+          if (vtx) {     
+            
+            void* tmp_remote =  NULL;
+            int isInterface = EN_getDataPtr((pEntity) vtx, tagVertex, &tmp_remote);
+            assert(isInterface);
+            std::vector<std::pair<int,pVertex> > *remote = (std::vector<std::pair<int,pVertex> >*) tmp_remote;  
+            remote->push_back(std::pair<int,pVertex>(from,precv));
+            
+          }
+        }
+        AP_free(msg);
+      }
+    }
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    delete [] sendcounts;
+
+#endif
+    
+    MDB_CommCheck cc;
+    exchangeDataOnVertices(mesh,cc);
+
+  }
+  
+//   // -------------------------------------------------------------------
+// #ifdef PARALLEL
+//   void MDB_Mesh::bdryLinkRemotePoint()
+//   {
+//     int mysize,myrank;
+//     MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+//     MPI_Comm_rank(MPI_COMM_WORLD, &myrank);   
+
+//     /*send pointeurs*/
+//     int *sendcounts = new int[mysize];
+//     for(int i=0;i<mysize;i++)sendcounts[i]=0;
+  
+//     pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+//     VIter vit = M_vertexIter(this);
+//     pVertex pv;  
+//     int nsend=0;
+//     while ((pv = VIter_next(vit))) {
+//       void *temp_ptr; 
+//       int isInterface = EN_getDataPtr((pEntity) pv , tagData, &temp_ptr);
+    
+//       if(isInterface) {
+//         std::vector<std::pair<int , MDB_Point*> > *recup = (std::vector<std::pair<int , MDB_Point*> > *) temp_ptr;
+//         int numGlobal = EN_id((pEntity)pv);
+//         for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+//           nsend++;
+//           int remoteID  = (*recup)[j].first;
+//           assert(remoteID != myrank);
+//           void *buf = AP_alloc(remoteID,444,sizeof(point_comm));
+//           point_comm *castbuf = (point_comm *) buf;
+//           castbuf->p         = pv;
+//           castbuf->nID       = myrank;
+//           castbuf->numGlobal = numGlobal;
+//           AP_send(buf);
+//           sendcounts[remoteID]++;   
+//         }
+//       }
+//     }	
+//     VIter_delete(vit);   
+
+//     AP_flush();
+//     AP_check_sends(AP_NOFLAGS);
+//     // AP_reduce_nsends(sendcounts);
+
+//     /*receive pointers*/
+//     int message=0;
+//     // while (!AP_recv_count(&count) || message<count) {
+//     while (message<nsend) {
+//       void *msg;
+//       int  from;
+//       int  tag;
+//       int  size;
+//       int  recv;
+//       recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+//                      &msg, &size, &from, &tag);
+//       if(recv) {
+//         message++;
+//         point_comm * castbuf = (point_comm*) msg;
+//         pVertex precv (0);
+//         precv = castbuf -> p;
+//         assert(precv);
+//         int recvID = castbuf -> nID;
+//         int numrecv = castbuf -> numGlobal;
+      
+//         pVertex p = this->find_point(numrecv);
+//         if(p) {
+//           void *temp_ptr; 
+//           int isInterface = EN_getDataPtr((pEntity) p , tagData, &temp_ptr);
+//           assert(isInterface);
+//           std::vector<std::pair<int , MDB_Point*> > *recup = 
+//             (std::vector<std::pair<int , MDB_Point*> > *) temp_ptr;
+//           for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+//             int remoteID  = (*recup)[j].first;
+//             if(remoteID == recvID) {
+//               (*recup)[j].second = precv;
+//             }
+//           }  
+//         }
+//         AP_free(msg);
+//       }		   
+   
+//     }
+//     AP_check_sends(AP_WAITALL);
+//     MPI_Barrier(MPI_COMM_WORLD);
+//     delete [] sendcounts;
+//   }
+// #endif
+
+  
+  // -------------------------------------------------------------------
+  /*! \brief Create edge correspondance and assure coherent orientation \ingroup parallel */ 
+  void E_createInfoInterface(pMesh mesh, pMeshDataId tagEdge)
+  { 
+    
+    int nproc = 1;
+    int myrank = 0;
+
+    size_t nbConnections = 0;
+
+#ifdef PARALLEL
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+#endif
+
+    // --- Delete previous information ---
+    
+    EIter eit = M_edgeIter(mesh);
+    while ( pEdge pe = EIter_next(eit) ) {
+      void * tmp_ptr;
+      if( EN_getDataPtr((pEntity) pe, tagEdge, &tmp_ptr) ) {
+        EN_deleteData((pEntity) pe, tagEdge);
+      }
+    }
+    EIter_delete(eit);
+
+
+    // --- establish local connections and assure coherent orientation --- 
+    // 
+    //     * coherent reorientation on other partitions assumes coherent orientation here 
+    //     * all periodic edges have same connections across partititions
+    //       hence subsequent reorientation should remain coherent
+    
+    eit = M_edgeIter(mesh);
+    
+    while ( pEdge pe = EIter_next(eit) ) {
+
+      std::vector<edge_comm> remote;
+      
+      int id0 = EN_id((pEntity) E_vertex(pe,0));
+      int id1 = EN_id((pEntity) E_vertex(pe,1));
+
+      std::pair<int,int> lNodeID(std::min(id0,id1),
+                                 std::max(id0,id1));
+      
+      if (E_isPotentialInterface(mesh,pe,remote)) {
+        
+        std::vector<edge_comm >::const_iterator riter = remote.begin();
+
+
+        pVertex p1Local = E_vertex(pe,0);
+        pVertex p2Local = E_vertex(pe,1);
+        
+
+        for (;riter!=remote.end();++riter) {
+        
+          int distProc = riter->distProc;
+
+          if (distProc == myrank) {
+            
+            edge_comm comm = *riter;
+            
+            pVertex p1 = comm.p1;
+            pVertex p2 = comm.p2;
+            
+            pEdge remoteEdge = E_exist(p1,p2);
+            
+            if (remoteEdge) {
+              
+
+              // get points again, since alignment may be different from comm 
+
+              pVertex p1Remote = E_vertex(remoteEdge,0);
+              pVertex p2Remote = E_vertex(remoteEdge,1);
+
+              // verify orientation 
+
+              int orientation = 0;
+              if (V_corresponds(p1Remote,p1Local) && V_corresponds(p2Remote,p2Local)) orientation =  1;
+              if (V_corresponds(p1Remote,p2Local) && V_corresponds(p2Remote,p1Local)) orientation = -1;
+                
+              if (orientation == 0) {
+                Msg(MDB_FATAL,
+                    "Got a locally periodic edge connection from %d-%d to %d-%d which does not correspond nodewise",
+                    EN_id((pEntity) p1),EN_id((pEntity) p2),EN_id((pEntity) p1Local),EN_id((pEntity) p2Local));
+              }
+              
+              std::pair<int,int> rNodeID(std::min(EN_id((pEntity) p1Remote),EN_id((pEntity) p2Remote)),
+                                         std::max(EN_id((pEntity) p1Remote),EN_id((pEntity) p2Remote))); 
+  
+            
+              if (rNodeID < lNodeID) { 
+                lNodeID = rNodeID; // remember to what we aligned the edge 
+                if (orientation == -1) {
+                  int dir = E_align(pe,p2Local,p1Local);
+                  if (dir != -1) std::cout << "misalignment of edges " << std::endl;
+                }
+              }
+              
+              void* tmp_ptr;
+              std::multimap<int,pEdge>* list;
+              
+              if(EN_getDataPtr((pEntity) pe, tagEdge, (void**)&tmp_ptr)) {
+                list = (std::multimap<int,pEdge>*) tmp_ptr;
+              }
+              else {
+                list = new std::multimap<int,pEdge> ;
+                EN_attachDataPtr((pEntity) pe,tagEdge,list);
+              }
+
+              list->insert(std::make_pair(myrank,remoteEdge));
+              nbConnections++;
+            }
+          }
+        }
+      }
+    }
+    EIter_delete(eit);
+    
+#ifdef PARALLEL
+    
+    int *sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+    
+    // --- send edge info ---
+
+    eit = M_edgeIter(mesh);
+    while ( pEdge pe = EIter_next(eit) ) {
+
+      std::vector<edge_comm> remote;
+
+      if (E_isPotentialInterface(mesh,pe,remote)) {
+
+        std::vector<edge_comm >::const_iterator riter = remote.begin();
+
+        for (;riter!=remote.end();++riter) {
+        
+          int distProc = riter->distProc;
+
+          if (distProc != myrank) {
+            void *buf = AP_alloc(distProc,446,sizeof(edge_comm));
+            edge_comm *castbuf = (edge_comm *) buf;
+            castbuf->p1  = riter->p1;
+            castbuf->p2  = riter->p2;
+            castbuf->id1 = riter->id1;
+            castbuf->id2 = riter->id1;
+            castbuf->pe = pe;
+            AP_send(buf);
+            sendcounts[distProc]++;
+          }
+        }
+      }
+    }
+    EIter_delete(eit);
+    
+    // --- synchronise sends --- 
+    
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+    //AP_flush();
+
+    // --- Receive edge info ---
+    
+    int message=0,count;
+    while (!AP_recv_count(&count) ||message<count) {
+
+      void *msg;
+      int from;
+      int tag;
+      int size;
+      int rc;
+
+      rc=AP_recv(MPI_ANY_SOURCE,446, AP_BLOCKING|AP_DROPOUT,
+                 &msg, &size, &from, &tag);
+      
+      if (rc) {
+        message++;
+        edge_comm * comm = (edge_comm*) msg;
+        pEdge pe = E_exist(comm->p1,comm->p2);
+        if(pe) {
+        
+          int lowestRank = myrank;
+
+          // avoid connections between two edges that span full periodicity
+          // ie. periodic nodes n1 and n3 while both edges n1-n2 and n2-n3 exist
+
+          int id1 = comm->id1;
+          int id2 = comm->id2;
+
+          if (E_corresponds(pe,id1,id2)) {
+            
+            std::multimap<int,pEdge>* list;
+            if(EN_getDataPtr((pEntity) pe, tagEdge, (void**)&list)) {
+              lowestRank = std::min(list->begin()->first,lowestRank);
+            }
+            else {
+              list = new std::multimap<int,pEdge>;
+              EN_attachDataPtr((pEntity) pe, tagEdge, (void*)list);
+            }
+            
+            list->insert(std::pair<int,pEdge>(from,comm->pe));
+            if (from < lowestRank) {
+              int dir = E_align(pe,comm->p1,comm->p2);
+            }
+          }
+        }
+        AP_free(msg);
+      }
+    }
+
+    // --- synchronise receives --- 
+    
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+    
+    // --- clean ship ---
+    
+    delete [] sendcounts;
+    
+#endif
+    
+    // --- verify !! --- 
+    
+    MDB_CommCheck cc;
+    exchangeDataOnEdges(mesh,cc);
+
+  }
+
+  // -------------------------------------------------------------------
+  /*! \brief Establish face to face correspondance and assure coherent orientation \ingroup parallel */ 
+  //
+  
+  void F_createInfoInterface(pMesh mesh, pMeshDataId tagFace)
+  {
+    
+    int nproc  = 1;
+    int myrank = 0;
+    size_t nbConnections = 0;
+    
+#ifdef PARALLEL
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+#endif
+
+    // --- delete previous information ---
+
+    FIter fit = M_faceIter(mesh);
+    while ( pFace pf = FIter_next(fit) ) {
+      void * tmp_ptr;
+      if( EN_getDataPtr((pEntity) pf, tagFace, &tmp_ptr) ) {
+        EN_deleteData((pEntity) pf, tagFace);
+      }
+    }
+    FIter_delete(fit);
+
+    // --- first establish local communication and coherent orientation ---
+    //     * coherent reorientation on other partitions assumes coherent orientation here 
+    //     * all periodic faces have same connections across partititions
+    //       hence subsequent reorientation should remain coherent
+    
+    
+    fit = M_faceIter(mesh);
+    while ( pFace pf = FIter_next(fit) ) {
+      int distProc = -1;
+
+      std::vector<pVertex> distVt;
+      std::vector<face_comm> rd;
+      
+      if ( F_isPotentialInterface(mesh, pf, rd) ) {
+        
+        std::vector<face_comm>::iterator rIter = rd.begin();
+
+        std::vector<int> lNodeID;
+        for (int i=0;i<F_numVertices(pf);i++) lNodeID.push_back(EN_id((pEntity) F_vertex(pf,i)));
+        
+        
+        for (;rIter!=rd.end();++rIter) {
+          
+          distProc = rIter->distProc;
+          
+          if (distProc == myrank) {
+            
+            face_comm& comm = *rIter;
+            
+            pVertex p1recv,p2recv,p3recv,p4recv;
+            int nbNodes = (comm.p4 == NULL) ? 3:4;
+
+            if (nbNodes != F_numVertices(pf)) {
+              std::cout << "Non-coherent number of vertices " << nbNodes << " vs " << F_numVertices(pf) << std::endl;
+            }
+            
+            p1recv = comm.p1;
+            p2recv = comm.p2;
+            p3recv = comm.p3;
+            p4recv = comm.p4;
+            
+            assert(p1recv);assert(p2recv);assert(p3recv);
+            // p4recv = nbNodes == 4 ? comm.p4 : NULL;
+            
+            pFace remoteFace = F_exist(p1recv,p2recv,p3recv,p4recv);
+            
+            if (remoteFace) {
+            
+              // compare ordered lists of nodes 
+              
+              std::vector<int> rNodeID;
+              rNodeID.push_back(EN_id((pEntity) p1recv));
+              rNodeID.push_back(EN_id((pEntity) p2recv));
+              rNodeID.push_back(EN_id((pEntity) p3recv));
+              if (nbNodes == 4) rNodeID.push_back(EN_id((pEntity) p4recv));
+              
+              // this is ok : only 1 periodic connection possible per face 
+
+              if (rNodeID > lNodeID) {
+                lNodeID = rNodeID; 
+                F_align(remoteFace,p1recv,p2recv,p3recv,p4recv);
+              }
+              
+              void* tmpptr;
+              std::multimap<int,pFace>* list = NULL;
+              
+              if(EN_getDataPtr((pEntity) pf , tagFace,&tmpptr)){
+                list = (std::multimap<int,pFace>*) (tmpptr);
+              } else {
+                list = new std::multimap<int,pFace>;
+                EN_attachDataPtr((pEntity) pf, tagFace, list);
+              }
+              list->insert(std::make_pair(myrank,remoteFace));
+              nbConnections++;
+            }
+          }
+        }
+      }
+    }
+    
+#ifdef PARALLEL
+
+    int *sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+
+    // --- send faces ---     
+
+    fit = M_faceIter(mesh);
+    while ( pFace pf = FIter_next(fit) ) {
+      int distProc = -1;
+      std::vector<pVertex> distVt;
+      
+      std::vector<face_comm> rd;
+      
+      if ( F_isPotentialInterface(mesh, pf, rd) ) {
+        
+        std::vector<face_comm>::iterator rIter = rd.begin();
+        
+        for (;rIter!=rd.end();++rIter) {
+          
+          distProc = rIter->distProc;
+          
+          if (distProc != myrank) {
+            
+            void *buf = AP_alloc(distProc,444,sizeof(face_comm));
+            face_comm *castbuf = (face_comm *) buf;
+            memcpy(buf,&(*rIter),sizeof(face_comm));
+            castbuf->distProc = myrank;
+            
+            AP_send(buf);
+            sendcounts[distProc]++;
+          }
+        }
+      }
+    }
+    FIter_delete(fit);
+
+    // --- synchronise sends --- 
+
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+    //AP_flush();
+  
+    // --- Receive face info ---
+    int message=0, count;
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int from;
+      int tag;
+      int size;
+      int rc;
+      rc=AP_recv(MPI_ANY_SOURCE,444, AP_BLOCKING|AP_DROPOUT,
+                 &msg, &size, &from, &tag);
+      if (rc) {
+        message++;
+        
+        face_comm * castbuf = (face_comm*) msg;
+        
+        pVertex p1recv = castbuf -> p1;
+        pVertex p2recv = castbuf -> p2;
+        pVertex p3recv = castbuf -> p3;
+        pVertex p4recv = castbuf -> p4;
+
+        int id1recv = castbuf->id1;
+        int id2recv = castbuf->id2;
+        int id3recv = castbuf->id3;
+        int id4recv = castbuf->id4;
+      
+        assert(p1recv);assert(p2recv);assert(p3recv);
+        // p4recv = nbNodes == 4 ? castbuf -> p4 : NULL;
+      
+        int nprocrecv = castbuf->distProc;
+        assert(nprocrecv==from);
+      
+        pFace pface = F_exist(p1recv,p2recv,p3recv,p4recv);
+        
+        if (pface) {
+
+          if (F_corresponds(pface,id1recv,id2recv,id3recv,id4recv)) {
+
+            // lowest ranking processor is master
+            
+            void* tmpptr;
+            std::multimap<int,pFace>* list = NULL;
+            
+            if( EN_getDataPtr((pEntity) pface , tagFace,&tmpptr)){
+              list = (std::multimap<int,pFace>*) (tmpptr);
+              if (from < myrank && from < list->begin()->first) {
+                F_align(pface,p1recv,p2recv,p3recv,p4recv);
+              }
+            } 
+            else {
+              if (from < myrank) F_align(pface,p1recv,p2recv,p3recv,p4recv);
+              list = new std::multimap<int,pFace>;
+              EN_attachDataPtr((pEntity) pface, tagFace, list);
+            }
+            list->insert(std::make_pair(nprocrecv,castbuf->pf));
+          }
+        }
+        AP_free(msg);
+      }
+    }
+
+    // --- synchronise receives --- 
+
+    AP_check_sends(AP_WAITALL);
+    MPI_Barrier(MPI_COMM_WORLD);
+
+    // --- clean ship --- 
+
+    delete [] sendcounts;
+
+#endif
+    
+    // --- verify !! --- 
+
+    MDB_CommCheck cc;
+    exchangeDataOnFaces(mesh,cc);
+  }
+  
+  // -------------------------------------------------------------------
+  // -------------------------------------------------------------------
+  // #ifdef PARALLEL
+  // void UpdateIDGlobal(pMesh mesh, int IdGlobal)
+  // {
+  //   int mysize,myrank;
+  //   MPI_Comm_size(MPI_COMM_WORLD, &mysize);
+  //   MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+
+  //   // send pointers
+  //   int *sendcounts = new int[mysize];
+  //   for(int i=0; i<mysize; i++) sendcounts[i] = 0;
+  
+  //   pMeshDataId tagVertex = MD_lookupMeshDataId("RemotePoint");
+  //   pMeshDataId tagGlob = MD_lookupMeshDataId("IdGlobal");
+
+  //   VIter vit = M_vertexIter(mesh);
+  //   pVertex pv;
+  //   while ((pv = VIter_next(vit))) {
+  //     void *temp_ptr; 
+  //     int isInterface = EN_getDataPtr((pEntity) pv , tagVertex, &temp_ptr);
+    
+  //     if(isInterface) {
+  //       std::vector<std::pair<int , MDB_Point*> > *recup = (std::vector<std::pair<int , MDB_Point*> > *) temp_ptr;
+  //       int minproc = mysize + 10;
+  //       for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+  //         minproc = std::min(minproc,(*recup)[j].first);
+  //       }
+  //       minproc = std::min(myrank,minproc);
+  //       if(minproc!=myrank) continue;
+  //       int numGlobal = EN_id((pEntity) pv) + IdGlobal + 1;
+  //       EN_attachDataInt((pEntity) pv, tagGlob, numGlobal);
+  //       for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+  //         int remoteID  = (*recup)[j].first;
+  //         assert(remoteID != myrank);
+  //         void *buf = AP_alloc(remoteID,444,sizeof(point_comm));
+  //         point_comm *castbuf = (point_comm *) buf;
+  //         castbuf->p         = (*recup)[j].second;
+  //         castbuf->nID       =  myrank;
+  //         castbuf->numGlobal =  numGlobal;
+  //         AP_send(buf);
+  //         sendcounts[remoteID]++;
+  //       }
+  //     }
+  //   }
+  //   VIter_delete(vit);
+
+  //   AP_check_sends(AP_NOFLAGS);
+  //   AP_reduce_nsends(sendcounts);
+  //   AP_flush();
+
+  //   // receive pointers
+  //   int message=0;
+  //   int count;
+  //   while (!AP_recv_count(&count) || message<count) {
+  //     void *msg;
+  //     int  from;
+  //     int  tag;
+  //     int  size;
+  //     int  recv;
+  //     recv = AP_recv(MPI_ANY_SOURCE, 444, AP_BLOCKING|AP_DROPOUT,
+  // 		   &msg, &size, &from, &tag);
+  //     if(recv) {
+  //       message++;
+  //       point_comm * castbuf = (point_comm*) msg;
+  //       pVertex precv (0);
+  //       precv = castbuf -> p;
+  //       assert(precv);
+  //       //int recvID = castbuf -> nID;
+  //       int numrecv = castbuf -> numGlobal;
+      
+  //       // DEBUG
+  //       void *temp_ptr; 
+  //       int isInterface = EN_getDataPtr((pEntity) precv, tagVertex, &temp_ptr);
+  //       assert(isInterface);
+      
+  //       EN_attachDataInt((pEntity) precv, tagGlob, numrecv);        
+  //       AP_free(msg);
+  //     }
+    
+  //   }
+  //   AP_check_sends(AP_WAITALL);
+  //   MPI_Barrier(MPI_COMM_WORLD);
+  //   delete [] sendcounts;
+  // }
+  // #endif
+
+  // -------------------------------------------------------------------
+
+}
diff --git a/Mesh/MeshDataBaseParallelInterface.h b/Mesh/MeshDataBaseParallelInterface.h
new file mode 100644
index 0000000..7f5fe16
--- /dev/null
+++ b/Mesh/MeshDataBaseParallelInterface.h
@@ -0,0 +1,131 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: J.-F. Remacle, C. Dobrzynski, K. Hillewaert, G. Compere
+// -------------------------------------------------------------------
+
+#ifndef H_MESHDATABASEPARALLELINTEFACE
+#define H_MESHDATABASEPARALLELINTEFACE
+
+#include "MeshDataBaseCommPeriodic.h"
+#include "MeshDataBaseComm.h"
+#include "MeshDataBaseInterface.h"
+
+#include <vector>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+
+#ifdef PARALLEL
+  void M_writeParallel(pMesh, const char*, int version=2);
+#endif 
+
+  // -------------------------------------------------------------------
+
+  /*! \brief Return true if on a parallel or periodic interface \ingroup internal */ 
+  bool EN_isInterface(pEntity pv);
+
+  /*! \brief Return true if on a parallel or periodic interface \ingroup parallel */ 
+  bool V_isInterface(pVertex pv);
+
+  /*! \brief Return true if pv is a (periodic) copy of vertex with tag id \ingroup parallel */
+  bool V_corresponds(pVertex pv,int id);
+
+  /*! \brief Return size of the list and list is an array containing 
+    proc numbers where pv exist except calling proc \ingroup parallel */ 
+  int  V_listInterface(pVertex pv, int* list=NULL);
+
+  /*! \brief  Return true if edge is //possibly// on a parallel or periodic interface \ingroup internal */ 
+  bool E_isPotentialInterface(pMesh, pEdge);
+
+  /*! \brief  Return true if on a parallel or periodic interface \ingroup parallel */ 
+  bool E_isInterface(pEdge);
+
+  /*! \brief Return true if the edge corresponds either directly or periodically \ingroup parallel */
+  bool E_corresponds(pEdge,int,int);
+
+  /*! \brief  Return true if on a parallel interface, distProc is 
+    (one of) the proc sharing the edge and distVt is a list 
+    of the pointers to the vertices on the distProc mesh \ingroup parallel */ 
+  bool E_isInterface(pMesh, pEdge, int * distProc,
+                     std::vector<pVertex>* distVt);
+  
+  /*! \brief  Return true if face is potentially on a parallel interface \ingroup internal */ 
+  bool F_isPotentialInterface(pMesh, pFace);
+
+  /*! \brief  Return true if face is on a parallel interface \ingroup parallel */ 
+  bool F_isInterface(pFace);
+
+  /*! \brief  Return true if on a parallel interface, distProc is the 
+    proc sharing the face and distVt is a list of the pointers 
+    to the vertices on the distant mesh \ingroup parallel */ 
+  bool F_isInterface(pMesh, pFace, int * distProc,
+                     std::vector<pVertex>* distVt);
+  /*! \brief  Return true if on a parallel interface (always false) \ingroup parallel */ 
+  bool R_isInterface(pRegion pr);
+
+  // -------------------------------------------------------------------
+
+  /*! \brief Fill the attached pointer containing the distant proc
+    numbers and the distant node pointers \ingroup parallel */ 
+  void V_createInfoInterface(pMesh mesh, pMeshDataId tagVertex);
+
+  /*! \brief Fill the attached pointer containing the distant proc
+    numbers and the distant edge pointers \ingroup parallel */ 
+  void E_createInfoInterface(pMesh mesh, pMeshDataId tagEdge);
+
+  /*! \brief Fill the attached pointer containing the distant proc
+    numbers and the distant face pointers \ingroup parallel */ 
+  void F_createInfoInterface(pMesh mesh, pMeshDataId tagFace);
+
+//   void UpdateIDGlobal(pMesh mesh, int IdGlobal);
+
+  // -------------------------------------------------------------------
+#ifdef PARALLEL
+
+  // interface elt migration
+  void Balance(pMesh mesh,MDB_DataExchanger &de);
+  void Balance2(pMesh mesh,MDB_DataExchanger &de);
+  void BalanceRandom(pMesh mesh,MDB_DataExchanger &de);
+  int BalanceManifold(pMesh mesh,MDB_DataExchanger &de);
+
+#ifdef _HAVE_PARMETIS_
+  // load balancing with metis
+  void BalanceMetis(pMesh mesh,MDB_DataExchanger &de);
+  void BalanceMetis2(pMesh mesh,MDB_DataExchanger &de);
+#endif
+
+  // migration of elt tagged tagElt
+  void loadBalancing(pMesh mesh,pMeshDataId tagElt, MDB_DataExchanger &de);  
+  void loadBalancing2(pMesh mesh,pMeshDataId tagElt, MDB_DataExchanger &de);
+#endif
+
+  //Move periodic interfaces
+  void BalancePeriodic(pMesh mesh,int dim,MDB_DataExchanger &de,
+                       MDB_DataExchangerPeriodic &deperiodic,std::vector<std::vector<int> >& transfo);
+
+// -------------------------------------------------------------------
+
+//migration of periodic elt
+void PeriodicInterfaceMigration(MAd::pMesh mesh,MAd::pMeshDataId tagElt,MAd::pMeshDataId tagMove,
+                                MAd::pMeshDataId tagTransfo, MDB_DataExchanger &de,
+                                MDB_DataExchangerPeriodic &deperiodic); 
+
+
+void GroupPeriodicTetra(MAd::pMesh mesh, MDB_DataExchanger &de,
+                        MDB_DataExchangerPeriodic &deperiodic);
+
+
+// -------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/Mesh/MshTags.h b/Mesh/MshTags.h
new file mode 100644
index 0000000..8dd536b
--- /dev/null
+++ b/Mesh/MshTags.h
@@ -0,0 +1,190 @@
+// -*- C++ -*- 
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Koen Hillewaert
+// -------------------------------------------------------------------
+
+#ifndef MSHTAGS__H
+#define MSHTAGS__H
+
+#include "MAdMessage.h"
+
+#include <string>
+#include <sstream>
+
+using namespace MAd;
+
+// Element types in .msh file format
+#define MSH_LIN_2  1
+#define MSH_TRI_3  2
+#define MSH_QUA_4  3
+#define MSH_TET_4  4
+#define MSH_HEX_8  5
+#define MSH_PRI_6  6
+#define MSH_PYR_5  7
+#define MSH_LIN_3  8
+#define MSH_TRI_6  9
+#define MSH_QUA_9  10
+#define MSH_TET_10 11
+#define MSH_HEX_27 12
+#define MSH_PRI_18 13
+#define MSH_PYR_14 14
+#define MSH_PNT    15
+#define MSH_QUA_8  16
+#define MSH_HEX_20 17
+#define MSH_PRI_15 18
+#define MSH_PYR_13 19
+#define MSH_TRI_9  20
+#define MSH_TRI_10 21
+#define MSH_TRI_12 22
+#define MSH_TRI_15 23
+#define MSH_TRI_15I 24
+#define MSH_TRI_21 25
+#define MSH_LIN_4  26
+#define MSH_LIN_5  27
+#define MSH_LIN_6  28
+#define MSH_TET_20 29
+#define MSH_TET_35 30
+#define MSH_TET_56 31
+#define MSH_TET_34 32
+#define MSH_MAX_ELEMENT_NODES 56
+
+inline
+int getNumVerticesForElementTypeMSH(int type)
+{
+  switch (type) {
+  case MSH_PNT    : return 1;
+  case MSH_LIN_2  : return 2;
+  case MSH_LIN_3  : return 2 + 1;
+  case MSH_LIN_4  : return 2 + 2;
+  case MSH_LIN_5  : return 2 + 3;
+  case MSH_LIN_6  : return 2 + 4;
+  case MSH_TRI_3  : return 3;
+  case MSH_TRI_6  : return 3 + 3;
+  case MSH_TRI_9  : return 3 + 6;
+  case MSH_TRI_10  : return 3 + 6 + 1;
+  case MSH_TRI_12  : return 3 + 9;
+  case MSH_TRI_15  : return 3 + 9 + 3;
+  case MSH_TRI_15I : return 3 + 12;
+  case MSH_TRI_21 : return 3 + 12 + 6;
+  case MSH_QUA_4  : return 4;
+  case MSH_QUA_8  : return 4 + 4;
+  case MSH_QUA_9  : return 4 + 4 + 1;
+  case MSH_TET_4  : return 4;
+  case MSH_TET_10 : return 4 + 6;
+  case MSH_HEX_8  : return 8;
+  case MSH_HEX_20 : return 8 + 12;
+  case MSH_HEX_27 : return 8 + 12 + 6 + 1;
+  case MSH_PRI_6  : return 6;
+  case MSH_PRI_15 : return 6 + 9;
+  case MSH_PRI_18 : return 6 + 9 + 3;
+  case MSH_PYR_5  : return 5;
+  case MSH_PYR_13 : return 5 + 8;
+  case MSH_PYR_14 : return 5 + 8 + 1;
+  case MSH_TET_20 : return 20;
+  case MSH_TET_35 : return 35;
+  case MSH_TET_34 : return 34;
+  case MSH_TET_56 : return 56;
+  default: 
+    MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                "Unknown type of element %d", type);
+  }
+  return 0;
+}
+
+inline
+int getDimForElementTypeMSH(int type)
+{
+  switch (type) {
+  case MSH_PNT    : return 0;
+  case MSH_LIN_2  : 
+  case MSH_LIN_3  : 
+  case MSH_LIN_4  : 
+  case MSH_LIN_5  : 
+  case MSH_LIN_6  : return 1;
+  case MSH_TRI_3  : 
+  case MSH_TRI_6  : 
+  case MSH_TRI_9  : 
+  case MSH_TRI_10  : 
+  case MSH_TRI_12  : 
+  case MSH_TRI_15  : 
+  case MSH_TRI_15I : 
+  case MSH_TRI_21 : 
+  case MSH_QUA_4  : 
+  case MSH_QUA_8  : 
+  case MSH_QUA_9  : return 2;
+  case MSH_TET_4  : 
+  case MSH_TET_10 : 
+  case MSH_HEX_8  : 
+  case MSH_HEX_20 : 
+  case MSH_HEX_27 : 
+  case MSH_PRI_6  : 
+  case MSH_PRI_15 : 
+  case MSH_PRI_18 : 
+  case MSH_PYR_5  : 
+  case MSH_PYR_13 : 
+  case MSH_PYR_14 : 
+  case MSH_TET_20 : 
+  case MSH_TET_35 : 
+  case MSH_TET_34 : 
+  case MSH_TET_56 : return 3;
+  default: 
+    MAdMsgSgl::instance().error(__LINE__,__FILE__,
+                                "Unknown type of element %d", type);
+  }
+  return -1;
+}
+
+inline
+std::string getElementName(int type) {
+
+  std::string name;
+  
+  switch (type) {
+  case MSH_PNT     : name = "Point"; break;
+  case MSH_LIN_2   : name = "Linear edge"; break;
+  case MSH_LIN_3   : name = "Quadratic edge"; break;
+  case MSH_LIN_4   : name = "Cubic edge"; break;
+  case MSH_LIN_5   : name = "Quartic edge"; break;
+  case MSH_LIN_6   : name = "Pentic edge"; break;
+  case MSH_TRI_3   : name = "Linear triangle"; break;
+  case MSH_TRI_6   : name = "Quadratic triangle"; break;
+  case MSH_TRI_9   : name = "Cubic serendipity triangle"; break;
+  case MSH_TRI_10  : name = "Cubic triangle"; break;
+  case MSH_TRI_12  : name = "Quartic serendipity triangle"; break;
+  case MSH_TRI_15  : name = "Quartic triangle"; break;
+  case MSH_TRI_15I : name = "Pentic serendipity triangle"; break;
+  case MSH_TRI_21  : name = "Pentic triangle"; break;
+  case MSH_QUA_4   : name = "Bilinear Quadrangle"; break;
+  case MSH_QUA_8   : name = "Quadratic serendipity quadrangle"; break;
+  case MSH_QUA_9   : name = "Quadratic quadrangle"; break;
+  case MSH_TET_4   : name = "Linear tetrahedron"; break;
+  case MSH_TET_10  : name = "Quadratic tetrahedron"; break;
+  case MSH_HEX_8   : name = "Trilinear hexahedron"; break;
+  case MSH_HEX_20  : name = "Quadratic edge serendipity hexahedron"; break;
+  case MSH_HEX_27  : name = "Quadratic serendipity hexahedron"; break;
+  case MSH_PRI_6   : name = "Linear prism"; break;
+  case MSH_PRI_15  : name = "Quadratic edge serendipity prism"; break;
+  case MSH_PRI_18  : name = "Quadratic serendipity prism"; break;
+  case MSH_PYR_5   : name = "Linear pyramid"; break;
+  case MSH_PYR_13  : name = "Quadratic edge serendipity pyramid"; break;
+  case MSH_PYR_14  : name = "Quadratic serendipty pyramid"; break;
+  case MSH_TET_20  : name = "Cubic tetrahedron";break;
+  case MSH_TET_35  : name = "Quartic tetrahedron";break;
+  case MSH_TET_34  : name = "Quartic serendipity tetrahedron";break;
+  case MSH_TET_56  : name = "Pentic tetrahedron";break;
+  default:
+    std::stringstream ss; break;
+    ss <<  "Unknown type of element (tag " << type << ")"; break;
+    name = ss.str(); 
+  }
+  return name;
+}
+#endif
diff --git a/Mesh/PList.h b/Mesh/PList.h
new file mode 100644
index 0000000..1df5bb2
--- /dev/null
+++ b/Mesh/PList.h
@@ -0,0 +1,59 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+/*
+  Store a list of pointers to entities
+
+  The list is stored as a standart vector:
+    - allow fast random access
+    - allow fast iterating
+    - can be allocated to a particular size
+    - slow at randomly adding/removing elements but not useful here
+*/
+
+#ifndef _H_PLIST
+#define _H_PLIST
+
+#include "MeshDataBase.h"
+
+#include <vector>
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  class PList {
+
+  public:
+
+    PList() {};
+    PList(const PList& ori)
+    {
+      entities = ori.entities;
+    };
+  
+    ~PList() {};
+
+  public:
+
+    void clear() { entities.clear(); };
+
+  public:
+
+    std::vector<MDB_MeshEntity *> entities;
+
+  };
+
+  // -------------------------------------------------------------------
+
+}
+#endif
diff --git a/Mesh/ParallelUtils.cc b/Mesh/ParallelUtils.cc
new file mode 100644
index 0000000..a2df5c8
--- /dev/null
+++ b/Mesh/ParallelUtils.cc
@@ -0,0 +1,444 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "MeshDataBase.h"
+#include "MSops.h"
+#include "MeshDataBaseInterface.h"
+#include "ParallelUtils.h"
+#include "assert.h"
+
+#ifdef PARALLEL
+#include "mpi.h"
+#include "autopack.h"
+#endif
+
+#ifdef _HAVE_METIS_
+extern "C"
+{
+#include "metis.h"
+}
+#endif
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+#ifdef _HAVE_METIS_
+  void PartitionMesh(pMesh mesh, int nbPart, const char * filename)
+  {
+    printf("Partitioning the mesh in %d parts\n",nbPart);
+
+    //NN = number of nodes of the graph
+
+    int dim = (mesh->tets.empty()) ? 2 : 3;
+    int NN =  (dim == 2) ? mesh->nbTriangles : mesh->nbTets;
+    int * partitionTable = new int[NN];
+    int * xadj = new int[NN + 2];
+
+    int totCount = 0;
+
+    if(nbPart>1) {
+      MDB_ListF::iterator it2 = mesh->triangles.begin();
+      MDB_ListT::iterator it3 = mesh->tets.begin();
+
+      xadj[0] = 0;
+      for(int i = 0; i < NN; i++) {
+        int nbAdj = 0;
+        if(dim == 2) {
+          MDB_Triangle *t = *it2;
+          ++it2;
+          t->iD = i;
+          nbAdj = (t->e1->numfaces() + t->e2->numfaces() + t->e3->numfaces() - 3);
+          totCount += nbAdj;
+        }
+        else if(dim == 3) {
+          MDB_Tet *t = *it3;
+          ++it3;
+          t->iD = i;
+          nbAdj = (t->f1->getNbRegions() + t->f2->getNbRegions() + 
+                   t->f3->getNbRegions() + t->f4->getNbRegions() - 4);
+          totCount += nbAdj;
+        }
+        xadj[i + 1] = xadj[i] + nbAdj;
+      }
+
+      it2 = mesh->triangles.begin();
+      it3 = mesh->tets.begin();
+
+      int *adjncy = new int[totCount + 1];
+
+      int count = 0;
+
+      for(int i = 0; i < NN; i++) {
+        if(dim == 2) {
+          MDB_Triangle *t = *it2;
+          for(int j = 0; j < t->e1->numfaces(); j++) {
+            MDB_Triangle *f = t->e1->faces(j);
+            if(f != t)
+              adjncy[count++] = f->iD;
+          }
+          for(int j = 0; j < t->e2->numfaces(); j++) {
+            MDB_Triangle *f = t->e2->faces(j);
+            if(f != t)
+              adjncy[count++] = f->iD;
+          }
+          for(int j = 0; j < t->e3->numfaces(); j++) {
+            MDB_Triangle *f = t->e3->faces(j);
+            if(f != t)
+              adjncy[count++] = f->iD;
+          }
+          ++it2;
+        }
+        else if(dim == 3) {
+          MDB_Tet *t = *it3;
+          MDB_Tet *o = dynamic_cast<MDB_Tet*>(t->f1->opposite_region((MDB_Region*)t));
+          if(o)
+            adjncy[count++] = o->iD;
+          o = dynamic_cast<MDB_Tet*>(t->f2->opposite_region((MDB_Region*)t));
+          if(o)
+            adjncy[count++] = o->iD;
+          o = dynamic_cast<MDB_Tet*>(t->f3->opposite_region((MDB_Region*)t));
+          if(o)
+            adjncy[count++] = o->iD;
+          o = dynamic_cast<MDB_Tet*>(t->f4->opposite_region((MDB_Region*)t));
+          if(o)
+            adjncy[count++] = o->iD;
+          ++it3;
+        }
+      }
+
+      int wgtflag = 0;
+      int numflag = 0;
+      int options[4];
+      options[0] = 0;
+      int edgecut;
+      METIS_PartGraphKway(&NN, xadj, adjncy, 0, 0, &wgtflag,
+                          &numflag, &nbPart, options, &edgecut, partitionTable);
+      delete[]adjncy;
+
+    } else {
+      for(int i = 0; i < NN; i++) {
+        partitionTable[i] = 0;     
+      }
+    }
+
+    M_writeMsh(mesh,filename,2,partitionTable);
+
+    delete[]xadj;
+  };
+#endif
+
+#ifdef PARALLEL
+
+  // -------------------------------------------------------------------
+  struct edge_comm
+  {
+    pVertex p1,p2;                //pointeur in dest
+    int     sendID;       
+  };
+  struct face_comm
+  {
+    pVertex p1,p2,p3;                //pointeur in dest
+    int     sendID;       
+  };
+
+  // -------------------------------------------------------------------
+  void E_facesAttachId(pMesh mesh,pMeshDataId tagEdge){
+    int nproc,myrank;
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank); 
+  
+    int *sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+  
+    pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+    EIter eit = M_edgeIter(mesh);
+    pEdge pe;  
+    while ((pe = EIter_next(eit))) {
+      pVertex p1 = E_vertex(pe,0);
+      pVertex p2 = E_vertex(pe,1);
+      assert(p1); assert(p2);
+      assert(E_exist(p1,p2)==pe);
+      void *temp_ptr1,*temp_ptr2; 
+      int isInterface1 = EN_getDataPtr((pEntity) p1 , tagData, &temp_ptr1);
+      int isInterface2 = EN_getDataPtr((pEntity) p2 , tagData, &temp_ptr2);
+      if(!(isInterface1 && isInterface2))continue;
+
+      const std::vector<std::pair<int , pVertex> > *recup1 = (const std::vector<std::pair<int , pVertex> > *) temp_ptr1;
+      const std::vector<std::pair<int , pVertex> > *recup2 = (const std::vector<std::pair<int , pVertex> > *) temp_ptr2;
+      int size1 = (*recup1).size();
+      int size2 = (*recup2).size();
+      assert(size1);assert(size2);
+      int *tab=new int[size1];
+      for(int i=0 ; i< size1 ; i++) tab[i] = (*recup1)[i].first;
+      for(int j=0 ; j<size2 ; j++) {    
+        int iProc = (*recup2)[j].first;
+        int i;
+        for(i=0 ; i<size1 ; i++) {
+          if(iProc == tab[i]) break;
+        }
+        if(i < size1) {        
+          pVertex remote1 = (*recup1)[i].second;
+          pVertex remote2 = (*recup2)[j].second;
+          for(int k = 0; k < pe->numfaces(); k++) {
+            pFace pface = pe->faces(k);
+            assert(pface);
+            assert(iProc != myrank);
+            void *buf = AP_alloc(iProc,444,sizeof(edge_comm));
+            edge_comm *castbuf = (edge_comm *) buf;
+            castbuf->p1	     = remote1;
+            castbuf->p2	     = remote2;
+            castbuf->sendID    = pface->iD;
+            AP_send(buf);
+            sendcounts[iProc]++;  
+          }
+        }
+      }
+      delete []tab;
+    }      
+    EIter_delete(eit);  
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+  
+    int message=0;
+    int count;
+  
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int from;
+      int tag;
+      int size;
+      int rc;
+      rc=AP_recv(MPI_ANY_SOURCE,444, AP_BLOCKING|AP_DROPOUT,
+                 &msg, &size, &from, &tag);
+      if (rc) {
+        message++;
+        edge_comm * castbuf = (edge_comm*) msg;
+        pVertex p1recv,p2recv;
+        p1recv = castbuf -> p1;
+        p2recv = castbuf -> p2;
+        assert(p1recv);assert(p2recv);
+        int numrecv = castbuf->sendID;
+        int NN = mesh->nbTriangles;
+        if(from > myrank) {
+          if(numrecv < NN) 
+            printf("from %d iD %d NN %d \n",from,numrecv,NN);
+          assert(numrecv >= NN);
+        }
+        assert(from!=myrank);
+        pEdge pe = E_exist(p1recv,p2recv);
+        if(pe) {
+          void* tmpptr; 
+          int is = EN_getDataPtr((pEntity) pe , tagEdge,&tmpptr);
+          if(is){
+            std::vector<int> *recup = (std::vector<int> *) tmpptr;
+            for(unsigned int i=0 ; i<(*recup).size() ; i++) assert((*recup)[i]!=numrecv);	     
+            (*recup).push_back(numrecv);
+          } else {
+            std::vector<int> list;
+            list.push_back(numrecv);
+            EN_attachDataPtr((pEntity) pe,tagEdge,new std::vector<int>(list));       
+          }
+        }
+        AP_free(msg);
+      }
+    }    
+    AP_check_sends(AP_WAITALL); 
+    MPI_Barrier(MPI_COMM_WORLD);
+
+    delete [] sendcounts;
+  
+    eit = M_edgeIter(mesh);
+    while ((pe = EIter_next(eit))) { 
+      void* tmpptr; 
+      int is = EN_getDataPtr((pEntity) pe , tagEdge,&tmpptr);
+      if(is){
+        std::vector<int> *recup = (std::vector<int> *) tmpptr;
+        for(int k = 0; k <  E_numFaces(pe); k++) {
+          pFace pface = E_face(pe,k);
+          int iD      = pface->iD;
+          unsigned int i;
+          for(i=0 ; i<(*recup).size() ; i++) {
+            if((*recup)[i]==iD) {
+              printf("%d my %d iD %d \n",myrank,(*recup)[i],pe->numfaces());
+            }
+            assert((*recup)[i]!=iD);
+          }  
+          (*recup).push_back(iD);
+        }
+      } else {
+        std::vector<int> list;
+        assert(pe->numfaces());
+        for(int k = 0; k < pe->numfaces(); k++) {
+          pFace pface = pe->faces(k);
+          list.push_back(pface->iD);
+        }	 
+        EN_attachDataPtr((pEntity) pe,tagEdge,new std::vector<int>(list));        
+      }    
+    } 
+    EIter_delete(eit);
+
+  }
+
+  // -------------------------------------------------------------------
+  void F_regionsAttachId(pMesh mesh,pMeshDataId tagAdj){
+    int nproc,myrank;
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank); 
+  
+    int *sendcounts = new int[nproc];
+    for(int i=0;i<nproc;i++)sendcounts[i]=0;
+  
+    pMeshDataId tagData = MD_lookupMeshDataId("RemotePoint");
+    FIter fit = M_faceIter(mesh);
+    pFace pface;  
+    while ((pface = FIter_next(fit))) {
+      pVertex p1 = F_vertex(pface,0);
+      pVertex p2 = F_vertex(pface,1);
+      pVertex p3 = F_vertex(pface,2);
+      assert(p1); assert(p2);assert(p3);
+      void *temp_ptr1,*temp_ptr2,*temp_ptr3; 
+      int isInterface1 = EN_getDataPtr((pEntity) p1 , tagData, &temp_ptr1);
+      int isInterface2 = EN_getDataPtr((pEntity) p2 , tagData, &temp_ptr2);
+      int isInterface3 = EN_getDataPtr((pEntity) p3 , tagData, &temp_ptr3);
+      if(!(isInterface1 && isInterface2 && isInterface3))continue;
+
+      const std::vector<std::pair<int , pVertex> > *recup1 = (const std::vector<std::pair<int , pVertex> > *) temp_ptr1;
+      const std::vector<std::pair<int , pVertex> > *recup2 = (const std::vector<std::pair<int , pVertex> > *) temp_ptr2;
+      const std::vector<std::pair<int , pVertex> > *recup3 = (const std::vector<std::pair<int , pVertex> > *) temp_ptr3;
+      int size1 = (*recup1).size();
+      int size2 = (*recup2).size();
+      int size3 = (*recup3).size();
+      assert(size1);assert(size2);assert(size3);
+      int *tab=new int[size1];
+      int *tab3=new int[size3];
+      for(int i=0 ; i< size1 ; i++) tab[i]  = (*recup1)[i].first;
+      for(int i=0 ; i< size3 ; i++) tab3[i] = (*recup3)[i].first;
+      for(int j=0 ; j<size2 ; j++) {    
+        int iProc = (*recup2)[j].first;
+        int i,l;
+        for(i=0 ; i<size1 ; i++) {
+          if(iProc == tab[i]) break;
+        }
+        for(l=0 ; l<size3 ; l++) {
+          if(iProc == tab3[l]) break;
+        }
+        if(i < size1 && l<size3) {        
+          pVertex remote1 = (*recup1)[i].second;
+          pVertex remote2 = (*recup2)[j].second;
+          pVertex remote3 = (*recup3)[l].second;
+          for(int k = 0; k < F_numRegions(pface); k++) {
+            pRegion pr = F_region(pface,k);
+            assert(pr);
+            assert(iProc != myrank);
+            void *buf = AP_alloc(iProc,444,sizeof(face_comm));
+            face_comm *castbuf = (face_comm *) buf;
+            castbuf->p1	     = remote1;
+            castbuf->p2	     = remote2;
+            castbuf->p3	     = remote3;
+            castbuf->sendID  = pr->iD;
+            AP_send(buf);
+            sendcounts[iProc]++;  
+          }
+        }
+      }
+      delete []tab;
+      delete []tab3;
+    }      
+    FIter_delete(fit);  
+    AP_check_sends(AP_NOFLAGS);
+    AP_reduce_nsends(sendcounts);
+  
+    int message=0;
+    int count;
+  
+    while (!AP_recv_count(&count) || message<count) {
+      void *msg;
+      int from;
+      int tag;
+      int size;
+      int rc;
+      rc=AP_recv(MPI_ANY_SOURCE,444, AP_BLOCKING|AP_DROPOUT,
+                 &msg, &size, &from, &tag);
+      if (rc) {
+        message++;
+        face_comm * castbuf = (face_comm*) msg;
+        pVertex p1recv,p2recv,p3recv;
+        p1recv = castbuf -> p1;
+        p2recv = castbuf -> p2;
+        p3recv = castbuf -> p3;
+        int numrecv = castbuf->sendID;
+        int NN = mesh->nbTets;
+        if(from > myrank) {
+          if(numrecv < NN) 
+            printf("from %d iD %d NN %d \n",from,numrecv,NN);
+          assert(numrecv >= NN);
+        }
+        assert(from!=myrank);
+        // pFace pface = F_exist(2,p1recv,p2recv,p3recv,0);
+        pFace pface = F_exist(p1recv,p2recv,p3recv,0);
+        if(pface) {
+          void* tmpptr; 
+          int is = EN_getDataPtr((pEntity) pface , tagAdj,&tmpptr);
+          if(is){
+            std::vector<int> *recup = (std::vector<int> *) tmpptr;
+            for(unsigned int i=0 ; i<(*recup).size() ; i++) assert((*recup)[i]!=numrecv);	     
+            (*recup).push_back(numrecv);
+          } else {
+            std::vector<int> newvec;
+            newvec.push_back(numrecv);
+            EN_attachDataPtr((pEntity) pface,tagAdj,new std::vector<int>(newvec));       
+          }
+        }
+        AP_free(msg);
+      }
+    }    
+    AP_check_sends(AP_WAITALL); 
+    MPI_Barrier(MPI_COMM_WORLD);
+
+    delete [] sendcounts;
+  
+    fit = M_faceIter(mesh);
+    while ((pface = FIter_next(fit))) { 
+      void* tmpptr; 
+      int is = EN_getDataPtr((pEntity) pface , tagAdj,&tmpptr);
+      if(is){
+        std::vector<int> *recup = (std::vector<int> *) tmpptr;
+        for(int k = 0; k <  F_numRegions(pface); k++) {
+          pRegion pr = F_region(pface,k);
+          int iD      = pr->iD;
+          unsigned int i;
+          for(i=0 ; i<(*recup).size() ; i++) {
+            if((*recup)[i]==iD) {
+              printf("%d my %d iD %d \n",myrank,(*recup)[i],F_numRegions(pface));
+            }
+            assert((*recup)[i]!=iD);
+          }  
+          (*recup).push_back(iD);
+        }
+      } else {
+        std::vector<int> list;
+        assert(F_numRegions(pface));
+        for(int k = 0; k < F_numRegions(pface); k++) {
+          pRegion pr = F_region(pface,k);
+          list.push_back(pr->iD);
+        }	 
+        EN_attachDataPtr((pEntity) pface,tagAdj,new std::vector<int>(list));        
+      }    
+    } 
+    FIter_delete(fit);
+
+  }
+
+  // -------------------------------------------------------------------
+#endif
+
+}
diff --git a/Mesh/ParallelUtils.h b/Mesh/ParallelUtils.h
new file mode 100644
index 0000000..d6c846a
--- /dev/null
+++ b/Mesh/ParallelUtils.h
@@ -0,0 +1,30 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifndef _PARALLELUTILS_H_
+#define _PARALLELUTILS_H_
+
+namespace MAd {
+
+#ifdef _HAVE_METIS_
+  void PartitionMesh(pMesh m, int nbPart, const char *);
+#endif
+
+#ifdef PARALLEL
+  void E_facesAttachId(pMesh mesh,pMeshDataId tagAdj);
+  void F_regionsAttachId(pMesh mesh,pMeshDataId tagAdj);
+#endif
+
+}
+
+#endif
diff --git a/Mesh/PeriodicInterfaceMigration.cc b/Mesh/PeriodicInterfaceMigration.cc
new file mode 100644
index 0000000..c40016f
--- /dev/null
+++ b/Mesh/PeriodicInterfaceMigration.cc
@@ -0,0 +1,1248 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#include "MeshDataBase.h"
+#include "MSops.h"
+#include "MeshDataBaseInterface.h"
+#include "MeshDataBaseCommPeriodic.h"
+#include "MeshDataBaseComm.h"
+#include "MeshDataBaseParallelInterface.h"
+#include "Mark.h"
+#include "assert.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <fstream>
+#include <iostream>
+
+int ddebug = 0; 
+
+namespace MAd {
+
+  void MarkPeriodicEltVertex(pMesh mesh,pMeshDataId tagElt,pMeshDataId tagMove) {
+
+    //Propagation du tagMove ie tagMove ==2
+    VIter vit = M_vertexIter(mesh);
+    pVertex pv;  
+    while ((pv = VIter_next(vit))) {
+      int move; 
+      int isMove = EN_getDataInt((pEntity) pv , tagMove,&move);
+    
+      if(!isMove) continue;
+      if(move != 1) continue;
+    
+      int numed = V_numEdges(pv);
+      for(int i=0 ; i<numed ; i++) {
+        pEdge ped = V_edge(pv,i);
+        pVertex pother = E_otherVertex(ped,pv);
+        int movother; 
+        int is = EN_getDataInt((pEntity) pother , tagMove,&movother);
+      
+        if(!is || (movother!=1)) EN_attachDataInt((pEntity) pother , tagMove,2);      
+      } 
+    }
+    VIter_delete(vit);
+
+    //tagMove == 10 : the vertex must be deleted
+    //tagMove == -2 : the vertex don't move 
+    vit = M_vertexIter(mesh);
+    while ((pv = VIter_next(vit))) {
+      int move; 
+      int isMove = EN_getDataInt((pEntity) pv , tagMove,&move);
+    
+      if(!isMove) {
+        EN_attachDataInt((pEntity) pv , tagMove,-2);   
+      } else {
+        if(abs(move)==1) continue;
+
+        int numed = V_numEdges(pv);
+        bool deleted = true;
+        for(int i=0 ; i<numed ; i++) {
+          pEdge ped = V_edge(pv,i);
+          pVertex pother = E_otherVertex(ped,pv);
+          int movother; 
+          int is = EN_getDataInt((pEntity) pother , tagMove,&movother);
+	
+          if((!is) || (movother < 0)) {
+            deleted = false;
+          }
+        }
+        //if(deleted) EN_attachDataInt((pEntity) pv , tagMove,10);         
+      }    
+    }
+    VIter_delete(vit);
+  
+  }
+  bool compare(pEdge p1, pEdge p2);
+  /*renvoie la bonne transfo pour les cas 3-periodic*/
+  int EltMoveNew(const int dim,const pRegion pr,const pVertex* nod,pMeshDataId tagMove,pMeshDataId tagTransfo,std::vector<int> *vecttransfo) {
+    pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+    int transformation = 0;
+    //if(EN_id(R_vertex(pr,0))==5 || EN_id(R_vertex(pr,1))== 5 || EN_id(R_vertex(pr,2)) ==5 ||
+    //							EN_id(R_vertex(pr,3))==5 )
+    //printf("------ tet %d : %d %d %d %d\n",EN_id((pEntity) pr),EN_id(R_vertex(pr,0)),EN_id(R_vertex(pr,1)),EN_id(R_vertex(pr,2))
+    //							,EN_id(R_vertex(pr,3)));  
+    //if(EN_id(R_vertex(pr,0))==28 && EN_id(R_vertex(pr,1))== 111 && EN_id(R_vertex(pr,2)) ==4 &&
+    //							EN_id(R_vertex(pr,3))==8 )
+    //printf("****** tet %d : %d %d %d %d\n",EN_id((pEntity) pr),EN_id(R_vertex(pr,0)),EN_id(R_vertex(pr,1)),EN_id(R_vertex(pr,2))
+    //													,EN_id(R_vertex(pr,3)));  
+     
+    /*on traite les aretes dans l'ordre decroissant (au cas ou plusieurs veulent bouger vers des dest diff)*/
+    std::list<pEdge> listedge;
+    for(int j=0 ; j<6 ; j++) {
+      pEdge ped = R_edge(pr,j);   
+      listedge.push_back(ped);
+    } 
+    //warning: anisotropic case!!
+    listedge.sort(compare);
+
+    /*boucle sur les aretes de pr*/
+    for(std::list<pEdge>::iterator it = listedge.begin() ; it!=listedge.end() ; it++) {  
+      pEdge ped = (*it);
+    
+      /*les deux sommets de l'arete ped*/
+      pVertex p0 = E_vertex(ped,0);
+      pVertex p1 = E_vertex(ped,1);
+      if(EN_id(R_vertex(pr,0))==28 && EN_id(R_vertex(pr,1))== 111 && EN_id(R_vertex(pr,2)) ==4 &&
+         EN_id(R_vertex(pr,3))==8 )
+        printf("treat edge %d %d \n",EN_id((pEntity) p0),EN_id((pEntity) p1));    
+    
+      /*sommets periodics ?*/
+      void *temp_ptr0; 
+      int isP0 = EN_getDataPtr((pEntity) p0 , tagPeriodic, &temp_ptr0);
+      if(!isP0) continue;
+      void *temp_ptr1; 
+      int isP1 = EN_getDataPtr((pEntity) p1 , tagPeriodic, &temp_ptr1);
+      if(!isP1) continue;  
+	
+      void *tr0,*tr1; 
+      int isT0 = EN_getDataPtr((pEntity) p0 ,tagTransfo, &tr0); 
+      if(!isT0) continue;
+      std::vector<int> *t0 = (std::vector<int> *) tr0;
+      int isT1 = EN_getDataPtr((pEntity) p1 ,tagTransfo, &tr1);
+      std::vector<int> *t1 = (std::vector<int> *) tr1;
+      if(!isT1) continue;    
+      unsigned int jj;
+      for(jj=0 ; jj<(*t0).size() ; jj++) {   
+        if((*t0)[jj] != (*t1)[jj]) break;   
+      }
+      if(jj!=(*t0).size()) {  
+        //printf("pbs les 2 points ne bougent pas pareil!!! %d %d\n"
+        //			,EN_id((pEntity) p0),EN_id((pEntity) p1));
+        continue; 
+      }
+      //if(EN_id(R_vertex(pr,0))==28 && EN_id(R_vertex(pr,1))== 111 && EN_id(R_vertex(pr,2)) ==4 &&
+      //							EN_id(R_vertex(pr,3))==8 )      
+      //							printf("on bouge : %d %d %d\n",(*t0)[0],(*t0)[1],(*t0)[2]);    
+      transformation = 1;
+      //for(int kv=0 ; kv<transfo.size() ; kv++)
+      (*vecttransfo) = *t0;
+      return(transformation);
+    } /*end j*/
+    //printf("problemmmm\n");
+    return transformation;
+  } 
+  int EltMove2dNew(const int dim,const pVertex* nod,pMeshDataId tagMove,pMeshDataId tagTransfo,std::vector<int> *vecttransfo) {
+    pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+    int transformation = 0;
+
+    for(int i=0 ; i<(dim+1) ; i++) {
+      void *temp_ptr; 
+      /*sommets periodics */
+      int isPeriodic = EN_getDataPtr((pEntity) nod[i] , tagPeriodic, &temp_ptr);
+      if(!isPeriodic) continue;
+      if(ddebug) printf("test nod %d) \n",EN_id((pEntity) nod[i]));
+
+      /*transfo*/                                               
+      void *tr0; 
+      int isT0 = EN_getDataPtr((pEntity) nod[i] ,tagTransfo, &tr0); 
+      if(!isT0) continue;
+      std::vector<int> *t0 = (std::vector<int> *) tr0;
+      transformation = 1;
+      //for(int kv=0 ; kv<transfo.size() ; kv++)
+      (*vecttransfo) = *t0;
+      return(transformation);
+
+    }
+    return transformation;
+  }
+  int EltMove(const int dim,const pVertex* nod,pMeshDataId tagMove,std::vector<int> *vecttransfo) {
+    pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+    int transformation = 0;
+
+ 
+    if(ddebug) printf("tetra %d %d %d %d\n",nod[0]->iD,nod[1]->iD,nod[2]->iD,nod[3]->iD);
+    for(int i=0 ; i<(dim+1) ; i++) {
+      void *temp_ptr; 
+      int isPeriodic = EN_getDataPtr((pEntity) nod[i] , tagPeriodic, &temp_ptr);
+      if(!isPeriodic) continue;
+      if(ddebug) printf("test nod %d) \n",EN_id((pEntity) nod[i]));
+      std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+      unsigned int j=0;
+      for(j=0 ; j<(*recup).size() ; j++) {
+        std::vector<int> transfo = (*recup)[j].first;
+        /*****************************************************************************/
+        /********************ancienne facon*******************************************/
+        /*****************************************************************************/		
+        unsigned int kk=0;
+        for(kk = 0 ; kk<transfo.size() ; kk++) {
+          if( transfo[kk]< 0) break;     
+        }
+        if(kk!=transfo.size()) continue;  
+   	/*****************************************************************************/
+        /*on bouge que par rapport à x*/   
+        /**   int somme = 0;
+              for(int kk = 0 ; kk<transfo.size() ; kk++) {
+              //if(kk==imove) continue;
+              somme +=  abs(transfo[kk] );
+              } 
+              int inv = (imove>=0) ? 1 : -1;    
+              if(inv < 0) imove = abs(imove)-1; 
+              for(kk = imove ; kk<imove+1 ; kk++) {
+              if((transfo[kk] == 0) || (inv * transfo[kk] <0)) break;	
+              }        
+              if(kk!=imove+1 || somme >=2) continue;    */ 
+        /*****************************************************************************/
+        /********nouvelle facon de bouger (sans pbs pour les tri-periodicite)*********/ 
+        /********on prend la seule transformation qui repond : ***********************/ 
+        /******** tous les autres points img doivent etre en mvt *********************/
+        /*****************************************************************************/
+
+        /*****************************************************************************/
+        /*****************************************************************************/
+
+        if(ddebug) printf("on peut eventuellement le bouge par %d %d %d (point %d)\n",transfo[0],transfo[1],transfo[2],EN_id((pEntity) (*recup)[j].second));
+        pVertex pImg = (*recup)[j].second;
+        int move;
+        int isMove = EN_getDataInt((pEntity) pImg ,tagMove, &move);
+        assert(isMove);
+        if(ddebug) printf("point img tagMove %d\n",move);      
+        if(move==10 || move==1) continue;
+        if(ddebug) printf("on teste de bouger sur le point %d (%d)\n",EN_id((pEntity) (*recup)[j].second),move);  
+        /*******************************************************************************************************/
+        /***** il faut verifier que s'il existe une img aux autres points par cette transfo elle soit fixe ****/
+        /******************************************************************************************************/
+        int k=0;//i+1;
+        for(k=i+1 ; k<(dim+1) ; k++) { 
+          if(k==i) continue;
+          void *temp_ptr2; 
+          int isPeriodic2 = EN_getDataPtr((pEntity) nod[k] , tagPeriodic, &temp_ptr2);
+          if(!isPeriodic2) continue;
+          if(ddebug) printf("on teste le point %d\n",EN_id((pEntity) nod[k]));
+          std::vector<std::pair<std::vector<int> , pVertex> > *recup2 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr2;
+          unsigned int j2=0;
+          for(j2=0 ; j2<(*recup2).size() ; j2++) {
+            std::vector<int> transfo2 = (*recup2)[j2].first;
+            assert(transfo2.size()==transfo.size());
+            unsigned int k2=0;
+            for(k2 = 0 ; k2<transfo2.size() ; k2++) { 
+              if( transfo2[k2] != transfo[k2] ) break;     
+            }
+            if(k2!=transfo2.size()) continue;  
+            pVertex pImg2 = (*recup2)[j2].second;
+            int move2;
+            int isMove2 = EN_getDataInt((pEntity) pImg2 ,tagMove, &move2);
+            assert(isMove2);
+            if(ddebug) printf("img %d (%d)\n",EN_id((pEntity) pImg2),move2);	  
+            if(move2==10 || move2==1) break;	  
+          }
+          if(j2!=(*recup2).size()) break;//si on est arrive au bout de la boucle : ce noeud est ok on passe au suivant
+        }
+        if(k==(dim+1)) { //on peut bouger
+          transformation = 1;
+          //for(int kv=0 ; kv<transfo.size() ; kv++)
+          (*vecttransfo) = transfo;
+          break;
+        }
+      }  
+      if(j!=(*recup).size()) break;//on peut bouger         
+    }
+    return transformation;
+  }
+
+  pFace findFace(pMesh mesh,const pVertex p1,const pVertex p2,const  pVertex p3) {
+    pFace pface;
+  
+    pface =  F_exist(p1,p2,p3,0);
+    if(!pface) pface = F_exist(p1,p2,p3,0);
+    if(!pface) pface = F_exist(p1,p3,p2,0);
+    if(!pface) pface = F_exist(p2,p1,p3,0);
+    if(!pface) pface = F_exist(p2,p3,p1,0);
+    if(!pface) pface = F_exist(p3,p1,p2,0);
+    if(!pface) pface = F_exist(p3,p2,p1,0);
+  
+    assert(pface);
+    return pface;
+
+  }
+  void TetraMove(pMesh mesh,pRegion pr,const pVertex* nodnew) {
+    pGEntity pg = EN_whatIn(pr);
+    int tag = GEN_tag(pg);
+    int dim = GEN_type(pg); 
+    if(dim==3) {
+      pg = (pGEntity) GM_regionByTag(mesh->model,tag);      
+    } else {
+      printf("----pbs faces**** %d\n",dim);
+    }
+
+    pFace pface[4];
+    pface[0] =  findFace(mesh,nodnew[0],nodnew[1],nodnew[2]);
+    assert(pface[0]);
+    pface[1] =  findFace(mesh,nodnew[0],nodnew[1],nodnew[3]);
+    assert(pface[1]);
+    pface[2] =  findFace(mesh,nodnew[1],nodnew[2],nodnew[3]);
+    assert(pface[2]);
+    pface[3] =  findFace(mesh,nodnew[0],nodnew[2],nodnew[3]);
+    assert(pface[3]);
+    //if((EN_id(nodnew[0])==5 || EN_id(nodnew[1])==5 ||EN_id(nodnew[2])==5 || EN_id(nodnew[3])==5) && 
+    //		(EN_id(nodnew[0])==3 || EN_id(nodnew[1])==3 || EN_id(nodnew[2])==3) || EN_id(nodnew[3])==3)  
+    //printf("new tet %d %d %d %d \n",EN_id(nodnew[0]),EN_id(nodnew[1]),EN_id(nodnew[2]),EN_id(nodnew[3]));
+   
+    pRegion prnew = M_createR(mesh,4,pface,pg);
+    //printf("tetnew face : %p %p %p %p\n",prnew->f1,prnew->f2,prnew->f3,prnew->f4);		
+    assert(prnew);
+  
+  
+    return;
+  }
+
+  void TriangleMove(pMesh mesh,pFace pface,const pVertex* nodnew) {
+    pGEntity pg = EN_whatIn(pface);
+    int tag = GEN_tag(pg);
+    int dim = GEN_type(pg); 
+    if(dim==2) {
+      pg = (pGEntity) GM_faceByTag(mesh->model,tag);
+    } else if(dim==3) {
+      pg = (pGEntity) GM_regionByTag(mesh->model,tag);      
+    } else {
+      printf("----pbs faces**** %d\n",dim);
+    }
+    pEdge pe[3];
+    pe[0] =  E_exist(nodnew[0],nodnew[1]);
+    assert(pe[0]);
+    pe[1] =  E_exist(nodnew[1],nodnew[2]);
+    assert(pe[1]);
+    pe[2] =  E_exist(nodnew[0],nodnew[2]);
+    //if(!pe[2]) pe[2] =  E_exist(nodnew[2],nodnew[0]);
+    assert(pe[2]);
+   
+    pFace pfnew =F_exist(pe[0],pe[1],pe[2],0);
+    if(!pfnew) pfnew = M_createF(mesh,3,pe,pg);
+    //printf("tetnew face : %p\n",pfnew); 
+   	
+    assert(pfnew);
+  
+
+  
+    return;
+  }
+
+  void TriangleDelete(pMesh mesh,const pVertex* nod) {
+    int i1,i2,i3;
+    for(int i=0 ; i<4 ; i++) {
+      switch(i) {
+      case 0 : 
+        i1 = 0;
+        i2 = 1;
+        i3 = 2;
+        break;
+      case 1 : 
+        i1 = 0;
+        i2 = 1;
+        i3 = 3;
+        break;
+      case 2 : 
+        i1 = 1;
+        i2 = 2;
+        i3 = 3;
+        break;
+      case 3 : 
+        i1 = 0;
+        i2 = 2;
+        i3 = 3;
+        break;
+      }
+      pFace pface = F_exist(nod[i1],nod[i2],nod[i3],0);
+      assert(pface);
+      int num = F_numRegions(pface);
+      //printf(" del? %d face %p \n",!num,pface);
+      if (!num) M_removeFace(mesh,pface);
+    }
+    return;
+  }
+
+  void numP(const int cas,int* i1,int* i2) {
+    switch(cas) {
+    case 0 :
+      *i1 = 0;
+      *i2 = 1;
+      break;  
+    case 1 :
+      *i1 = 1;
+      *i2 = 2;
+      break;  
+    case 2 :
+      *i1 = 2;
+      *i2 = 0;
+      break;  
+    case 3 :
+      *i1 = 0;
+      *i2 = 3;
+      break;  
+    case 4 :
+      *i1 = 1;
+      *i2 = 3;
+      break;  
+    case 5 :
+      *i1 = 2;
+      *i2 = 3;
+      break;  
+    default : 
+      throw;
+      break;  
+    }
+    return;
+  }
+
+  void EdgeDelete(const int nbe,pMesh mesh,const pVertex* nod) {
+    int i1,i2;
+    for(int i = 0 ; i<nbe ; i++) {
+      numP(i,&i1,&i2);
+      pEdge pedge = E_exist(nod[i1],nod[i2]);
+      //if(!pedge) pedge = E_exist(nod[i1],nod[i2]);
+      assert(pedge);
+      int num = E_numFaces(pedge); 
+      if (!num) M_removeEdge(mesh,pedge);
+    }
+    return;
+  }
+
+  void EdgeMove(const int nbe,pMesh mesh,const pVertex* nod,const pVertex* nodnew) {
+    int i1,i2;
+    for(int i = 0 ; i<nbe ; i++) {
+      numP(i,&i1,&i2);
+   
+      pEdge pedge = E_exist(nod[i1],nod[i2]);
+      //if(!pedge) pedge = E_exist(nod[i2],nod[i1]);
+      assert(pedge);
+      pGEntity  pg = EN_whatIn(pedge);
+      int dim  = GEN_type(pg);
+      int tag  = GEN_tag(pg);
+      if(dim==1) {
+        pg = (pGEntity) GM_edgeByTag(mesh->model,tag);	   
+      } else if(dim==2) {
+        pg = (pGEntity) GM_faceByTag(mesh->model,tag);
+      } else if(dim==3) {
+        pg = (pGEntity) GM_regionByTag(mesh->model,tag);      
+      } else {
+        printf("----pbs**** %d\n",dim);
+      }
+      pEdge     e = E_exist(nodnew[i1],nodnew[i2]);  
+      //if(EN_id(nod[i1])==4694 || EN_id(nod[i2])==4694 || EN_id(nodnew[i1])==4694 || EN_id(nod[i2])==4694)
+      //	printf("edge %d  %d ---> %d %d\n",EN_id(nod[i1]),EN_id(nod[i2]),EN_id(nodnew[i1]),EN_id(nodnew[i2])) ;
+      //printf("on cree edge : %d %d\n",EN_id((pEntity) nodnew[i1]),EN_id((pEntity) nodnew[i2]));
+      //if(nodnew[i1]->iD==144 || nodnew[i2]->iD==144) printf("-------------------- on cree edge : %d %d\n",EN_id((pEntity) nodnew[i1]),EN_id((pEntity) nodnew[i2]));
+      if (!e)   e = M_createE(mesh,nodnew[i1],nodnew[i2],pg);
+    }
+    return;
+  }
+
+  void VertexDelete(pMesh mesh, pMeshDataId tagMove, pMeshDataId tagTransfo){
+    pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+
+    VIter vit = M_vertexIter(mesh);
+    pVertex pv;  
+    while ((pv = VIter_next(vit))) {
+      int move;
+      int isMove = EN_getDataInt((pEntity) pv ,tagMove, &move);
+      assert(isMove);
+      EN_deleteData((pEntity)pv, tagMove);
+      //  if(!(move==1 || move==10)) continue;    
+    
+      //  printf("on delete le point %d ?\n",EN_id((pEntity) pv));
+      int num = V_numEdges(pv);
+      if(num){
+        // if(move!=10) printf("point not deleted %d (%d)\n",EN_id((pEntity) pv),move);
+        //assert(move==10);
+        continue;
+      }
+      void *ttr; 
+      int isT = EN_getDataPtr((pEntity) pv , tagTransfo, &ttr);
+      if(isT) {
+        std::vector<int> *rcup = (std::vector<int> *) ttr;
+        delete rcup;
+        EN_deleteData((pEntity) pv , tagTransfo);
+      }
+ 
+      void *temp_ptr; 
+      int isPeriodic = EN_getDataPtr((pEntity) pv , tagPeriodic, &temp_ptr);
+      if(isPeriodic) {
+        std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+        for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+          pVertex ptemp = (*recup)[j].second;
+          void *temp_ptr2; 
+          int is = EN_getDataPtr((pEntity) ptemp , tagPeriodic, &temp_ptr2);
+          assert(is);
+          std::vector<std::pair<std::vector<int> , pVertex> > *recup2 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr2;
+          if((*recup2).size()==1) {
+            EN_deleteData((pEntity) ptemp , tagPeriodic);
+          } else {
+            std::vector<std::pair<std::vector<int> , pVertex> > vectnod;
+            for(unsigned int k=0 ; k<(*recup2).size() ; k++) {
+              if((*recup2)[k].second != pv) vectnod.push_back(std::pair<std::vector<int> , pVertex>((*recup2)[k].first,(*recup2)[k].second));
+            }	
+            EN_attachDataPtr((pEntity) ptemp , tagPeriodic, 
+                             new std::vector<std::pair<std::vector<int> , pVertex> >(vectnod)); 
+          }
+        }      
+        delete recup;
+        EN_deleteData((pEntity) pv , tagPeriodic);
+      }
+      
+      M_removeVertex(mesh,pv);
+    
+    }
+    VIter_delete(vit);
+
+    return;
+  }
+
+  void VertexMove(const int nbv,pMesh mesh,const pVertex* nod,const std::vector<int>& vecttransfo,pMeshDataId tagMove,
+                  pVertex* nodnew,MDB_DataExchangerPeriodic &deperiodic) {
+    pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+      
+    std::vector<int> invvecttransfo;  
+    for(unsigned k=0 ; k<vecttransfo.size() ; k++) {
+      invvecttransfo.push_back(-vecttransfo[k]);
+    }
+  
+    for(int i=0 ; i<nbv ; i++) {
+      void *temp_ptr; 
+      int isPeriodic = EN_getDataPtr((pEntity) nod[i] , tagPeriodic, &temp_ptr);
+      if(!isPeriodic) {
+        //creation du point, nod[i] et nodnew[i] devient periodic
+        pGEntity  pg  = EN_whatIn(nod[i]);
+        pGEntity pent;
+        int dim  = GEN_type(pg);
+        int tag  = GEN_tag(pg);
+        if(dim == 0) {
+          pent = (pGEntity) GM_vertexByTag(mesh->model,tag);
+        } else if(dim==1) {
+          pent = (pGEntity) GM_edgeByTag(mesh->model,tag);	 
+        } else if(dim==2) {
+          pent = (pGEntity) GM_faceByTag(mesh->model,tag);
+        } else if(dim==3) {
+          pent = (pGEntity) GM_regionByTag(mesh->model,tag);	   
+        } else {
+          printf("pbs**** %d\n",dim);
+        }
+        double X,Y,Z;
+        X = nod[i]->X;
+        Y = nod[i]->Y;
+        Z = nod[i]->Z;
+        for(int k = 0 ; k<deperiodic.nbRefPeriodic() ; k++) {
+          if(vecttransfo[k]){
+            int inv1 = (vecttransfo[k] < 0) ? 1 : 0;
+            for(int nb = 0 ; nb<abs(vecttransfo[k]) ; nb++) {
+              deperiodic.fperiodic(inv1,X,Y,Z,k+1,&X,&Y,&Z);
+            }  
+          }
+        }
+        nodnew[i] = M_createV(mesh,X,Y,Z,-1,pent);
+        if(ddebug) {
+          printf("nod vient de %d avec %d %d\n",EN_id((pEntity) nod[i]),vecttransfo[0],vecttransfo[1]);
+          printf("coor nod %e %e\n",nod[i]->X,nod[i]->Y);
+          printf("coor nodnew %e %e\n",nodnew[i]->X,nodnew[i]->Y);	
+        }
+        std::vector<std::pair<std::vector<int> , pVertex> > vectnodperiodic;
+        vectnodperiodic.push_back(std::pair<std::vector<int> , pVertex>(vecttransfo,nodnew[i]));
+        EN_attachDataPtr((pEntity) nod[i] , tagPeriodic, 
+                         new std::vector<std::pair<std::vector<int> , pVertex> >(vectnodperiodic)); 	
+        std::vector<std::pair<std::vector<int> , pVertex> > vectnodnewperiodic;
+
+        vectnodnewperiodic.push_back(std::pair<std::vector<int> , pVertex>(invvecttransfo,nod[i]));
+        EN_attachDataPtr((pEntity) nodnew[i] , tagPeriodic, 
+                         new std::vector<std::pair<std::vector<int> , pVertex> >(vectnodnewperiodic)); 
+        EN_attachDataInt((pEntity) nodnew[i] , tagMove,2); 
+        if(ddebug) printf("creation non periodique %d -> %d (2)\n",EN_id((pEntity) nod[i]),EN_id((pEntity) nodnew[i]));					
+ 
+      } else {
+        std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+        unsigned int j=0;
+        for(j=0 ; j<(*recup).size() ; j++) {
+          std::vector<int> transfo = (*recup)[j].first;
+          assert(transfo.size()==vecttransfo.size());
+          unsigned int kt = 0;
+          for(kt = 0 ; kt < vecttransfo.size(); kt++) {
+            if(vecttransfo[kt] != transfo[kt]) break;
+          }
+          if(kt!=vecttransfo.size()) continue;  
+
+          if((EN_id(nod[0])==28 && EN_id(nod[1])==111 && EN_id(nod[2])==4 && EN_id(nod[3])==8))  
+            printf("le correspondant de %d est %d par %d %d\n",EN_id((pEntity) nod[i]),EN_id((pEntity)(*recup)[j].second),
+                   vecttransfo[0],vecttransfo[1]);
+          if(ddebug) printf("le correspondant de %d est %d par %d %d\n",EN_id((pEntity) nod[i]),EN_id((pEntity)(*recup)[j].second),
+                            vecttransfo[0],vecttransfo[1]);	
+          //le point existe
+          nodnew[i] = (*recup)[j].second;
+          break;
+        }
+        if(j==(*recup).size()) {
+          //printf("ARGGGGGGGGGGGGGG point %d (%e %e) par %d %d\n",EN_id((pEntity) nod[i]),nod[i]->X,nod[i]->Y,
+          //					vecttransfo[0],vecttransfo[1]);    
+          //le point n'existe pas mais nod est periodic
+          pGEntity  pg  = EN_whatIn(nod[i]);
+          pGEntity pent;
+          int dim  = GEN_type(pg);
+          int tag  = GEN_tag(pg);
+          if(dim == 0) {
+            pent = (pGEntity) GM_vertexByTag(mesh->model,tag);
+          } else if(dim==1) {
+            pent = (pGEntity) GM_edgeByTag(mesh->model,tag);	 
+          } else if(dim==2) {
+            pent = (pGEntity) GM_faceByTag(mesh->model,tag);
+          } else if(dim==3) {
+            pent = (pGEntity) GM_regionByTag(mesh->model,tag);	   
+          } else {
+            printf("pbs**** %d\n",dim);
+          }
+          double X,Y,Z;
+          X = nod[i]->X;
+          Y = nod[i]->Y;
+          Z = nod[i]->Z;
+          for(int k = 0 ; k<deperiodic.nbRefPeriodic() ; k++) {
+            if(vecttransfo[k]){
+              int inv1 = (vecttransfo[k] < 0) ? 1 : 0;
+              for(int nb = 0 ; nb<abs(vecttransfo[k]) ; nb++) {  
+                deperiodic.fperiodic(inv1,X,Y,Z,k+1,&X,&Y,&Z);
+              }	  
+            }
+          }
+          nodnew[i] = M_createV(mesh,X,Y,Z,-1,pent);
+          //printf("on cree le point %p : %e %e \n",nodnew[i],X,Y);
+          std::vector<std::pair<std::vector<int> , pVertex> > vectnodnewperiodic;
+          //printf("1) on ajoute le point %d (%e %e) a la liste de %d (%e %e) par %d %d\n",EN_id((pEntity) nod[i])
+          //			,nod[i]->X,nod[i]->Y
+          //			,EN_id((pEntity) nodnew[i]),nodnew[i]->X,nodnew[i]->Y
+          //			,invvecttransfo[0],invvecttransfo[1]);
+          vectnodnewperiodic.push_back(std::pair<std::vector<int> , pVertex>(invvecttransfo,nod[i]));
+          for(j=0 ; j<(*recup).size() ; j++) {
+            std::vector<int> transfo = (*recup)[j].first;
+            pVertex ptemp = (*recup)[j].second;
+            void *temp_ptr2; 
+            int is = EN_getDataPtr((pEntity) ptemp , tagPeriodic, &temp_ptr2); 
+            assert(is);
+            //#warning: calcule la bonne transformation	  
+            std::vector<std::pair<std::vector<int> , pVertex> > *recup2 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr2;
+#ifdef DEBUG
+            unsigned int k=0;
+            for(k=0 ; k<(*recup2).size() ; k++) {
+              std::vector<int> transfo2 = (*recup2)[k].first; 
+              int kk=0;                                    
+              for(kk = 0 ; kk<deperiodic.nbRefPeriodic() ; kk++) {       
+                if(transfo[kk]!=(-1) * transfo2[kk]) break;
+              }
+              if(kk<deperiodic.nbRefPeriodic()) continue;  
+              //printf(" %p (%e %e %e) -- %p (%e %e %e)\n",(*recup2)[k].second,(*recup2)[k].second->X,(*recup2)[k].second->Y,(*recup2)[k].second->Z,nod[i],nod[i]->X,nod[i]->Y,nod[i]->Z);
+              assert((*recup2)[k].second == nod[i]); 
+              break;
+            }        
+            assert(k!=(*recup2).size());
+#endif
+            std::vector<int> newtransfo;
+            std::vector<int> invnewtransfo;
+            for(unsigned int kn = 0 ; kn < transfo.size() ; kn++){
+              invnewtransfo.push_back(vecttransfo[kn] - transfo[kn]);
+              newtransfo.push_back(-(vecttransfo[kn] - transfo[kn]));
+            }
+            //printf("2) on ajoute le point %d (%e %e) a la liste de %d (%e %e) par %d %d\n",EN_id((pEntity) ptemp)
+            //   			,ptemp->X,ptemp->Y
+            //   			,EN_id((pEntity) nodnew[i]),nodnew[i]->X,nodnew[i]->Y
+            //   			,newtransfo[0],newtransfo[1]);
+            vectnodnewperiodic.push_back(std::pair<std::vector<int> , pVertex>(newtransfo,ptemp));
+            //printf("3) on ajoute le point %d (%e %e) a la liste de %d (%e %e) par %d %d\n",EN_id((pEntity) nodnew[i])
+            //  			,nodnew[i]->X,nodnew[i]->Y
+            //  			,EN_id((pEntity) ptemp),ptemp->X,ptemp->Y
+            //  			,invnewtransfo[0],invnewtransfo[1]);
+            (*recup2).push_back(std::pair<std::vector<int> , pVertex>(invnewtransfo,nodnew[i]));
+          }  
+          EN_attachDataPtr((pEntity) nodnew[i] , tagPeriodic, 
+                           new std::vector<std::pair<std::vector<int> , pVertex> >(vectnodnewperiodic)); 
+          EN_attachDataInt((pEntity) nodnew[i] , tagMove,2); 
+          (*recup).push_back(std::pair<std::vector<int> , pVertex>(vecttransfo,nodnew[i]));
+          //printf("4) on ajoute le point %d (%e %e) a la liste de %d (%e %e) par %d %d\n",EN_id((pEntity) nodnew[i])
+          //			,nodnew[i]->X,nodnew[i]->Y
+          //			,EN_id((pEntity) nod[i]),nod[i]->X,nod[i]->Y
+          //			,vecttransfo[0],vecttransfo[1]);
+							     
+        } else {
+          //le point existe rien a faire pour l'instant
+        }
+      }//end if periodic
+    }// end for i
+    return;
+  }
+
+  void MovePeriodicTriangles(pMesh mesh,pMeshDataId tagElt,pMeshDataId tagMove,pMeshDataId tagTransfo, MDB_DataExchanger &de,
+                             MDB_DataExchangerPeriodic &deperiodic) {
+
+    int nmodif = 0;
+    EIter eit;
+    pEdge pedge;  
+  
+    do {
+      printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ while : nb modif = %d\n",nmodif);
+      //if(nmodif) break;
+      nmodif = 0;
+      eit = M_edgeIter(mesh);
+      while ((pedge = EIter_next(eit))) {
+        pVertex p[2];
+        p[0] = pedge->p1;
+        p[1] = pedge->p2;
+        int move1,move2;
+        int isMove1 = EN_getDataInt((pEntity) p[0] ,tagMove, &move1);
+        int isMove2 = EN_getDataInt((pEntity) p[1] ,tagMove, &move2);
+        assert(isMove1 && isMove2);
+        if(!(move1 == 1 || move1 == 10 || move2==1 || move2 == 10)) continue;
+        //l'arete doit bouger
+        if(E_numFaces(pedge)!=1) continue;
+        pFace pface = E_face(pedge,0);
+        assert(pface);
+        pVertex nod[3];
+        pface->getNodes(nod);
+
+        int tmp; 
+        int isChange = EN_getDataInt((pEntity) pface , tagElt, &tmp);
+        if(!isChange) continue;
+
+        //       printf("test edge ------------- : %d (%d) -- %d (%d)\n",EN_id((pEntity)p[0]),move1,EN_id((pEntity)p[1]),move2);
+        //       printf("tr(%d %d %d) \n\n",EN_id((pEntity)nod[0]),EN_id((pEntity)nod[1]),EN_id((pEntity)nod[2]));    
+     
+        //test si on peut bouger le triangle issu de cette arete
+        std::vector<int> vecttransfo;
+        int transformation = EltMove2dNew(2,nod,tagMove,tagTransfo,&vecttransfo);
+        if(!transformation) continue; 
+        //printf("------------- edge : %d (%d) -- %d (%d)\n",EN_id((pEntity)p[0]),move1,EN_id((pEntity)p[1]),move2);
+        //printf("on a le droit de bouger (%d %d %d) selon %d %d\n\n",EN_id((pEntity)nod[0]),EN_id((pEntity)nod[1]),EN_id((pEntity)nod[2]),
+        //					vecttransfo[0],vecttransfo[1]);    
+      
+       
+        //si oui on le bouge => creation des points, edges, face + delete face, edges, points
+        // + mise a jour des tagPeriodic et des tagMove (ie points deviennent fixes : -2)
+     
+        //bouge des points : s'il n'existe pas on le cree, sinon on donne son pointeur
+        pVertex nodnew[3];
+        VertexMove(3,mesh,nod,vecttransfo,tagMove,nodnew,deperiodic);
+     
+        //creation des edges
+        EdgeMove(3,mesh,nod,nodnew);
+        //printf("on bouge les points (%f %f) (%f %f) (%f %f) \n",nod[0]->X,nod[0]->Y,
+        //   							nod[1]->X,nod[1]->Y,   
+        //   							nod[2]->X,nod[2]->Y);
+        //printf("vers     les points (%f %f) (%f %f) (%f %f) \n",nodnew[0]->X,nodnew[0]->Y,
+        //   							nodnew[1]->X,nodnew[1]->Y,   
+        //   							nodnew[2]->X,nodnew[2]->Y);
+        //creation/delete des triangles
+        TriangleMove(mesh,pface,nodnew);
+        int is = EN_getDataInt((pEntity) pface , tagElt, &tmp);
+        assert(is);	 
+        EN_deleteData((pEntity) pface , tagElt);
+        M_removeFace(mesh,pface);  
+   
+        EdgeDelete(3,mesh,nod); 
+      
+        nmodif++;
+      }
+      EIter_delete(eit);
+    } while (nmodif);
+  
+    //check si plus de tr a bouger
+
+  }
+
+  void MovePeriodicTetras(pMesh mesh,pMeshDataId tagElt,pMeshDataId tagMove ,pMeshDataId tagTransfo,
+                          MDB_DataExchanger &de,
+                          MDB_DataExchangerPeriodic &deperiodic) {
+
+    int nmodif = 0;
+    FIter fit;
+    pFace pface;  
+  
+    do {
+      printf(" Tets $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ while : nb modif = %d\n",nmodif);
+      //M_writeSMS(mesh,"chk.msh",10);
+      //CheckMshPeriodic(mesh);
+    
+      //     //if(nmodif) break;
+      nmodif = 0;
+  
+      //   //check adj
+      //     fit = M_faceIter(mesh);
+      //   while ((pface = FIter_next(fit))) {
+      //     assert(!pface->deleted);
+      //     int num = F_numRegions(pface);
+      //     if(!num) {
+      //       printf("face %p dim %d\n",pface,GEN_type(pface->g));
+      //       exit(0);
+      //       continue;
+      //     }
+      //   }
+      //   FIter_delete(fit);
+  
+  
+      fit = M_faceIter(mesh);
+      while ((pface = FIter_next(fit))) {
+       
+        if(pface->deleted) continue;
+        pVertex p[3];
+        pface->getNodes(p);
+
+        int move1,move2,move3;
+        int isMove1 = EN_getDataInt((pEntity) p[0] ,tagMove, &move1);
+        int isMove2 = EN_getDataInt((pEntity) p[1] ,tagMove, &move2);
+        int isMove3 = EN_getDataInt((pEntity) p[2] ,tagMove, &move3);
+        assert(isMove1 && isMove2 && isMove3);
+        //	if((p[0]->iD==5 || p[1]->iD==5 || p[2]->iD==5) && (p[0]->iD==3 || p[2]->iD==3 || p[1]->iD==3))  
+        //		printf("*** face %d %d %d : %d %d %d\n",p[0]->iD,p[1]->iD,p[2]->iD,move1,move2,move3) ;
+	
+        if(!(move1 == 1 || move1 == 10 || move2==1 || move2 == 10 || move3==1 || move3 == 10 )) continue;
+        if(F_numRegions(pface)<1) printf("face %p pbs\n",(void*)pface);  
+        assert(F_numRegions(pface)>=1);
+        if(F_numRegions(pface)==2) continue;
+
+        if((p[0]->iD==0 && p[1]->iD==0 && p[2]->iD==0) ||
+           (p[0]->iD==0 && p[2]->iD==0 && p[1]->iD==0) ||
+           (p[1]->iD==0 && p[2]->iD==0 && p[0]->iD==0) ||
+           (p[1]->iD==0 && p[0]->iD==0 && p[2]->iD==0) ||
+           (p[2]->iD==0 && p[1]->iD==0 && p[0]->iD==0) ||
+           (p[2]->iD==0 && p[0]->iD==0 && p[1]->iD==0)) ddebug = 1;
+        else if(p[0]->iD==0 || p[1]->iD==0 || p[2]->iD==0)ddebug = 1;
+        else ddebug = 0;  
+ 
+        pRegion pr = F_region(pface,0);
+        assert(pr);
+        pVertex nod[4];
+        pr->getNodes(nod);
+
+        int tmp; 
+        int isChange = EN_getDataInt((pEntity) pr , tagElt, &tmp);
+        if(!isChange) continue; 
+
+        if(ddebug) printf("test face ------------- : %d (%d) -- %d (%d) -- %d(%d)\n",EN_id((pEntity)p[0]),move1,
+                          EN_id((pEntity)p[1]),move2,
+                          EN_id((pEntity)p[2]),move3);
+     
+        if(ddebug) printf("tet : %d %d %d %d\n",EN_id((pEntity)nod[0]),EN_id((pEntity)nod[1]),
+                          EN_id((pEntity)nod[2]),EN_id((pEntity)nod[3]));
+        if(ddebug) printf("tet face : %p %p %p %p\n",(void*)(pr->getFace(0)),(void*)(pr->getFace(1)),(void*)(pr->getFace(2)),(void*)(pr->getFace(3)));		
+		
+        //test si on peut bouger le tetra issu de cette face
+        std::vector<int> vecttransfo;
+        int transformation = EltMoveNew(3,pr,nod,tagMove,tagTransfo,&vecttransfo); 
+        /*ancienne version*/ 
+        //int transformation = EltMove(3,nod,tagMove,&vecttransfo);
+
+        if(ddebug) printf("on bouge ? %d\n",transformation);
+        if(!transformation) continue;       
+       
+      
+        //Orientation!!!!!!
+       
+        pVertex nodnew[4];
+        VertexMove(4,mesh,nod,vecttransfo,tagMove,nodnew,deperiodic);
+	if((EN_id(nodnew[0])==23 && EN_id(nodnew[1])==148 && EN_id(nodnew[2])==3 && EN_id(nodnew[3])==5))  
+          printf("tet %d %d %d %d: %d?\n",EN_id(nod[0]),EN_id(nod[1]),EN_id(nod[2]),EN_id(nod[3]),isChange);
+        // printf("tetnew : %d %d %d %d\n",EN_id((pEntity)nodnew[0]),EN_id((pEntity)nodnew[1]),
+        //       		EN_id((pEntity)nodnew[2]),EN_id((pEntity)nodnew[3]));
+        //      
+        //creation des edges
+        EdgeMove(6,mesh,nod,nodnew);
+     
+        //creation/delete des triangles
+        for(int i=0 ; i<4 ; i++) {
+          pVertex nodtmp[3];
+          switch(i) {
+          case 0 : 
+            nodtmp[0] = nodnew[0];
+            nodtmp[1] = nodnew[1];
+            nodtmp[2] = nodnew[2];
+            break;
+          case 1 : 
+            nodtmp[0] = nodnew[0];
+            nodtmp[1] = nodnew[1];
+            nodtmp[2] = nodnew[3];
+            break;
+          case 2 : 
+            nodtmp[0] = nodnew[1];
+            nodtmp[1] = nodnew[2];
+            nodtmp[2] = nodnew[3];
+            break;
+          case 3 : 
+            nodtmp[0] = nodnew[0];
+            nodtmp[1] = nodnew[2];
+            nodtmp[2] = nodnew[3];
+            break;
+          }
+          TriangleMove(mesh,pface,nodtmp);
+        }
+
+        TetraMove(mesh,pr,nodnew); 
+      
+        int is = EN_getDataInt((pEntity) pr , tagElt, &tmp);
+        assert(is);	 
+        EN_deleteData((pEntity) pr , tagElt);
+        M_removeRegion(mesh,pr);  
+     
+        TriangleDelete(mesh,nod);
+        EdgeDelete(6,mesh,nod); 
+      
+      
+      
+        nmodif++;
+      }
+      FIter_delete(fit);
+
+      //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$MAJ des refs
+      fit = M_faceIter(mesh);
+      while ((pface = FIter_next(fit))) {
+        assert(!pface->deleted);
+        int num = F_numRegions(pface);
+        if(!num) {
+          printf("face %p dim %d\n",(void*)pface,GEN_type(pface->g));
+          M_removeFace(mesh,pface); 
+          continue;
+        }
+        int dim = GEN_type(pface->g); 
+        if(dim == 2) {
+          int num = F_numRegions(pface);
+          if(num == 2) {
+            //puts("enlever la ref");
+            pRegion pr = F_region(pface,0);
+            //	pGEntity pg  = EN_whatIn(pface);
+            pGEntity pgr = EN_whatIn(pr);
+            int tagr = GEN_tag(pgr);
+            int dimr = GEN_type(pgr); 
+            if(dimr==3) {
+              pface->g = (pGEntity) GM_regionByTag(mesh->model,tagr);   
+              assert(   GEN_type(pface->g)==3);
+            } else {
+              printf("----pbs faces**** %d\n",dim);
+            }
+
+          } else if(!num) {
+            M_removeFace(mesh,pface); 
+          }
+          if(!(F_numRegions(pface)==1 || GEN_type(pface->g)!=2)) {
+            printf("face %p %d %d %d\n",(void*)pface,F_numRegions(pface),GEN_type(pface->g),pface->deleted);
+          }
+          assert(F_numRegions(pface)==1 || GEN_type(pface->g)!=2 || pface->deleted);
+        }
+      }
+      FIter_delete(fit);
+      EIter eit = M_edgeIter(mesh);
+      pEdge ped;
+      while ((ped = EIter_next(eit))) {
+        int num = E_numFaces(ped);
+        if(!num) {
+          printf("edge dim %d\n",GEN_type(ped->g));
+          M_removeEdge(mesh,ped); 
+          continue;
+        }
+
+      }
+      EIter_delete(eit);
+      //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ End MAJ des refs
+
+
+    } while (nmodif);
+  
+  }
+
+  void PeriodicInterfaceMigration(pMesh mesh,pMeshDataId tagElt,pMeshDataId tagMove, 
+                                  pMeshDataId tagTransfo,MDB_DataExchanger &de,
+                                  MDB_DataExchangerPeriodic &deperiodic) {
+
+    int dim = (mesh->tets.empty()) ? 2 : 3;
+
+    /* 1) marked vertex*/
+    MarkPeriodicEltVertex(mesh,tagElt,tagMove);
+
+    /* 2) move elements*/
+    if(dim==2) MovePeriodicTriangles(mesh,tagElt,tagMove,tagTransfo,de,deperiodic);
+    else  MovePeriodicTetras(mesh,tagElt,tagMove,tagTransfo,de,deperiodic);
+  
+    /* 3) delete vertex*/
+    VertexDelete(mesh,tagMove,tagTransfo);
+  
+  }
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+  int EltMoveInverse(const int dim,const pVertex* nod,pMeshDataId tagMove,std::vector<int> *vecttransfo) {
+    pMeshDataId tagPeriodic = MD_lookupMeshDataId("PeriodicPoint");
+    int transformation = 0;
+  
+    for(int i=0 ; i<(dim+1) ; i++) {
+      void *temp_ptr; 
+      int isPeriodic = EN_getDataPtr((pEntity) nod[i] , tagPeriodic, &temp_ptr);
+      if(!isPeriodic) continue;
+      //printf("test nod %d)\n",EN_id((pEntity) nod[i]));
+      std::vector<std::pair<std::vector<int> , pVertex> > *recup = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr;
+      unsigned int j=0;
+      for(j=0 ; j<(*recup).size() ; j++) {
+        std::vector<int> transfo = (*recup)[j].first;
+        unsigned int kk=0;
+        for(kk = 0 ; kk<transfo.size() ; kk++) {
+          if( transfo[kk]> 0) break;     
+        }
+        if(kk!=transfo.size()) continue;
+        //printf("on peut eventuellement le bouge par %d %d (point %d)\n",transfo[0],transfo[1],EN_id((pEntity) (*recup)[j].second));
+        pVertex pImg = (*recup)[j].second;
+        int move;
+        int isMove = EN_getDataInt((pEntity) pImg ,tagMove, &move);
+        assert(isMove);
+        if(move==10 || move==1) continue;
+        //printf("on teste de bouger sur le point %d (%d)\n",EN_id((pEntity) (*recup)[j].second),move);
+        int k=i+1;
+        for(k=i+1 ; k<(dim+1) ; k++) {
+          void *temp_ptr2; 
+          int isPeriodic2 = EN_getDataPtr((pEntity) nod[k] , tagPeriodic, &temp_ptr2);
+          if(!isPeriodic2) continue;
+          //printf("on teste le point %d\n",EN_id((pEntity) nod[k]));
+          std::vector<std::pair<std::vector<int> , pVertex> > *recup2 = (std::vector<std::pair<std::vector<int> , pVertex> > *) temp_ptr2;
+          unsigned int j2=0;
+          for(j2=0 ; j2<(*recup2).size() ; j2++) {
+            std::vector<int> transfo2 = (*recup2)[j2].first;
+            assert(transfo2.size()==transfo.size());
+            unsigned int k2=0;
+            for(k2 = 0 ; k2<transfo2.size() ; k2++) {
+              if( transfo2[k2] != transfo[k2]) break;     
+            }
+            if(k2!=transfo2.size()) continue;
+            pVertex pImg2 = (*recup2)[j2].second;
+            int move2;
+            int isMove2 = EN_getDataInt((pEntity) pImg2 ,tagMove, &move2);
+            assert(isMove2);
+            //printf("img %d (%d)\n",EN_id((pEntity) pImg2),move2);	  
+            if(move2==10 || move2==1) break;	  
+          }
+          if(j2!=(*recup2).size()) break;//si on est arrive au bout de la boucle : ce noeud est ok on passe au suivant
+        }
+        if(k==(dim+1)) { //on peut bouger
+          transformation = 1;
+          //for(int kv=0 ; kv<transfo.size() ; kv++)
+          (*vecttransfo) = transfo;
+          break;
+        }
+      }  
+      if(j!=(*recup).size()) break;//on peut bouger         
+    }
+    return transformation;
+  } 
+ 
+ 
+ 
+ 
+ 
+  void MovePeriodicTetrasInverse(pMesh mesh,pMeshDataId tagElt,pMeshDataId tagMove, MDB_DataExchanger &de,
+                                 MDB_DataExchangerPeriodic &deperiodic) {
+
+    int nmodif = 0;
+    FIter fit;
+    pFace pface;  
+  
+    do {
+      printf("Inverse $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ while : nb modif = %d\n",nmodif);
+      //     //if(nmodif) break;
+      nmodif = 0;
+  
+      fit = M_faceIter(mesh);
+      while ((pface = FIter_next(fit))) {
+       
+        if(pface->deleted) continue;
+        pVertex p[3];
+        pface->getNodes(p);
+        int move1,move2,move3;
+        int isMove1 = EN_getDataInt((pEntity) p[0] ,tagMove, &move1);
+        int isMove2 = EN_getDataInt((pEntity) p[1] ,tagMove, &move2);
+        int isMove3 = EN_getDataInt((pEntity) p[2] ,tagMove, &move3);
+        assert(isMove1 && isMove2 && isMove3);
+        if(!(move1 == 1 || move1 == 10 || move2==1 || move2 == 10 || move3==1 || move3 == 10 )) continue;
+        if(F_numRegions(pface)==2) continue;
+       
+        pRegion pr = F_region(pface,0);
+        assert(pr);
+        pVertex nod[4];
+        pr->getNodes(nod);
+
+        int tmp; 
+        int isChange = EN_getDataInt((pEntity) pr , tagElt, &tmp);
+        if(!isChange) continue; 
+
+        //printf("test face ------------- : %d (%d) -- %d (%d) -- %d(%d)\n",EN_id((pEntity)p[0]),move1,
+        //				EN_id((pEntity)p[1]),move2,
+        //				EN_id((pEntity)p[2]),move3);
+     
+        //printf("tet : %d %d %d %d\n",EN_id((pEntity)nod[0]),EN_id((pEntity)nod[1]),
+        //      		EN_id((pEntity)nod[2]),EN_id((pEntity)nod[3]));
+        //printf("tet face : %p %p %p %p\n",pr->f1,pr->f2,pr->f3,pr->f4);		
+		
+        //test si on peut bouger le tetra issu de cette face
+        std::vector<int> vecttransfo;
+        int transformation = EltMoveInverse(3,nod,tagMove,&vecttransfo);
+        //printf("on bouge ? %d\n",transformation);
+        if(!transformation) continue;       
+       
+       
+        //Orientation!!!!!!
+       
+        pVertex nodnew[4];
+        VertexMove(4,mesh,nod,vecttransfo,tagMove,nodnew,deperiodic);
+        // printf("tetnew : %d %d %d %d\n",EN_id((pEntity)nodnew[0]),EN_id((pEntity)nodnew[1]),
+        //       		EN_id((pEntity)nodnew[2]),EN_id((pEntity)nodnew[3]));
+        //      
+        //creation des edges
+        EdgeMove(6,mesh,nod,nodnew);
+     
+        //creation/delete des triangles
+        for(int i=0 ; i<4 ; i++) {
+          pVertex nodtmp[3];
+          switch(i) {
+          case 0 : 
+            nodtmp[0] = nodnew[0];
+            nodtmp[1] = nodnew[1];
+            nodtmp[2] = nodnew[2];
+            break;
+          case 1 : 
+            nodtmp[0] = nodnew[0];
+            nodtmp[1] = nodnew[1];
+            nodtmp[2] = nodnew[3];
+            break;
+          case 2 : 
+            nodtmp[0] = nodnew[1];
+            nodtmp[1] = nodnew[2];
+            nodtmp[2] = nodnew[3];
+            break;
+          case 3 : 
+            nodtmp[0] = nodnew[0];
+            nodtmp[1] = nodnew[2];
+            nodtmp[2] = nodnew[3];
+            break;
+          }
+          TriangleMove(mesh,pface,nodtmp);
+        }
+
+        TetraMove(mesh,pr,nodnew); 
+      
+        int is = EN_getDataInt((pEntity) pr , tagElt, &tmp);
+        assert(is);	 
+        EN_deleteData((pEntity) pr , tagElt);
+        M_removeRegion(mesh,pr);  
+     
+        TriangleDelete(mesh,nod);
+        EdgeDelete(6,mesh,nod); 
+      
+        nmodif++;
+      }
+      FIter_delete(fit);
+    } while (nmodif);
+  
+    //MAJ des refs
+    fit = M_faceIter(mesh);
+    while ((pface = FIter_next(fit))) {
+      assert(!pface->deleted);
+      int num = F_numRegions(pface);
+      if(!num) {
+        printf("face %p dim %d\n",(void*)pface,GEN_type(pface->g));
+        M_removeFace(mesh,pface); 
+        continue;
+      }
+      int dim = GEN_type(pface->g); 
+      if(dim == 2) {
+        int num = F_numRegions(pface);
+        if(num == 2) {
+          //puts("enlever la ref");
+          pRegion pr = F_region(pface,0);
+          //	pGEntity pg  = EN_whatIn(pface);
+          pGEntity pgr = EN_whatIn(pr);
+          int tagr = GEN_tag(pgr);
+          int dimr = GEN_type(pgr); 
+          if(dimr==3) {
+            pface->g = (pGEntity) GM_regionByTag(mesh->model,tagr);   
+            assert(   GEN_type(pface->g)==3);
+          } else {
+            printf("----pbs faces**** %d\n",dim);
+          }
+
+        } else if(!num) {
+          M_removeFace(mesh,pface); 
+        }
+        if(!(F_numRegions(pface)==1 || GEN_type(pface->g)!=2)) {
+          printf("face %p %d %d %d\n",(void*)pface,F_numRegions(pface),GEN_type(pface->g),pface->deleted);
+        }
+        assert(F_numRegions(pface)==1 || GEN_type(pface->g)!=2 || pface->deleted);
+      }
+    }
+    FIter_delete(fit);
+    EIter eit = M_edgeIter(mesh);
+    pEdge ped;
+    while ((ped = EIter_next(eit))) {
+      int num = E_numFaces(ped);
+      if(!num) {
+        printf("edge dim %d\n",GEN_type(ped->g));
+        M_removeEdge(mesh,ped); 
+        continue;
+      }
+
+    }
+    EIter_delete(eit);
+  }
+
+
+  void GroupPeriodicTetra(pMesh mesh, MDB_DataExchanger &de,
+                          MDB_DataExchangerPeriodic &deperiodic) {
+
+    pMeshDataId tagMove = MD_newMeshDataId("TagMovePeriodic");
+    pMeshDataId tagElt  = MD_newMeshDataId("EltDestination"); //dest = (int - 1)
+
+    int maxiter = 5;
+    int iter = 1;                                       
+    while(MarkGroupPeriodicTets(mesh,tagElt,tagMove) && iter++ < maxiter) { 
+      printf("group iter %d\n",iter-1);
+      /* 1) marked vertex*/
+      MarkPeriodicEltVertex(mesh,tagElt,tagMove);
+
+      /* 2) move elements*/                                         
+      MovePeriodicTetrasInverse(mesh,tagElt,tagMove,de,deperiodic);
+  
+      /* 3) delete vertex*/
+      VertexDelete(mesh,tagMove,tagMove); 
+  
+    } 
+    MD_deleteMeshDataId(tagMove);
+    MD_deleteMeshDataId(tagElt);  
+  
+    return;
+  }
+
+} // End of namespace MAd
diff --git a/Mesh/metisAdaptiveRepart.cc b/Mesh/metisAdaptiveRepart.cc
new file mode 100644
index 0000000..a16e228
--- /dev/null
+++ b/Mesh/metisAdaptiveRepart.cc
@@ -0,0 +1,293 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifdef PARALLEL
+#ifdef _HAVE_PARMETIS_
+
+#include "mpi.h" // has to be included before "parmetis.h"
+extern "C" {
+#include "parmetis.h"
+}
+#include "autopack.h"
+
+#include "assert.h"
+#include "MeshDataBase.h"
+#include "MSops.h"
+#include "MeshDataBaseInterface.h"
+#include "ParallelUtils.h"
+
+namespace MAd {
+
+  // -------------------------------------------------------------------
+  void metisAdaptiveRepart(pMesh mesh,pMeshDataId tagElt) {
+
+    int nproc,myrank;
+    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
+    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);   
+
+    int dim = (mesh->tets.empty()) ? 2 : 3;
+    int NN =  (dim == 2) ? mesh->nbTriangles : mesh->nbTets;
+
+    // ------------------------------------------------
+    // Creation of 'tab' which contains the number of elements for each proc
+
+    int *tab = new int[nproc];
+    int sendnum = NN; 
+    if(myrank) {
+      MPI_Send(&sendnum,1,MPI_INT,0,myrank,MPI_COMM_WORLD);   
+    } else {
+      MPI_Status status;
+      tab[0] = sendnum;
+      for(int i=1 ; i<nproc ; i++) {
+        MPI_Recv(&tab[i],1,MPI_INT,i,i,MPI_COMM_WORLD,&status);
+      }
+    }
+    MPI_Bcast(&tab[0],nproc,MPI_INT,0,MPI_COMM_WORLD);
+  
+    // ------------------------------------------------
+    // Creation of 'vtxdist' which contains the starting element id on each proc
+
+    int *vtxdist = new int[nproc+1];
+    int pos = 0;
+    for(int i=0 ; i<=nproc ; i++) {
+      vtxdist[i] = pos;
+      if(i<nproc) pos += tab[i];
+    }
+  
+    // ------------------------------------------------
+    // Global numbering of the elements
+
+    int mypos = 0;
+    for(int i=0; i<myrank; i++) mypos += tab[i];
+
+    if(dim==2) {
+      FIter fit = M_faceIter(mesh);
+      pFace pface;
+      int i=0;
+      while ((pface = FIter_next(fit))) { 
+        pface->iD = i + mypos;
+        i++;
+      }
+      FIter_delete(fit);  
+    }
+    else if(dim==3){
+      RIter rit = M_regionIter(mesh);
+      pRegion pr;
+      int i=0;
+      while ((pr = RIter_next(rit))) { 
+        pr->iD = i + mypos;
+        i++;
+      }
+      RIter_delete(rit);  
+    }
+
+    // ------------------------------------------------
+    // Creation of the graph of the mesh
+
+    // --- determine the neighborhood of elements ---
+
+    pMeshDataId tagAdj = MD_newMeshDataId("AdjGlobal"); 
+    if(dim==2)      E_facesAttachId  (mesh,tagAdj);
+    else if(dim==3) F_regionsAttachId(mesh,tagAdj);
+
+    // --- count the adjencies of elements ---
+
+    int *xadj = new int[NN + 1]; // xadj[i] = xadj[i-1] + nb adjencies of element 'i'
+    xadj[0] = 0;
+
+    int totCount = 0;
+
+    if(dim==2) {
+      FIter fit = M_faceIter(mesh);
+      pFace pface;
+      int i=0;
+      while ((pface = FIter_next(fit))) { 
+        int nbAdj = 0;
+        assert(!pface->deleted);
+        pface->iD = i + mypos;
+        for(int k=0 ; k<3 ; k++) {
+          pEdge pe = F_edge(pface,k);
+          void* tmpptr; 
+          int is = EN_getDataPtr((pEntity) pe , tagAdj,&tmpptr);
+          assert(is);
+          std::vector<int> *recup = (std::vector<int> *) tmpptr;
+          nbAdj+=(*recup).size();
+        }      
+        nbAdj -= 3;
+        totCount += nbAdj;  
+        xadj[i + 1] = xadj[i] + nbAdj;  
+        i++;
+      }
+      FIter_delete(fit);
+    }
+    else if(dim==3){
+      RIter rit = M_regionIter(mesh);
+      pRegion pr;
+      int i=0;
+      while ((pr = RIter_next(rit))) { 
+        int nbAdj = 0;
+        for(int k=0 ; k<4 ; k++) {
+          pFace pface = R_face(pr,k);
+          void* tmpptr; 
+          int is = EN_getDataPtr((pEntity) pface , tagAdj,&tmpptr);
+          assert(is);
+          std::vector<int> *recup = (std::vector<int> *) tmpptr;
+          nbAdj+=(*recup).size();
+        }      
+        nbAdj -= 4;
+        totCount += nbAdj;  
+        xadj[i + 1] = xadj[i] + nbAdj;  
+        i++;
+      }
+      RIter_delete(rit);
+    }
+
+    // --- determine the adjencies ---
+
+    int *adjncy = new int[totCount + 1];
+
+    int count = 0;
+    if(dim==2) {
+      FIter fit = M_faceIter(mesh);
+      pFace pface;
+      int i=0;
+      while ((pface = FIter_next(fit))) { 
+        assert(!pface->deleted);
+        for(int k=0 ; k<3 ; k++) {
+          pEdge pe = F_edge(pface,k);
+          void* tmpptr; 
+          int is = EN_getDataPtr((pEntity) pe , tagAdj,&tmpptr);
+          assert(is);
+          std::vector<int> *recup = (std::vector<int> *) tmpptr;
+          for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+            int iDrecup = (*recup)[j];
+            if(iDrecup != pface->iD)
+              adjncy[count++] = iDrecup;
+          }            
+        }
+        i++;
+        assert(count==(xadj[i]));
+      }
+      FIter_delete(fit);
+    }
+    else {
+      RIter rit = M_regionIter(mesh);
+      pRegion pr;
+      int i=0;
+      while ((pr = RIter_next(rit))) { 
+        assert(!pr->deleted);
+        for(int k=0 ; k<4 ; k++) {
+          pFace pface = R_face(pr,k);
+          void* tmpptr; 
+          int is = EN_getDataPtr((pEntity) pface , tagAdj,&tmpptr);
+          assert(is);
+          std::vector<int> *recup = (std::vector<int> *) tmpptr;
+          for(unsigned int j=0 ; j<(*recup).size() ; j++) {
+            int iDrecup = (*recup)[j];
+            if(iDrecup != pr->iD)
+              adjncy[count++] = iDrecup;
+          }            
+        }
+        i++;
+        assert(count==(xadj[i]));
+      }
+      RIter_delete(rit);
+    }  
+    
+    // ------------------------------------------------
+    // Call ParMetis to adapt the graph
+
+    int wgtflag = 0;
+    int numflag = 0;
+    int ncon    = 1;
+    float itr   = 1000.0;
+    int options[1];  options[0] = 0;
+    int edgecut = 0;
+    float *tpwgts, ubvec[1];
+    tpwgts  = (float *)   malloc((nproc * ncon) * sizeof(float));
+    for (int i=0; i<nproc*ncon; i++)  tpwgts[i] = 1.0/(float)(nproc);
+    ubvec[0]  = 1.05;
+    MPI_Comm comm = MPI_COMM_WORLD;
+    int *partitionVector = new int[NN]; // ParMetis output: will contain the destinations of the elements
+    ParMETIS_V3_AdaptiveRepart(vtxdist, xadj, adjncy, NULL, NULL, NULL,&wgtflag,
+                               &numflag,&ncon,&nproc,tpwgts, ubvec,&itr, 
+                               options,&edgecut, partitionVector,&comm);
+  
+    /*    ParMETIS_V3_PartKway(vtxdist, xadj, adjncy, NULL, NULL,&wgtflag,
+          &numflag,&ncon,&nproc,tpwgts, ubvec, 
+          options,&edgecut, partitionVector,&comm);
+    */
+
+    // ------------------------------------------------
+    // Tag elements to be migrated
+
+    if(dim==2) {
+      FIter fit = M_faceIter(mesh);
+      pFace pface;
+      while ((pface = FIter_next(fit))) {
+        int num  = pface->iD - mypos;
+        int dest = partitionVector[num];
+        if(dest == myrank) continue;
+        EN_attachDataInt((pEntity) pface ,tagElt, dest + 1);
+      }
+      FIter_delete(fit);
+    }
+    else if(dim==3) {
+      RIter rit = M_regionIter(mesh);
+      pRegion pr;
+      while ((pr = RIter_next(rit))) {
+        int num  = pr->iD - mypos;
+        int dest = partitionVector[num];
+        if(dest == myrank) continue;
+        EN_attachDataInt((pEntity) pr ,tagElt, dest + 1);
+      }
+      RIter_delete(rit);
+    }
+
+    // ------------------------------------------------
+    // Do some cleaning
+
+    delete [] tab;
+    delete [] vtxdist;
+    delete [] xadj;
+    delete [] partitionVector;
+
+    if(dim==2) {
+      EIter eit = M_edgeIter(mesh);
+      pEdge pe;
+      while ((pe = EIter_next(eit))) { 
+        void* tmpptr; 
+        int is = EN_getDataPtr((pEntity) pe , tagAdj,&tmpptr);
+        assert(is);
+        EN_deleteData((pEntity) pe,tagAdj);        
+      }    
+      EIter_delete(eit);  
+    } else if(dim==3) {
+      FIter fit = M_faceIter(mesh);
+      pFace pface;
+      while ((pface = FIter_next(fit))) { 
+        void* tmpptr; 
+        int is = EN_getDataPtr((pEntity) pface , tagAdj,&tmpptr);
+        assert(is);
+        EN_deleteData((pEntity) pface,tagAdj);        
+      }    
+      FIter_delete(fit);
+    }
+    MD_deleteMeshDataId(tagAdj);
+  }
+
+  // -------------------------------------------------------------------
+}
+
+#endif
+#endif
+
diff --git a/Mesh/metisAdaptiveRepart.h b/Mesh/metisAdaptiveRepart.h
new file mode 100644
index 0000000..98e8e9a
--- /dev/null
+++ b/Mesh/metisAdaptiveRepart.h
@@ -0,0 +1,32 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+//
+// Authors: Cecile Dobrzynski, Jean-Francois Remacle, Gaetan Compere
+// -------------------------------------------------------------------
+
+#ifdef PARALLEL
+#ifndef H_METISADAPTIVEREPART
+#define H_METISADAPTIVEREPART
+
+#include "MSops.h"
+
+namespace MAd {
+
+#ifdef _HAVE_PARMETIS_
+  //! Repartition (adapt) the graph of the elements over the 
+  //! set of processors and attach the destination to the 
+  //! elements under the tag 'tagElt'  \ingroup parallel
+  extern void metisAdaptiveRepart(pMesh mesh, pMeshDataId tagElt);
+#endif
+
+}
+
+#endif
+#endif
diff --git a/README b/README
new file mode 100755
index 0000000..06b5cb4
--- /dev/null
+++ b/README
@@ -0,0 +1,30 @@
+MAdLib 1.0 - README file.
+
+See the Copyright.txt, License.txt and Credits.txt files for copyright, 
+license and authors informations. You should have received a copy of 
+these files along with MAdLib. If not, see <http://www.madlib.be/license/>.
+
+Please report bugs and problems to <contrib at madlib.be>.
+
+To compile and install the MAdLib library, simply type
+ ./configure;
+ make;
+ make install;
+
+If you want to compile and install some benchmark executables, type
+ ./configure;
+ make bench;
+ make install-bin;
+
+The documentation is generated and installed automatically with the 
+previous compilations if you have Doxygen installed but you can also 
+generate it (in doc/) by
+ make doc;
+
+Note that you need a linear system solver for the benchmarks that include 
+the global node repositioning algorithm, like 'moveIt/example/tube' (for inst. PETSc) 
+and a library to compute the distance to a cloud of points (for inst. ANN) 
+for benchmarks including local size fields.
+
+To see what options are available, type
+ ./configure --help
diff --git a/Tutorial/MAdLibInterface.cpp b/Tutorial/MAdLibInterface.cpp
new file mode 100644
index 0000000..aa7764b
--- /dev/null
+++ b/Tutorial/MAdLibInterface.cpp
@@ -0,0 +1,444 @@
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+// -------------------------------------------------------------------
+// Author: Gaetan Compere
+//
+// This file provides an example of an interface to MAdLib as it 
+// could be implemented in a physical solver requiring mesh adaptivity.
+// -------------------------------------------------------------------
+
+#include "MAdLibInterface.h"
+using namespace MAd;
+
+// -------------------------------------------------------------------
+// This is an example of a callback function that takes care of a 
+// nodal solution when local mesh modifications are applied.
+// This function will be registered by 'MAdLibInterface' and will 
+// then be called during every local mesh modification.
+// --------------------------------------------------------------------
+void Solver_CBFunction (pPList before, pPList after, void *data,
+                        operationType type, pEntity ppp) {
+  
+  // Data can point to the object of type 'MAdLibInterface' for instance,
+  // depending on what pointer was given when registering the callback function
+  // It is not used in this example
+  MAdLibInterface * mi = static_cast<MAdLibInterface *>(data);
+  
+  // The data id used to identify the data attached to mesh entities
+  pMeshDataId dataId = MD_lookupMeshDataId("SolutionTag");
+
+  // Do the right manipulation on data according to the mesh modification
+  // that is currently applied
+  switch (type) {
+  case MAd_ESPLIT:
+    // Edge split case:
+    //   - 'before' contains the split edge (not deleted yet)
+    //   - 'after'  contains the two new edges
+    //   - 'ppp'    contains the new vertex
+    {
+      // find the edge to be deleted
+      void * temp = NULL;
+      pEdge pE = (pEdge) PList_next(before,&temp);
+     
+      // get coordinates and data at old nodes
+      double data0 = 0.;
+      pVertex pV0 = E_vertex((pEdge)pE, 0);
+      int gotit0 = EN_getDataDbl((pEntity)pV0, dataId,  &data0);
+      
+      double data1 = 0.;
+      pVertex pV1 = E_vertex((pEdge)pE, 1);
+      int gotit1 = EN_getDataDbl((pEntity)pV1, dataId,  &data1);
+      
+      if ( !gotit0 || !gotit1) {
+        printf("Error: one of the nodes has no data attached to\n");
+        throw;
+      }
+
+      // interpolate the data at the new vertex (here linear interpolation)
+      double t = E_linearParams(pE,(pVertex)ppp);
+      double newData = (1.-t) * data0 + t * data1;
+      
+      // attach this data to the new vertex
+      EN_attachDataDbl(ppp, dataId, newData);
+    }
+    break;
+  case MAd_ECOLLAPSE:
+    // Edge collapse case:
+    //   - 'before' contains the regions (3D) or faces (2D) of the cavity 
+    //                       before the edge collapse (not deleted yet)
+    //   - 'after'  contains the regions (3D) or faces (2D) of the cavity 
+    //                       after the edge collapse
+    //   - 'ppp'    contains the vertex to be deleted (not deleted yet)
+    {
+      // remove the data on deleted vertex
+      EN_deleteData(ppp, dataId);
+    }
+    break;
+  case MAd_FSWAP:
+    // Face swap case:
+    //   - 'before' contains the regions of the cavity before the face swap (not deleted yet)
+    //   - 'after'  contains the regions of the cavity after the face swap
+    //   - 'ppp'    contains the swapped face (not deleted yet)
+    {
+      // nothing to be done for nodal solutions
+    }
+    break;
+  case MAd_ESWAP:
+    // Edge swap case:
+    //   - 'before' contains the regions (3D) or faces (2D) of the cavity 
+    //                       before the edge swap (not deleted yet)
+    //   - 'after'  contains the regions (3D) or faces (2D) of the cavity 
+    //                       after the edge swap
+    //   - 'ppp'    contains the swapped edge (not deleted yet)
+    {
+      // nothing to be done for nodal solutions
+    }
+    break;
+  default:
+    printf("Error: no callback function should be called with this operation: %d",type);
+    throw;
+  }
+};
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+MAdLibInterface::MAdLibInterface()
+{}
+
+//-----------------------------------------------------------------------------
+MAdLibInterface::~MAdLibInterface()
+{}
+
+//-----------------------------------------------------------------------------
+// Main routine for adaptation
+void MAdLibInterface::adaptMesh()
+{
+  //-----------------------------------------------------
+  // Step 1: Prepare for adaptation
+  //-----------------------------------------------------
+
+  // 1. Delete mesh/solution dependent data in the solver
+  solver->deleteData();
+
+  // 2.A. Build the MAdLib geometrical model.
+  pGModel MAdModel = NULL;
+  GM_create(&MAdModel,"theModel");
+  exportToMAdModel(solver->getModel(), MAdModel);
+
+  // 2.B. Build the MAdLib mesh.
+  pMesh MAdMesh = M_new(MAdModel);
+  exportToMAdMesh(solver->getMesh(), MAdMesh);
+  
+  // 3. Transfer solution to the MAdLib mesh as an attached data
+  attachSolutionToMesh(MAdMesh);
+  solver->deallocateSolution();
+
+  // 4. Delete the solver mesh.
+  solver->deleteMesh();
+
+  // 5. Build the size field used in adaptation
+  PWLSField * sizeField = new PWLSField(MAdMesh);
+  buildSizeField(sizeField);
+
+  //-----------------------------------------------------
+  // Step 2: Run the adaptation
+  //-----------------------------------------------------
+
+  // 6.A. Build the adaptation tool
+  MeshAdapter * adapter = new MeshAdapter(MAdMesh,sizeField);
+  
+  // 6.B. Register the callback function(s) of the solver
+  adapter->addCallback(Solver_CBFunction,(void*)this);
+
+  // 6.C. Edit the adaptation parameters if necessary
+  adapter->setEdgeLenSqBounds( 1.0/3.0, 3.0 );
+  adapter->setNoSwapQuality( 0.1 );
+  adapter->setSliverQuality( 0.02 );
+  adapter->setSliverPermissionInESplit( true, 10. );
+  adapter->setSliverPermissionInECollapse( true, 0.1 );
+
+  // 6.D. Run the adaptation procedure
+  adapter->run();
+
+  // 6.E. Optional output
+  adapter->printStatistics(std::cout);
+  M_writeMsh(MAdMesh,"adapted_mesh.msh",2);
+
+  // 6.F. Clean the adaptation objects
+  delete adapter;
+  delete sizeField;
+
+  //-----------------------------------------------------
+  // Step 3: Rebuild solver data and mesh
+  //-----------------------------------------------------
+
+  // 7. Rebuild the solver mesh
+  importFromMAdModel(MAdModel, solver->getModel());
+  importFromMAdMesh(MAdMesh, solver->getMesh());
+
+  // 8. Get the solution from the MAdLib mesh
+  solver->allocateSolution();
+  getSolutionFromMesh(MAdMesh);
+
+  // 9. Delete MAdLib mesh
+  delete MAdMesh;
+  delete MAdModel;
+
+  // 10. Build mesh/solution dependent data in the solver
+  solver->allocateAndComputeData();
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// Converts a MAdLib mesh into a 'Solver_mesh'
+void MAdLibInterface::importFromMAdMesh(const MAd::pMesh MAdMesh, 
+                                        Solver_mesh * solverMesh)
+{
+  MAdToSolverIds.clear();
+  SolverToMAdIds.clear();
+
+  // --- Mesh dimension ---
+  int dim = M_dim(MAdMesh);
+
+  // --- Mesh size ---
+  int numVertices = M_numVertices(MAdMesh);
+  int numElements;
+  if ( dim == 3 ) numElements = M_numRegions(MAdMesh);
+  if ( dim == 2 ) numElements = M_numFaces(MAdMesh);
+
+  solverMesh->allocate(numVertices,numElements);
+
+  // --- Build vertices ---
+  int solver_Id = 0; // will allow consecutive ids for the solver mesh
+  VIter vit = M_vertexIter(MAdMesh);
+  while (pVertex pv = VIter_next(vit))
+    {
+      // get MAdLib mesh id
+      int MAd_Id = EN_id((pEntity)pv);
+
+      // get coordinates
+      double xyz[3];
+      V_coord(pv,xyz);
+      
+      // add node in solver mesh
+      solverMesh->addNode(solver_Id,xyz[0],xyz[1],xyz[2]);
+      
+      // fill in id's tables
+      MAdToSolverIds[MAd_Id] = solver_Id;
+      SolverToMAdIds[solver_Id] = MAd_Id;
+
+      solver_Id++;
+    }
+  VIter_delete(vit);
+
+  // --- Build elements ---
+  int solver_elem_Id = 0;
+  if (dim==3) {
+    RIter rit = M_regionIter(MAdMesh);
+    while (pRegion pr = RIter_next(rit))
+      {
+        // get list of node id's in the solver mesh
+        int nodes[4];
+        pPList rVerts = R_vertices(pr);
+        void * temp = NULL;
+        int iN = 0;
+        while ( pVertex pv = (pVertex)PList_next(rVerts,&temp) )
+          {
+            int MAd_Id = EN_id((pEntity)pv);
+            nodes[iN++] = MAdToSolverIds[MAd_Id];
+          }
+        PList_delete(rVerts);
+
+        // add the element to the solver mesh
+        solverMesh->addElement(solver_elem_Id, nodes);
+        solver_elem_Id++;
+      }
+    RIter_delete(rit);
+  }
+  else  if (dim==2) {
+    FIter fit = M_faceIter(MAdMesh);
+    while (pFace pf = FIter_next(fit))
+      {
+        // get list of node id's in the solver mesh
+        int nodes[3];
+        pPList fVerts = F_vertices(pf,1);
+        void * temp = NULL;
+        int iN = 0;
+        while ( pVertex pv = (pVertex)PList_next(fVerts,&temp) )
+          {
+            int MAd_Id = EN_id((pEntity)pv);
+            nodes[iN++] = MAdToSolverIds[MAd_Id];
+          }
+        PList_delete(fVerts);
+
+        // add the element to the solver mesh
+        solverMesh->addElement(solver_elem_Id, nodes);
+        solver_elem_Id++;
+      }
+    FIter_delete(fit);
+  }
+}
+
+//-----------------------------------------------------------------------------
+// Converts a 'Solver_mesh' into a MAdLib mesh
+void MAdLibInterface::exportToMAdMesh(const Solver_mesh * solverMesh, 
+                                      MAd::pMesh MAdMesh)
+{
+  // --- Build the vertices ---
+  MAdToSolverIds.clear();
+  SolverToMAdIds.clear();
+  int nVerts = solverMesh->nVertices();
+  const double ** xyz = solverMesh->getCoordinates();
+  for (int iV=0; iV < nVerts; iV++) {
+    MAdMesh->add_point(iV+1,xyz[iV][0],xyz[iV][1],xyz[iV][2]);
+    SolverToMAdIds[iV] = iV+1;
+    MAdToSolverIds[iV+1] = iV;
+  }
+
+  // --- Build the elements ---
+  int dim = solverMesh->getDim();
+  int nElems = solverMesh->nElements();
+  if (dim==3)
+    {
+      const int ** elements = solverMesh->getElements();
+      const int * elemGeoTags = solverMesh->getElemGeoTags();
+      for (int iC=0; iC < nElems; iC++) {
+        pGRegion geom = GM_regionByTag(MAdMesh->model,
+                                       elemGeoTags[iC]);
+        MAdMesh->add_tet(elements[iC][0], elements[iC][1],
+                         elements[iC][2], elements[iC][3],
+                         (pGEntity)geom); 
+      }
+    }
+  else if (dim==2)
+    {
+      const int ** elements = solverMesh->getElements();
+      const int * elemGeoTags = solverMesh->getElemGeoTags();
+      for (int iC=0; iC < nElems; iC++) {
+        pGFace geom = GM_faceByTag(MAdMesh->model,
+                                   elemGeoTags[iC]);
+        MAdMesh->add_triangle(elements[iC][0], elements[iC][1],
+                              elements[iC][2], (pGEntity)geom); 
+      }
+    }
+
+  /*
+    Here, the entities of the MAdLib mesh sould be classified
+    on their corresponding geometrical entities, like for boundary 
+    faces in 3D for instance. The implementation of this step 
+    is highly dependent on the implementation of Solver_mesh and 
+    Solver_model so it is up to the reader to add the right 
+    instructions here. 
+
+    Note that the geometrical entities have been created in the 
+    execution of 'exportToMAdModel'. Any mesh entity can be 
+    associated to a geometrical entity using the EN_setWhatIn(...) 
+    function of the MAdLib mesh interface.
+
+    Note that all the steps involving geometrical entities can be
+    replaced by appropriate constraints on boundary mesh entities
+    (see AdaptInterface.h) but no mesh modification will therefore
+    be applied on the boundaries, which can be problematic for some
+    computations.
+  */
+
+  MAdMesh->classify_unclassified_entities();
+  MAdMesh->destroyStandAloneEntities();
+}
+
+//-----------------------------------------------------------------------------
+// Create in MAdModel all geometrical entities listed in solverModel.
+void MAdLibInterface::exportToMAdModel(const Solver_model * solverModel, 
+                                       MAd::pGModel MAdModel)
+{
+  std::set<std::pair<int,int> > geometry = solverModel->getAllGeoEntities();
+  std::set<std::pair<int,int> >::const_iterator geoIter = geometry.begin();
+  for (; geoIter != geometry.end(); geoIter++) {
+    int dim = (*geoIter).first;
+    int id  = (*geoIter).second;
+    GM_entityByTag(MAdModel,dim,id);
+  }
+}
+
+//-----------------------------------------------------------------------------
+// Build a field of prescribed edges lengths on the domain.
+void MAdLibInterface::buildSizeField(MAd::PWLSField * sizeField)
+{
+  // First option: keep actual edges lengths
+  sizeField->setCurrentSize();
+
+  // Second option: compute it from solver functions
+  VIter vit = M_vertexIter(sizeField->getMesh());
+  while (pVertex pv = VIter_next(vit))
+    {
+      // get solver point id
+      int MAd_Id = EN_id((pEntity)pv);
+      int solver_Id = MAdToSolverIds[MAd_Id];
+      
+      // get the edge length prescribed by the solver
+      double length = solver->prescribedEdgeLength(solver_Id);
+
+      // fill in the size field
+      sizeField->setSize((pEntity)pv, length);
+    }
+  VIter_delete(vit);
+}
+
+//-----------------------------------------------------------------------------
+void MAdLibInterface::attachSolutionToMesh(MAd::pMesh MAdMesh)
+{
+  // Get the solution database. Here we assume that it is a nodal solution.
+  const Solver_solution * solution = solver->getSolution();
+
+  // The data id used to identify the data attached to mesh entities
+  pMeshDataId dataId = MD_lookupMeshDataId("SolutionTag");
+
+  VIter vit = M_vertexIter(MAdMesh);
+  while (pVertex pv = VIter_next(vit))
+    {
+      // get solver point id
+      int MAd_Id = EN_id((pEntity)pv);
+      int solver_Id = MAdToSolverIds[MAd_Id];
+      
+      double data = (*solution)[solver_Id];
+      
+      // attach data to the mesh vertex
+      EN_attachDataDbl((pEntity)pv,dataId,data);
+    }
+  VIter_delete(vit);
+}
+
+//-----------------------------------------------------------------------------
+void MAdLibInterface::getSolutionFromMesh(MAd::pMesh MAdMesh)
+{
+  // Get the solution database. Here we assume that it is a nodal solution.
+  Solver_solution * solution = solver->getSolution();
+
+  // The data id used to identify the data attached to mesh entities
+  pMeshDataId dataId = MD_lookupMeshDataId("SolutionTag");
+
+  VIter vit = M_vertexIter(MAdMesh);
+  while (pVertex pv = VIter_next(vit))
+    {
+      // get solver point id
+      pPoint pp = V_point(pv);
+      int MAdId = P_id(pp);
+      int solver_Id = MAdToSolverIds[MAdId];
+      
+      // get attached data and delete it
+      double data;
+      EN_getDataDbl((pEntity)pv,dataId,&data);
+      EN_deleteData((pEntity)pv,dataId);
+      
+      *(*solution)[solver_Id] = data;
+    }
+  VIter_delete(vit);
+}
+
+//-----------------------------------------------------------------------------
diff --git a/Tutorial/MAdLibInterface.h b/Tutorial/MAdLibInterface.h
new file mode 100644
index 0000000..c80f187
--- /dev/null
+++ b/Tutorial/MAdLibInterface.h
@@ -0,0 +1,139 @@
+// -*- C++ -*-
+// -------------------------------------------------------------------
+// MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+//
+// See the Copyright.txt and License.txt files for license information. 
+// You should have received a copy of these files along with MAdLib. 
+// If not, see <http://www.madlib.be/license/>
+//
+// Please report all bugs and problems to <contrib at madlib.be>
+// -------------------------------------------------------------------
+// Author: Gaetan Compere
+//
+// This file provides an example of an interface to MAdLib as it 
+// could be implemented in a physical solver requiring mesh adaptivity.
+// -------------------------------------------------------------------
+
+#ifndef __MADLIBINTERFACE_H
+#define __MADLIBINTERFACE_H
+
+#include "ModelInterface.h"
+#include "MeshDataBaseInterface.h"
+#include "AdaptInterface.h"
+#include "PWLinearSField.h"
+#include <utility>
+#include <set>
+
+//-----------------------------------------------------------------------------
+// For this example, what is needed in the solver side ?
+//-----------------------------------------------------------------------------
+
+/*
+Solver class containing the solver geometrical model if any.
+  ( Note that all the steps involving geometrical entities can be
+    replaced by appropriate constraints on boundary mesh entities
+    (see AdaptInterface.h) but no mesh modification will therefore
+    be applied on the boundaries, which can be problematic for some
+    computations. )
+*/
+class Solver_model
+{
+public:
+  void addGeoEntity(int dim, int id);
+  std::set<std::pair<int,int> > getAllGeoEntities() const;
+  // return a set of pairs(dimension,id) 
+  // each pair representing a geometric entity.
+};
+
+/*
+  Solver class containing the solver mesh
+*/
+class Solver_mesh
+{
+public:
+  void allocate (int nNodes, int nElements) {}
+  void addNode (int id, double x, double y, double z) {}
+  void addElement (int id, int * nodes) {}
+  int getDim() const {return -1;}
+  int nVertices() const {return -1;}
+  int nElements() const {return -1;}
+  const double ** getCoordinates() const {return NULL;}
+  const int ** getElements() const {return NULL;}
+  const int * getElemGeoTags() const {return NULL;}
+};
+
+/*
+  Solver solution. We assume a nodal solution but the current example can be
+  easily extended to other discretizations.
+*/
+class Solver_solution
+{
+public:
+  double * operator[](int i) {return NULL;}
+  const double operator[](int i) const {return 0.;}
+};
+
+/*
+  Solver class containing pointers to solver data, solution and mesh
+*/
+class Solver
+{
+public:
+  Solver_model    * getModel()    {return model;}
+  Solver_mesh     * getMesh()     {return mesh;}
+  Solver_solution * getSolution() {return solution;}
+  void deleteMesh() {}
+  void deallocateSolution() {}
+  void allocateSolution() {}
+  // optional functions:
+  void deleteData() {}
+  void allocateAndComputeData() {}
+  double prescribedEdgeLength(int node) {return 0.;}
+private:
+  Solver_model    * model;
+  Solver_mesh     * mesh;
+  Solver_solution * solution;
+};
+
+//-----------------------------------------------------------------------------
+// Class interfacing MAdLib with 'Solver'
+//-----------------------------------------------------------------------------
+class MAdLibInterface {
+
+public:
+   
+  MAdLibInterface();
+  ~MAdLibInterface();
+
+  void adaptMesh();
+
+private:
+
+  // Mesh to mesh conversion
+  void importFromMAdMesh(const MAd::pMesh, Solver_mesh *);
+  void exportToMAdMesh(const Solver_mesh *, MAd::pMesh);
+  void importFromMAdModel(const MAd::pGModel, Solver_model *);
+  void exportToMAdModel(const Solver_model *, MAd::pGModel);
+
+  // Size field construction
+  void buildSizeField(MAd::PWLSField *);
+
+  // Solution to solution conversion
+  void attachSolutionToMesh(MAd::pMesh);
+  void getSolutionFromMesh(MAd::pMesh);
+
+private:
+
+  // The solver that needs mesh adaptivity
+  Solver * solver;
+
+  // Correspondancy tables between nodal id's in the solver
+  // and in the MAdLib mesh
+  std::map<int,int> MAdToSolverIds;
+  std::map<int,int> SolverToMAdIds;
+};
+
+//-----------------------------------------------------------------------------
+
+#endif
+
diff --git a/Tutorial/Makefile b/Tutorial/Makefile
new file mode 100644
index 0000000..b32d126
--- /dev/null
+++ b/Tutorial/Makefile
@@ -0,0 +1,53 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information. 
+# You should have received a copy of these files along with MAdLib. 
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+include ../variables
+
+INC =  ${MAdLib_INCLUDES}\
+       ${DASH}I$(MAdROOT)/Tutorial\
+       ${DASH}I$(MAdROOT)/Geo\
+       ${DASH}I$(MAdROOT)/Mesh\
+       ${DASH}I$(MAdROOT)/Common\
+       ${DASH}I$(MAdROOT)/Adapt\
+       ${DASH}I$(MAdROOT)/Adapt/constraint\
+       ${DASH}I$(MAdROOT)/Adapt/operator\
+       ${DASH}I$(MAdROOT)/Adapt/output\
+       ${DASH}I$(MAdROOT)/Adapt/quality\
+       ${DASH}I$(MAdROOT)/Adapt/repositioning\
+       ${DASH}I$(MAdROOT)/Adapt/sizeField\
+       ${DASH}I$(MAdROOT)/Adapt/utils
+
+CXXFLAGS = ${OPTIM} ${MAdLib_DEFS} ${FLAGS} ${INC} ${SYSINCLUDE}
+
+SRC = MAdLibInterface.cc
+
+OBJ = ${SRC:.cc=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cc
+
+.cc${OBJEXT}:
+	${CXX} ${CXXFLAGS} ${DASH}c $< ${DASH}o $@
+
+build: ${OBJ}
+
+clean:
+	${RM} */*.o *.o *.obj
+
+purge:
+
+depend:
+	(sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+         ${CXX} -MM ${CXXFLAGS} ${SRC} | sed 's/.o:/$${OBJEXT}:/g' \
+        ) > Makefile.new
+	cp Makefile Makefile.bak
+	cp Makefile.new Makefile
+	rm -f Makefile.new
\ No newline at end of file
diff --git a/configure b/configure
new file mode 100755
index 0000000..5dc1d33
--- /dev/null
+++ b/configure
@@ -0,0 +1,7596 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.63 for MAdLib 1.2.3.
+#
+# Report bugs to <contrib at madlib.be>.
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+if test "x$CONFIG_SHELL" = x; then
+  if (eval ":") 2>/dev/null; then
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+
+  if test $as_have_required = yes &&	 (eval ":
+(as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=\$LINENO
+  as_lineno_2=\$LINENO
+  test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" &&
+  test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; }
+") 2> /dev/null; then
+  :
+else
+  as_candidate_shells=
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  case $as_dir in
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     as_candidate_shells="$as_candidate_shells $as_dir/$as_base"
+	   done;;
+       esac
+done
+IFS=$as_save_IFS
+
+
+      for as_shell in $as_candidate_shells $SHELL; do
+	 # Try only shells that exist, to save several forks.
+	 if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		{ ("$as_shell") 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+_ASEOF
+}; then
+  CONFIG_SHELL=$as_shell
+	       as_have_required=yes
+	       if { "$as_shell" 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+(as_func_return () {
+  (exit $1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = "$1" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test $exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; }
+
+_ASEOF
+}; then
+  break
+fi
+
+fi
+
+      done
+
+      if test "x$CONFIG_SHELL" != x; then
+  for as_var in BASH_ENV ENV
+	do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+	done
+	export CONFIG_SHELL
+	exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+
+    if test $as_have_required = no; then
+  echo This script requires a shell more modern than all the
+      echo shells that I found on your system.  Please install a
+      echo modern shell, or manually run the script under such a
+      echo shell if you do have one.
+      { (exit 1); exit 1; }
+fi
+
+
+fi
+
+fi
+
+
+
+(eval "as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0") || {
+  echo No shell found that supports shell functions.
+  echo Please tell bug-autoconf at gnu.org about your system,
+  echo including any error possibly output before this message.
+  echo This can help us improve future autoconf versions.
+  echo Configuration will now proceed without shell functions.
+}
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+	test -d "$1/.";
+      else
+	case $1 in
+	-*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+
+exec 7<&0 </dev/null 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Identity of this package.
+PACKAGE_NAME='MAdLib'
+PACKAGE_TARNAME='madlib'
+PACKAGE_VERSION='1.2.3'
+PACKAGE_STRING='MAdLib 1.2.3'
+PACKAGE_BUGREPORT='contrib at madlib.be'
+
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+MAdLib_BENCHDIRS
+MAdLib_INCLUDES
+MAdLib_LIBS
+MAdLib_DIRS
+MAdLib_TMPDIR
+MAdROOT
+MAdLib_DEFS
+LIBEXT
+LINKER
+OPTIM
+FLAGS
+HOSTNAME
+UNAME
+DOXYGEN
+DOX
+EGREP
+GREP
+CXXCPP
+AR
+RANLIB
+CPP
+ac_ct_CXX
+CXXFLAGS
+CXX
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_blas_lapack_prefix
+with_mpi_prefix
+with_autopack_prefix
+with_metis_prefix
+with_parmetis_prefix
+with_gmsh_prefix
+with_occ_prefix
+with_sparskit_prefix
+with_petsc_prefix
+with_parser_prefix
+enable_blas_lapack
+enable_ann
+enable_mathex
+enable_mpi
+enable_metis
+enable_parmetis
+enable_gmm
+enable_gmsh
+enable_occ
+enable_petsc
+enable_parser
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CXX
+CXXFLAGS
+CCC
+CPP
+CXXCPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=*)	ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *)	ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2
+   { (exit 1); exit 1; }; }
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2
+   { (exit 1); exit 1; }; }
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2
+   { (exit 1); exit 1; }; }
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2
+   { (exit 1); exit 1; }; }
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) { $as_echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; }
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+      { $as_echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+   { (exit 1); exit 1; }; }
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  { $as_echo "$as_me: error: missing argument to $ac_option" >&2
+   { (exit 1); exit 1; }; }
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) { $as_echo "$as_me: error: unrecognized options: $ac_unrecognized_opts" >&2
+   { (exit 1); exit 1; }; } ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
+		datadir sysconfdir sharedstatedir localstatedir includedir \
+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+		libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  { $as_echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; }
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used." >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  { $as_echo "$as_me: error: working directory cannot be determined" >&2
+   { (exit 1); exit 1; }; }
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  { $as_echo "$as_me: error: pwd does not report name of working directory" >&2
+   { (exit 1); exit 1; }; }
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_myself" : 'X\(//\)[^/]' \| \
+	 X"$as_myself" : 'X\(//\)$' \| \
+	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  { $as_echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+   { (exit 1); exit 1; }; }
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || { $as_echo "$as_me: error: $ac_msg" >&2
+   { (exit 1); exit 1; }; }
+	pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures MAdLib 1.2.3 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/madlib]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of MAdLib 1.2.3:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-blas-lapack    use Blas/Lapack for linear algebra (default=yes)
+  --enable-ann            use ANN library (default=no)
+  --enable-mathex         use Mathex library (default=yes)
+  --enable-mpi            enable MPI support (default=no)
+  --enable-metis          use Metis partitioner (default=no)
+  --enable-parmetis       use ParMetis partitioner (default=no)
+  --enable-gmm            compile gmm++ linear solvers (default=no)
+  --enable-gmsh           use Gmsh geometric model (default=no)
+  --enable-occ            use OpenCascade geometric model (through Gmsh)
+                          (default=no)
+  --enable-petsc          use PETSc if available (default=no)
+  --enable-parser         use Parser (restricted, CENAERO, Belgium) if
+                          available (default=no)
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-blas-lapack-prefix=PFX
+                          prefix where BLAS and LAPACK are installed
+  --with-mpi-prefix=PFX   prefix where MPI is installed
+  --with-autopack-prefix=PFX
+                          prefix where Autopack is installed
+  --with-metis-prefix=PFX prefix where Metis is installed
+  --with-parmetis-prefix=PFX
+                          prefix where ParMetis is installed
+  --with-gmsh-prefix=PFX  prefix where Gmsh is installed
+  --with-occ-prefix=PFX   prefix where OpenCascade is installed
+  --with-sparskit-prefix=PFX
+                          prefix where Sparskit is installed
+  --with-petsc-prefix=PFX prefix where PETSc is installed
+  --with-parser-prefix=PFX
+                          prefix where the parser is installed
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CXX         C++ compiler command
+  CXXFLAGS    C++ compiler flags
+  CPP         C preprocessor
+  CXXCPP      C++ preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <contrib at madlib.be>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+MAdLib configure 1.2.3
+generated by GNU Autoconf 2.63
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by MAdLib $as_me 1.2.3, which was
+generated by GNU Autoconf 2.63.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  $as_echo "PATH: $as_dir"
+done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+    2)
+      ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      ac_configure_args="$ac_configure_args '$ac_arg'"
+      ;;
+    esac
+  done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+	"s/'\''/'\''\\\\'\'''\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      cat <<\_ASBOX
+## ------------------- ##
+## File substitutions. ##
+## ------------------- ##
+_ASBOX
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	$as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  ac_site_file1=$CONFIG_SITE
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test -r "$ac_site_file"; then
+    { $as_echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special
+  # files actually), so we avoid doing that.
+  if test -f "$cache_file"; then
+    { $as_echo "$as_me:$LINENO: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:$LINENO: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	# differences in whitespace do not lead to failure.
+	ac_old_val_w=`echo x $ac_old_val`
+	ac_new_val_w=`echo x $ac_new_val`
+	if test "$ac_old_val_w" != "$ac_new_val_w"; then
+	  { $as_echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	  ac_cache_corrupted=:
+	else
+	  { $as_echo "$as_me:$LINENO: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+	  eval $ac_var=\$ac_old_val
+	fi
+	{ $as_echo "$as_me:$LINENO:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+	{ $as_echo "$as_me:$LINENO:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  { { $as_echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+$as_echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+# Check whether --with-blas-lapack-prefix was given.
+if test "${with_blas_lapack_prefix+set}" = set; then
+  withval=$with_blas_lapack_prefix; BLAS_LAPACK_PREFIX=$withval
+fi
+
+
+# Check whether --with-mpi-prefix was given.
+if test "${with_mpi_prefix+set}" = set; then
+  withval=$with_mpi_prefix; MPI_PREFIX=$withval
+fi
+
+
+# Check whether --with-autopack-prefix was given.
+if test "${with_autopack_prefix+set}" = set; then
+  withval=$with_autopack_prefix; AUTOPACK_PREFIX=$withval
+fi
+
+
+# Check whether --with-metis-prefix was given.
+if test "${with_metis_prefix+set}" = set; then
+  withval=$with_metis_prefix; METIS_PREFIX=$withval
+fi
+
+
+# Check whether --with-parmetis-prefix was given.
+if test "${with_parmetis_prefix+set}" = set; then
+  withval=$with_parmetis_prefix; PARMETIS_PREFIX=$withval
+fi
+
+
+# Check whether --with-gmsh-prefix was given.
+if test "${with_gmsh_prefix+set}" = set; then
+  withval=$with_gmsh_prefix; GMSH_PREFIX=$withval
+fi
+
+
+# Check whether --with-occ-prefix was given.
+if test "${with_occ_prefix+set}" = set; then
+  withval=$with_occ_prefix; OCC_PREFIX=$withval
+fi
+
+
+# Check whether --with-sparskit-prefix was given.
+if test "${with_sparskit_prefix+set}" = set; then
+  withval=$with_sparskit_prefix; SPARSKIT_PREFIX=$withval
+fi
+
+
+# Check whether --with-petsc-prefix was given.
+if test "${with_petsc_prefix+set}" = set; then
+  withval=$with_petsc_prefix; PETSC_PREFIX=$withval
+fi
+
+
+# Check whether --with-parser-prefix was given.
+if test "${with_parser_prefix+set}" = set; then
+  withval=$with_parser_prefix; PARSER_PREFIX=$withval
+fi
+
+
+# Check whether --enable-blas-lapack was given.
+if test "${enable_blas_lapack+set}" = set; then
+  enableval=$enable_blas_lapack;
+fi
+
+# Check whether --enable-ann was given.
+if test "${enable_ann+set}" = set; then
+  enableval=$enable_ann;
+fi
+
+# Check whether --enable-mathex was given.
+if test "${enable_mathex+set}" = set; then
+  enableval=$enable_mathex;
+fi
+
+# Check whether --enable-mpi was given.
+if test "${enable_mpi+set}" = set; then
+  enableval=$enable_mpi;
+fi
+
+# Check whether --enable-metis was given.
+if test "${enable_metis+set}" = set; then
+  enableval=$enable_metis;
+fi
+
+# Check whether --enable-parmetis was given.
+if test "${enable_parmetis+set}" = set; then
+  enableval=$enable_parmetis;
+fi
+
+# Check whether --enable-gmm was given.
+if test "${enable_gmm+set}" = set; then
+  enableval=$enable_gmm;
+fi
+
+# Check whether --enable-gmsh was given.
+if test "${enable_gmsh+set}" = set; then
+  enableval=$enable_gmsh;
+fi
+
+# Check whether --enable-occ was given.
+if test "${enable_occ+set}" = set; then
+  enableval=$enable_occ;
+fi
+
+# Check whether --enable-petsc was given.
+if test "${enable_petsc+set}" = set; then
+  enableval=$enable_petsc;
+fi
+
+# Check whether --enable-parser was given.
+if test "${enable_parser+set}" = set; then
+  enableval=$enable_parser;
+fi
+
+
+if test "x$enable_ann" != "xyes"; then
+  enable_ann=no;
+fi
+if test "x$enable_mpi" != "xyes"; then
+  enable_mpi=no;
+fi
+if test "x$enable_metis" != "xyes"; then
+  enable_metis=no;
+fi
+if test "x$enable_parmetis" != "xyes"; then
+  enable_parmetis=no;
+fi
+if test "x$enable_gmm" != "xyes"; then
+  enable_gmm=no;
+fi
+if test "x$enable_gmsh" != "xyes"; then
+  enable_gmsh=no;
+  enable_occ=no;
+fi
+if test "x$enable_occ" != "xyes"; then
+  enable_occ=no;
+fi
+if test "x$enable_petsc" != "xyes"; then
+  enable_petsc=no;
+fi
+if test "x$enable_parser" != "xyes"; then
+  enable_parser=no;
+fi
+
+UNAME=`uname`
+HOSTNAME=`hostname`
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:$LINENO: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler --version >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler -v >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler -V >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { (ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+	;;
+    [ab].out )
+	# We found the default executable, but exeext='' is most
+	# certainly right.
+	break;;
+    *.* )
+        if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+	then :; else
+	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	fi
+	# We set ac_cv_exeext here because the later test for it is not
+	# safe: cross compilers may not add the suffix if given an `-o'
+	# argument, so we may need to know it at that point already.
+	# Even if this section looks crufty: it has the advantage of
+	# actually working.
+	break;;
+    * )
+	break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+
+{ $as_echo "$as_me:$LINENO: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+if test -z "$ac_file"; then
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+  if { ac_try='./$ac_file'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+{ $as_echo "$as_me:$LINENO: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+{ $as_echo "$as_me:$LINENO: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+{ $as_echo "$as_me:$LINENO: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if test "${ac_cv_objext+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_compiler_gnu=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_compiler_gnu=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	CFLAGS=""
+      cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_c89=$ac_arg
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:$LINENO: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:$LINENO: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -z "$CXX"; then
+  if test -n "$CCC"; then
+    CXX=$CCC
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CXX+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+  { $as_echo "$as_me:$LINENO: result: $CXX" >&5
+$as_echo "$CXX" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CXX" && break
+  done
+fi
+if test -z "$CXX"; then
+  ac_ct_CXX=$CXX
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CXX"; then
+  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CXX="$ac_prog"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5
+$as_echo "$ac_ct_CXX" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CXX" && break
+done
+
+  if test "x$ac_ct_CXX" = x; then
+    CXX="g++"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CXX=$ac_ct_CXX
+  fi
+fi
+
+  fi
+fi
+# Provide some information about the compiler.
+$as_echo "$as_me:$LINENO: checking for C++ compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler --version >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler -v >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler -V >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5
+$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
+if test "${ac_cv_cxx_compiler_gnu+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_compiler_gnu=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_compiler_gnu=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5
+$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GXX=yes
+else
+  GXX=
+fi
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ $as_echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5
+$as_echo_n "checking whether $CXX accepts -g... " >&6; }
+if test "${ac_cv_prog_cxx_g+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_cxx_werror_flag=$ac_cxx_werror_flag
+   ac_cxx_werror_flag=yes
+   ac_cv_prog_cxx_g=no
+   CXXFLAGS="-g"
+   cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cxx_g=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	CXXFLAGS=""
+      cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+	 CXXFLAGS="-g"
+	 cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cxx_g=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5
+$as_echo "$ac_cv_prog_cxx_g" >&6; }
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+if test "x${CC}" = "x" -o "x${CXX}" = "x" ; then
+  { { $as_echo "$as_me:$LINENO: error: Could not find required compilers, aborting." >&5
+$as_echo "$as_me: error: Could not find required compilers, aborting." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+if test "x$enable_petsc" != "xno"; then
+
+{ $as_echo "$as_me:$LINENO: checking for main in -lpetsc" >&5
+$as_echo_n "checking for main in -lpetsc... " >&6; }
+if test "${ac_cv_lib_petsc_main+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpetsc -lpetsc $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_petsc_main=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_petsc_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_petsc_main" >&5
+$as_echo "$ac_cv_lib_petsc_main" >&6; }
+if test "x$ac_cv_lib_petsc_main" = x""yes; then
+  PETSC="yes"
+fi
+
+  if test "x${PETSC}" = "xyes"; then
+    CXX="mpic++.openmpi"
+    LINKER="mpic++.openmpi"
+  fi
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if test "${ac_cv_prog_CPP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:$LINENO: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  :
+else
+  { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+LINKER="${CXX}"
+
+FLAGS="-D_FORTIFY_SOURCE=0 -ansi "
+OPTIM="${CXXFLAGS}"
+CXXFLAGS=""
+
+MAdLib_DEFS=""
+
+case "$UNAME" in
+  CYGWIN*)
+    if test "x$enable_cygwin" != "xyes"; then
+      UNAME="${UNAME}-no-cygwin"
+      CC="${CC} -mno-cygwin"
+      CXX="${CXX} -mno-cygwin"
+      LINKER="${LINKER} -mno-cygwin"
+    fi
+    ;;
+esac
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+
+
+MAdROOT=`pwd`
+MAdLib_TMPDIR="/tmp/$USER/MAdLib"
+MAdLib_DIRS="Common Geo Mesh Adapt"
+MAdLib_LIBS="-L${MAdROOT}/lib -lMAdLib"
+MAdLib_INCLUDES=""
+MAdLib_BENCHDIRS="Benchmarks/checkMesh Benchmarks/meshInfo Benchmarks/optimize Benchmarks/moveIt"
+
+
+
+{ $as_echo "$as_me:$LINENO: checking for main in -lm" >&5
+$as_echo_n "checking for main in -lm... " >&6; }
+if test "${ac_cv_lib_m_main+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_m_main=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_m_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_m_main" >&5
+$as_echo "$ac_cv_lib_m_main" >&6; }
+if test "x$ac_cv_lib_m_main" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+  LIBS="-lm $LIBS"
+
+fi
+
+
+if test "x$enable_gmm" != "xno"; then
+  { $as_echo "$as_me:$LINENO: checking for Contrib/gmm/gmm.h" >&5
+$as_echo_n "checking for Contrib/gmm/gmm.h... " >&6; }
+if test "${ac_cv_file_Contrib_gmm_gmm_h+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  test "$cross_compiling" = yes &&
+  { { $as_echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
+$as_echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
+   { (exit 1); exit 1; }; }
+if test -r "Contrib/gmm/gmm.h"; then
+  ac_cv_file_Contrib_gmm_gmm_h=yes
+else
+  ac_cv_file_Contrib_gmm_gmm_h=no
+fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_file_Contrib_gmm_gmm_h" >&5
+$as_echo "$ac_cv_file_Contrib_gmm_gmm_h" >&6; }
+if test "x$ac_cv_file_Contrib_gmm_gmm_h" = x""yes; then
+  GMM="yes"
+fi
+
+  if test "x${GMM}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_GMM_"
+    MAdLib_INCLUDES="${MAdLib_INCLUDES} -I${MAdROOT}/Contrib/gmm"
+    cat >>confdefs.h <<\_ACEOF
+#define _HAVE_GMM_ 1
+_ACEOF
+
+    BO="${BO} Gmm"
+    echo "********************************************************************"
+    echo "  You are building a version of MAdLib that contains the gmm++"
+    echo "  linear solvers. Gmm++ is available under the GNU LGPL."
+    echo "  To disable gmm++, run configure again with the --disable-gmm"
+    echo "  option."
+    echo "********************************************************************"
+  fi
+fi
+
+if test "x$enable_gmsh" != "xno"; then
+  if test "x${GMSH_PREFIX}" != "x"; then
+    LDFLAGS="-L${GMSH_PREFIX} -L${GMSH_PREFIX}/lib ${LDFLAGS}"
+  fi
+  as_ac_File=`$as_echo "ac_cv_file_"${GMSH_PREFIX}/include/gmsh/Gmsh.h"" | $as_tr_sh`
+{ $as_echo "$as_me:$LINENO: checking for \"${GMSH_PREFIX}/include/gmsh/Gmsh.h\"" >&5
+$as_echo_n "checking for \"${GMSH_PREFIX}/include/gmsh/Gmsh.h\"... " >&6; }
+if { as_var=$as_ac_File; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  test "$cross_compiling" = yes &&
+  { { $as_echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
+$as_echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
+   { (exit 1); exit 1; }; }
+if test -r ""${GMSH_PREFIX}/include/gmsh/Gmsh.h""; then
+  eval "$as_ac_File=yes"
+else
+  eval "$as_ac_File=no"
+fi
+fi
+ac_res=`eval 'as_val=${'$as_ac_File'}
+		 $as_echo "$as_val"'`
+	       { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+as_val=`eval 'as_val=${'$as_ac_File'}
+		 $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  GMSH="yes"
+fi
+
+  if test "x${GMSH}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_GMSH_"
+    cat >>confdefs.h <<\_ACEOF
+#define _HAVE_GMSH_ 1
+_ACEOF
+
+    BO="${BO} Gmsh"
+    if test "x${GMSH_PREFIX}" = "x"; then
+      MAdLib_LIBS="${MAdLib_LIBS} -lGmsh"
+    else
+      MAdLib_LIBS="${MAdLib_LIBS} -L${GMSH_PREFIX} -L${GMSH_PREFIX}/lib -lGmsh"
+      FLAGS="${FLAGS} -I${GMSH_PREFIX} -I${GMSH_PREFIX}/include"
+    fi
+    echo "********************************************************************"
+    echo "  You are building a version of MAdLib that uses Gmsh and. Gmsh is "
+    echo "  available under the GNU GPL."
+    echo "  To disable Gmsh, run configure again with"
+    echo "  the --disable-gmsh and --disable-gsl options."
+    echo "  Note that you should disable Chaco and Metis in Gmsh or add"
+    echo "  the corresponding libraries in the current version of MAdLib."
+    echo "********************************************************************"
+  fi
+fi
+
+if test "x$enable_occ" != "xno"; then
+  if test "x${OCC_PREFIX}" != "x"; then
+    LDFLAGS="-L${OCC_PREFIX} -L${OCC_PREFIX}/lib ${LDFLAGS}"
+  fi
+  { $as_echo "$as_me:$LINENO: checking for main in -lTKernel" >&5
+$as_echo_n "checking for main in -lTKernel... " >&6; }
+if test "${ac_cv_lib_TKernel_main+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lTKernel -lTKernel $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_TKernel_main=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_TKernel_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_TKernel_main" >&5
+$as_echo "$ac_cv_lib_TKernel_main" >&6; }
+if test "x$ac_cv_lib_TKernel_main" = x""yes; then
+  OCC="yes"
+fi
+
+  if test "x${OCC}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_OCC_"
+    cat >>confdefs.h <<\_ACEOF
+#define _HAVE_OCC_ 1
+_ACEOF
+
+    BO="${BO} OpenCascade"
+    if test "x${OCC_PREFIX}" != "x"; then
+      MAdLib_LIBS="${MAdLib_LIBS} -L${OCC_PREFIX}/lib "
+      FLAGS="${FLAGS} -I${OCC_PREFIX}/include"
+    fi
+    # DataExchange (subset; see occ/ros/adm/make/Makefile for more info)
+    MAdLib_LIBS="${MAdLib_LIBS} -lTKSTEP -lTKSTEP209 -lTKSTEPAttr -lTKSTEPBase -lTKIGES -lTKXSBase"
+    # ModelingAlgorithms
+    MAdLib_LIBS="${MAdLib_LIBS} -lTKOffset -lTKFeat -lTKFillet -lTKBool -lTKShHealing"
+    MAdLib_LIBS="${MAdLib_LIBS} -lTKMesh -lTKHLR -lTKBO -lTKPrim -lTKTopAlgo -lTKGeomAlgo"
+    # ModelingData
+    MAdLib_LIBS="${MAdLib_LIBS} -lTKBRep -lTKGeomBase -lTKG3d -lTKG2d"
+    # FoundationClasses
+    MAdLib_LIBS="${MAdLib_LIBS} -lTKAdvTools -lTKMath -lTKernel"
+
+    #MAdLib_LIBS="${MAdLib_LIBS} -lTKAdvTools -lTKBO -lTKBool -lTKBRep -lTKernel -lTKFeat -lTKFillet -lTKG2d -lTKG3d -lTKGeomAlgo -lTKGeomBase -lTKHLR -lTKIGES -lTKMath -lTKMesh -lTKOffset -lTKPrim -lTKShHealing -lTKSTEP209 -lTKSTEP -lTKSTEPAttr -lTKSTEPBase -lTKTopAlgo -lTKXSBase"
+  fi
+fi
+
+if test "x$enable_ann" != "xno"; then
+  { $as_echo "$as_me:$LINENO: checking for Contrib/ANN/include/ANN/ANN.h" >&5
+$as_echo_n "checking for Contrib/ANN/include/ANN/ANN.h... " >&6; }
+if test "${ac_cv_file_Contrib_ANN_include_ANN_ANN_h+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  test "$cross_compiling" = yes &&
+  { { $as_echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
+$as_echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
+   { (exit 1); exit 1; }; }
+if test -r "Contrib/ANN/include/ANN/ANN.h"; then
+  ac_cv_file_Contrib_ANN_include_ANN_ANN_h=yes
+else
+  ac_cv_file_Contrib_ANN_include_ANN_ANN_h=no
+fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_file_Contrib_ANN_include_ANN_ANN_h" >&5
+$as_echo "$ac_cv_file_Contrib_ANN_include_ANN_ANN_h" >&6; }
+if test "x$ac_cv_file_Contrib_ANN_include_ANN_ANN_h" = x""yes; then
+  ANN="yes"
+fi
+
+  if test "x${ANN}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_ANN_"
+    cat >>confdefs.h <<\_ACEOF
+#define _HAVE_ANN_ 1
+_ACEOF
+
+    BO="${BO} Ann"
+    MAdLib_DIRS="Contrib/ANN ${MAdLib_DIRS}"
+    MAdLib_INCLUDES="${MAdLib_INCLUDES} -I${MAdROOT}/Contrib/ANN/include"
+    MAdLib_LIBS="${MAdLib_LIBS} -lMAdANN"
+    FLAGS="${FLAGS} -I${MAdROOT}/Contrib/ANN/include"
+    echo "********************************************************************"
+    echo "  You are building a version of MAdLib that uses ANN, the"
+    echo "  Approximate Nearest Neighbor library. ANN is available under the"
+    echo "  GNU LGPL. To disable ANN, run configure again with the"
+    echo "  --disable-ann option."
+    echo "********************************************************************"
+  fi
+fi
+
+if test "x$enable_mathex" != "xno"; then
+  { $as_echo "$as_me:$LINENO: checking for Contrib/mathex/mathex.h" >&5
+$as_echo_n "checking for Contrib/mathex/mathex.h... " >&6; }
+if test "${ac_cv_file_Contrib_mathex_mathex_h+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  test "$cross_compiling" = yes &&
+  { { $as_echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
+$as_echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
+   { (exit 1); exit 1; }; }
+if test -r "Contrib/mathex/mathex.h"; then
+  ac_cv_file_Contrib_mathex_mathex_h=yes
+else
+  ac_cv_file_Contrib_mathex_mathex_h=no
+fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_file_Contrib_mathex_mathex_h" >&5
+$as_echo "$ac_cv_file_Contrib_mathex_mathex_h" >&6; }
+if test "x$ac_cv_file_Contrib_mathex_mathex_h" = x""yes; then
+  MATHEX="yes"
+fi
+
+  if test "x${MATHEX}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_MATHEX_"
+    MAdLib_INCLUDES="${MAdLib_INCLUDES} -I${MAdROOT}/Contrib/mathex"
+    cat >>confdefs.h <<\_ACEOF
+#define _HAVE_MATHEX_ 1
+_ACEOF
+
+    BO="${BO} Mathex"
+    echo "********************************************************************"
+    echo "  You are building a version of MAdLib that contains Mathex."
+    echo "  Mathex is available under the GNU LGPL. To disable Mathex, run "
+    echo "  configure again with the --disable-mathex option."
+    echo "********************************************************************"
+  fi
+fi
+
+if test "x$enable_petsc" != "xno"; then
+  if test "x${PETSC_PREFIX}" != "x"; then
+    LDFLAGS="-L${PETSC_PREFIX} -L${PETSC_PREFIX}/lib ${LDFLAGS}"
+  fi
+  { $as_echo "$as_me:$LINENO: checking for main in -lpetsc" >&5
+$as_echo_n "checking for main in -lpetsc... " >&6; }
+if test "${ac_cv_lib_petsc_main+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpetsc -lpetsc $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_petsc_main=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_petsc_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_petsc_main" >&5
+$as_echo "$ac_cv_lib_petsc_main" >&6; }
+if test "x$ac_cv_lib_petsc_main" = x""yes; then
+  PETSC="yes"
+fi
+
+  if test "x${PETSC}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_PETSC_"
+    cat >>confdefs.h <<\_ACEOF
+#define _HAVE_PETSC_ 1
+_ACEOF
+
+    BO="${BO} PETSc"
+    if test "x${PETSC_PREFIX}" = "x"; then
+      MAdLib_LIBS="${MAdLib_LIBS} -lpetsc -lpetscksp -lpetscmat -lpetscvec "
+    else
+      MAdLib_LIBS="${MAdLib_LIBS} -L${PETSC_PREFIX} -L${PETSC_PREFIX}/lib -lpetsc -lpetscksp -lpetscmat -lpetscvec "
+      FLAGS="${FLAGS} -I${PETSC_PREFIX} -I${PETSC_PREFIX}/include"
+    fi
+  fi
+fi
+
+if test "x$enable_metis" != "xno"; then
+  if test "x${METIS_PREFIX}" != "x"; then
+    LDFLAGS="-L${METIS_PREFIX} -L${METIS_PREFIX}/lib ${LDFLAGS}"
+  fi
+  { $as_echo "$as_me:$LINENO: checking for main in -lmetis" >&5
+$as_echo_n "checking for main in -lmetis... " >&6; }
+if test "${ac_cv_lib_metis_main+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lmetis -lmetis $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_metis_main=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_metis_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_metis_main" >&5
+$as_echo "$ac_cv_lib_metis_main" >&6; }
+if test "x$ac_cv_lib_metis_main" = x""yes; then
+  METIS="yes"
+fi
+
+  if test "x${METIS}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_METIS_"
+    cat >>confdefs.h <<\_ACEOF
+#define _HAVE_METIS_ 1
+_ACEOF
+
+    BO="${BO} Metis"
+    if test "x${METIS_PREFIX}" = "x"; then
+      MAdLib_LIBS="${MAdLib_LIBS} -lmetis"
+    else
+      MAdLib_LIBS="${MAdLib_LIBS} -L${METIS_PREFIX} -L${METIS_PREFIX}/lib -lmetis"
+      FLAGS="${FLAGS} -I${METIS_PREFIX} -I${METIS_PREFIX}/include"
+    fi
+  fi
+fi
+
+if test "x$enable_parmetis" != "xno"; then
+  if test "x${PARMETIS_PREFIX}" != "x"; then
+    LDFLAGS="-L${PARMETIS_PREFIX} -L${PARMETIS_PREFIX}/lib ${LDFLAGS}"
+  fi
+  { $as_echo "$as_me:$LINENO: checking for main in -lmetis" >&5
+$as_echo_n "checking for main in -lmetis... " >&6; }
+if test "${ac_cv_lib_metis_main+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lmetis -lmetis $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_metis_main=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_metis_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_metis_main" >&5
+$as_echo "$ac_cv_lib_metis_main" >&6; }
+if test "x$ac_cv_lib_metis_main" = x""yes; then
+  METIS="yes"
+fi
+
+  { $as_echo "$as_me:$LINENO: checking for main in -lparmetis" >&5
+$as_echo_n "checking for main in -lparmetis... " >&6; }
+if test "${ac_cv_lib_parmetis_main+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lparmetis -lparmetis $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_parmetis_main=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_parmetis_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_parmetis_main" >&5
+$as_echo "$ac_cv_lib_parmetis_main" >&6; }
+if test "x$ac_cv_lib_parmetis_main" = x""yes; then
+  PARMETIS="yes"
+fi
+
+  if test "x${METIS}" = "xyes"; then
+    if test "x${PARMETIS}" = "xyes"; then
+      MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_PARMETIS_"
+      cat >>confdefs.h <<\_ACEOF
+#define _HAVE_PARMETIS_ 1
+_ACEOF
+
+      BO="${BO} Parmetis"
+      if test "x${PARMETIS_PREFIX}" = "x"; then
+        MAdLib_LIBS="${MAdLib_LIBS} -lparmetis -lmetis"
+      else
+        MAdLib_LIBS="${MAdLib_LIBS} -L${PARMETIS_PREFIX} -L${PARMETIS_PREFIX}/lib -lparmetis -lmetis"
+        FLAGS="${FLAGS} -I${PARMETIS_PREFIX} -I${PARMETIS_PREFIX}/include"
+      fi
+    fi
+  fi
+fi
+
+
+  if test "x${BLAS_LAPACK_PREFIX}" != "x"; then
+    LDFLAGS="-L${BLAS_LAPACK_PREFIX} -L${BLAS_LAPACK_PREFIX}/lib ${LDFLAGS}"
+  fi
+  { $as_echo "$as_me:$LINENO: checking for cblas_dgemm in -lcblas" >&5
+$as_echo_n "checking for cblas_dgemm in -lcblas... " >&6; }
+if test "${ac_cv_lib_cblas_cblas_dgemm+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcblas  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char cblas_dgemm ();
+int
+main ()
+{
+return cblas_dgemm ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_cblas_cblas_dgemm=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_cblas_cblas_dgemm=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_cblas_cblas_dgemm" >&5
+$as_echo "$ac_cv_lib_cblas_cblas_dgemm" >&6; }
+if test "x$ac_cv_lib_cblas_cblas_dgemm" = x""yes; then
+  CBLAS="yes" BLAS_LIBS="-lcblas"
+fi
+
+  if test "x${CBLAS}" != "xyes"; then
+    { $as_echo "$as_me:$LINENO: checking for cblas_dgemm in -lcblas" >&5
+$as_echo_n "checking for cblas_dgemm in -lcblas... " >&6; }
+if test "${ac_cv_lib_cblas_cblas_dgemm+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcblas -latlas $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char cblas_dgemm ();
+int
+main ()
+{
+return cblas_dgemm ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_cblas_cblas_dgemm=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_cblas_cblas_dgemm=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_cblas_cblas_dgemm" >&5
+$as_echo "$ac_cv_lib_cblas_cblas_dgemm" >&6; }
+if test "x$ac_cv_lib_cblas_cblas_dgemm" = x""yes; then
+  CBLAS="yes" BLAS_LIBS="-lcblas -latlas"
+fi
+
+  fi
+  if test "x${CBLAS}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_BLAS_"
+    cat >>confdefs.h <<\_ACEOF
+#define _HAVE_BLAS_ 1
+_ACEOF
+
+    BO="${BO} Cblas"
+  else
+    if test "x${GSL}" = "xyes"; then
+            BLAS_LIBS="-lgslcblas"
+      MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_BLAS_"
+      cat >>confdefs.h <<\_ACEOF
+#define _HAVE_BLAS_ 1
+_ACEOF
+
+      BO="${BO} Cblas"
+    fi
+  fi
+
+if test "x${FM}" = "xyes" -o "x${GSL}" != "xyes"; then
+  { $as_echo "$as_me:$LINENO: checking for ATL_xerbla in -latlas" >&5
+$as_echo_n "checking for ATL_xerbla in -latlas... " >&6; }
+if test "${ac_cv_lib_atlas_ATL_xerbla+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-latlas  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ATL_xerbla ();
+int
+main ()
+{
+return ATL_xerbla ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_atlas_ATL_xerbla=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_atlas_ATL_xerbla=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_atlas_ATL_xerbla" >&5
+$as_echo "$ac_cv_lib_atlas_ATL_xerbla" >&6; }
+if test "x$ac_cv_lib_atlas_ATL_xerbla" = x""yes; then
+  { $as_echo "$as_me:$LINENO: checking for dgemm_ in -lf77blas" >&5
+$as_echo_n "checking for dgemm_ in -lf77blas... " >&6; }
+if test "${ac_cv_lib_f77blas_dgemm_+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lf77blas -latlas $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dgemm_ ();
+int
+main ()
+{
+return dgemm_ ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_f77blas_dgemm_=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_f77blas_dgemm_=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_f77blas_dgemm_" >&5
+$as_echo "$ac_cv_lib_f77blas_dgemm_" >&6; }
+if test "x$ac_cv_lib_f77blas_dgemm_" = x""yes; then
+  BLAS="yes" BLAS_LIBS="${BLAS_LIBS} -lf77blas -latlas"
+fi
+
+fi
+
+  if test "x${BLAS}" != "xyes"; then
+    { $as_echo "$as_me:$LINENO: checking for dgemm_ in -lblas" >&5
+$as_echo_n "checking for dgemm_ in -lblas... " >&6; }
+if test "${ac_cv_lib_blas_dgemm_+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lblas  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dgemm_ ();
+int
+main ()
+{
+return dgemm_ ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_blas_dgemm_=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_blas_dgemm_=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_blas_dgemm_" >&5
+$as_echo "$ac_cv_lib_blas_dgemm_" >&6; }
+if test "x$ac_cv_lib_blas_dgemm_" = x""yes; then
+  BLAS="yes" BLAS_LIBS="${BLAS_LIBS} -lblas"
+fi
+
+  fi
+  if test "x${BLAS}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_BLAS_"
+    MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_BLAS"
+    cat >>confdefs.h <<\_ACEOF
+#define HAVE_BLAS 1
+_ACEOF
+
+    BO="${BO} Blas"
+    { $as_echo "$as_me:$LINENO: checking for dbdsqr_ in -llapack" >&5
+$as_echo_n "checking for dbdsqr_ in -llapack... " >&6; }
+if test "${ac_cv_lib_lapack_dbdsqr_+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-llapack ${BLAS_LIBS} $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dbdsqr_ ();
+int
+main ()
+{
+return dbdsqr_ ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_lapack_dbdsqr_=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_lapack_dbdsqr_=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_lapack_dbdsqr_" >&5
+$as_echo "$ac_cv_lib_lapack_dbdsqr_" >&6; }
+if test "x$ac_cv_lib_lapack_dbdsqr_" = x""yes; then
+  LAPACK="yes" BLAS_LIBS="-llapack ${BLAS_LIBS}"
+fi
+
+    if test "x${LAPACK}" = "xyes"; then
+      MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_LAPACK_"
+      MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_LAPACK"
+      cat >>confdefs.h <<\_ACEOF
+#define HAVE_LAPACK 1
+_ACEOF
+
+      BO="${BO} Lapack"
+    fi
+  fi
+fi
+
+if test "x${BLAS_LIBS}" != "x"; then
+  if test "x${BLAS_LAPACK_PREFIX}" != "x"; then
+    MAdLib_LIBS="${MAdLib_LIBS} -L${BLAS_LAPACK_PREFIX} -L${BLAS_LAPACK_PREFIX}/lib ${BLAS_LIBS}"
+  else
+    MAdLib_LIBS="${MAdLib_LIBS} ${BLAS_LIBS}"
+  fi
+fi
+
+if test "x$enable_mpi" = "xyes"; then
+  if test "x${MPI_PREFIX}" != "x"; then
+    LDFLAGS="-L${MPI_PREFIX}/lib ${LDFLAGS}"
+  fi
+  { $as_echo "$as_me:$LINENO: checking for main in -lmpi" >&5
+$as_echo_n "checking for main in -lmpi... " >&6; }
+if test "${ac_cv_lib_mpi_main+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lmpi  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_mpi_main=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_mpi_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_mpi_main" >&5
+$as_echo "$ac_cv_lib_mpi_main" >&6; }
+if test "x$ac_cv_lib_mpi_main" = x""yes; then
+  MPI="yes"
+fi
+
+  if test "x${MPI}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_MPI_ -DPARALLEL"
+    cat >>confdefs.h <<\_ACEOF
+#define _HAVE_MPI_ 1
+_ACEOF
+
+    cat >>confdefs.h <<\_ACEOF
+#define PARALLEL 1
+_ACEOF
+
+    BO="${BO} Mpi"
+    echo "********************************************************************"
+    echo "Warning: MAdLib is configured with MPI enabled. It may be necessary"
+    echo "to specify the values of the CXX and LINKER variables."
+    echo "********************************************************************"
+    if test "x${MPI_PREFIX}" = "x"; then
+      MAdLib_LIBS="${MAdLib_LIBS} -lmpi"
+      FLAGS="${FLAGS} -I/usr/include/mpi"
+    else
+      MAdLib_LIBS="${MAdLib_LIBS} -L${MPI_PREFIX}/lib -lmpi"
+      FLAGS="${FLAGS} -I${MPI_PREFIX}/include"
+    fi
+  fi
+fi
+
+if test "x$enable_mpi" = "xyes"; then
+  if test "x${AUTOPACK_PREFIX}" != "x"; then
+    LDFLAGS="-L${AUTOPACK_PREFIX}/lib ${LDFLAGS}"
+  fi
+  { $as_echo "$as_me:$LINENO: checking for main in -lautopack" >&5
+$as_echo_n "checking for main in -lautopack... " >&6; }
+if test "${ac_cv_lib_autopack_main+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lautopack  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_autopack_main=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_autopack_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_autopack_main" >&5
+$as_echo "$ac_cv_lib_autopack_main" >&6; }
+if test "x$ac_cv_lib_autopack_main" = x""yes; then
+  AUTOPACK="yes"
+fi
+
+  if test "x${AUTOPACK}" = "xyes"; then
+    BO="${BO} Autopack"
+    if test "x${AUTOPACK_PREFIX}" = "x"; then
+      MAdLib_LIBS="${MAdLib_LIBS} -lautopack"
+    else
+      MAdLib_LIBS="${MAdLib_LIBS} -L${AUTOPACK_PREFIX}/lib -lautopack"
+      FLAGS="${FLAGS} -I${AUTOPACK_PREFIX}/include"
+    fi
+  fi
+fi
+
+if test "x$enable_parser" = "xyes"; then
+  if test "x${PARSER_PREFIX}" != "x"; then
+    LDFLAGS="-L${PARSER_PREFIX}/lib ${LDFLAGS}"
+  fi
+  { $as_echo "$as_me:$LINENO: checking for main in -lParser" >&5
+$as_echo_n "checking for main in -lParser... " >&6; }
+if test "${ac_cv_lib_Parser_main+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lParser  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_Parser_main=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_Parser_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_Parser_main" >&5
+$as_echo "$ac_cv_lib_Parser_main" >&6; }
+if test "x$ac_cv_lib_Parser_main" = x""yes; then
+  PARSER="yes"
+fi
+
+  if test "x${PARSER}" = "xyes"; then
+    BO="${BO} Parser"
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_PARSER_"
+    cat >>confdefs.h <<\_ACEOF
+#define _HAVE_PARSER_ 1
+_ACEOF
+
+    if test "x${PARSER_PREFIX}" = "x"; then
+      MAdLib_LIBS="${MAdLib_LIBS} -lParser"
+    else
+      MAdLib_LIBS="${MAdLib_LIBS} -L${PARSER_PREFIX}/lib -lParser"
+      FLAGS="${FLAGS} -I${PARSER_PREFIX}/include"
+    fi
+  fi
+fi
+
+case "$UNAME" in
+  Darwin*)
+    RANLIB=true
+    AR="libtool -o"
+    LIBEXT=".a"
+    ;;
+  Linux*)
+    RANLIB=true
+    AR="${CXX} -shared -o"
+    LIBEXT=".so"
+    CXXFLAGS="${CXXFLAGS} -fPIC"
+    ;;
+  *)
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  { $as_echo "$as_me:$LINENO: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_RANLIB="ranlib"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_RANLIB" = x; then
+    RANLIB=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    RANLIB=$ac_ct_RANLIB
+  fi
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+    # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_path_AR+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  case $AR in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_AR="$AR" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_AR="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+AR=$ac_cv_path_AR
+if test -n "$AR"; then
+  { $as_echo "$as_me:$LINENO: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    if test "x${AR}" = "x:"; then
+      { { $as_echo "$as_me:$LINENO: error: Could not find the library archiver, aborting." >&5
+$as_echo "$as_me: error: Could not find the library archiver, aborting." >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+    AR="${AR} ruvs"
+    LIBEXT=".a"
+    ;;
+esac
+
+MAdLib_LIBS="${MAdLib_LIBS} -lm"
+
+case "$UNAME" in
+
+  CYGWIN* | MINGW*)
+            LINKER="${LINKER} -mwindows -Wl,--stack,16777216"
+    if test "x$enable_cygwin" != "xyes"; then
+      MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+      cat >>confdefs.h <<\_ACEOF
+#define HAVE_NO_DLL 1
+_ACEOF
+
+      BO="${BO} NoDll"
+    fi
+    if test "x${OCC}" = "xyes"; then
+      MAdLib_LIBS="${MAdLib_LIBS} -lwinspool -lws2_32"
+    fi
+    if test "x$enable_gui" != "xno"; then
+      MAdLib_LIBS="${MAdLib_LIBS} Fltk/Win32Icon.res"
+    fi
+    ;;
+
+  Darwin*)
+    MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+    cat >>confdefs.h <<\_ACEOF
+#define HAVE_NO_DLL 1
+_ACEOF
+
+    BO="${BO} NoDll"
+    if test "x$enable_universal" = "xyes"; then
+      FLAGS="-arch ppc -arch i386 ${FLAGS}"
+    fi
+    if test "x$enable_gui" = "xno"; then
+      MAdLib_LIBS="${MAdLib_LIBS} -framework ApplicationServices"
+    fi
+    ;;
+
+  AIX*)
+    MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+    cat >>confdefs.h <<\_ACEOF
+#define HAVE_NO_DLL 1
+_ACEOF
+
+    BO="${BO} NoDll"
+    FLAGS="-D_BSD ${FLAGS}"
+    ;;
+
+  IRIX*)
+        case "${CXX}" in
+      *CC*)
+                        FLAGS="-LANG:std -OPT:Olimit=0 -DOLDCINCLUDE ${FLAGS}"
+        AR="${CXX} -ar -o"
+        LINKER="${CXX}"
+        ;;
+    esac
+    ;;
+
+  OSF1*)
+    MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_SOCKLEN_T"
+    cat >>confdefs.h <<\_ACEOF
+#define HAVE_NO_SOCKLEN_T 1
+_ACEOF
+
+    BO="${BO} NoSocklenT"
+        case "${CXX}" in
+      *cxx*)
+        FLAGS="-D__USE_STD_IOSTREAM ${FLAGS}"
+        ;;
+    esac
+    ;;
+
+  SunOS*)
+    MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+    cat >>confdefs.h <<\_ACEOF
+#define HAVE_NO_DLL 1
+_ACEOF
+
+    BO="${BO} NoDll"
+    MAdLib_LIBS="${MAdLib_LIBS} -lsocket -lnsl -ldl"
+    ;;
+
+  HP-UX*)
+    MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+    cat >>confdefs.h <<\_ACEOF
+#define HAVE_NO_DLL 1
+_ACEOF
+
+    BO="${BO} NoDll"
+    ;;
+
+esac
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+{ $as_echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5
+$as_echo_n "checking how to run the C++ preprocessor... " >&6; }
+if test -z "$CXXCPP"; then
+  if test "${ac_cv_prog_CXXCPP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CXXCPP needs to be expanded
+    for CXXCPP in "$CXX -E" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  break
+fi
+
+    done
+    ac_cv_prog_CXXCPP=$CXXCPP
+
+fi
+  CXXCPP=$ac_cv_prog_CXXCPP
+else
+  ac_cv_prog_CXXCPP=$CXXCPP
+fi
+{ $as_echo "$as_me:$LINENO: result: $CXXCPP" >&5
+$as_echo "$CXXCPP" >&6; }
+ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  :
+else
+  { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }; }
+fi
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+{ $as_echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    { { $as_echo "$as_me:$LINENO: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+$as_echo "$as_me: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:$LINENO: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    { { $as_echo "$as_me:$LINENO: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+$as_echo "$as_me: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_header_stdc=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_header_stdc=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then
+  :
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -rf conftest.dSYM
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  eval "$as_ac_Header=yes"
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+		 $as_echo "$as_val"'`
+	       { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+as_val=`eval 'as_val=${'$as_ac_Header'}
+		 $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:$LINENO: checking size of size_t" >&5
+$as_echo_n "checking size of size_t... " >&6; }
+if test "${ac_cv_sizeof_size_t+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (size_t))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (size_t))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_lo=`expr $ac_mid + 1`
+			if test $ac_lo -le $ac_mid; then
+			  ac_lo= ac_hi=
+			  break
+			fi
+			ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (size_t))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (size_t))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_hi=`expr '(' $ac_mid ')' - 1`
+			if test $ac_mid -le $ac_hi; then
+			  ac_lo= ac_hi=
+			  break
+			fi
+			ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (size_t))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_size_t=$ac_lo;;
+'') if test "$ac_cv_type_size_t" = yes; then
+     { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (size_t)
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot compute sizeof (size_t)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }; }
+   else
+     ac_cv_sizeof_size_t=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+static long int longval () { return (long int) (sizeof (size_t)); }
+static unsigned long int ulongval () { return (long int) (sizeof (size_t)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (size_t))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (size_t))))
+	return 1;
+      fprintf (f, "%ld", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (size_t))))
+	return 1;
+      fprintf (f, "%lu", i);
+    }
+  /* Do not output a trailing newline, as this causes \r\n confusion
+     on some platforms.  */
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_size_t=`cat conftest.val`
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_size_t" = yes; then
+     { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (size_t)
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot compute sizeof (size_t)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }; }
+   else
+     ac_cv_sizeof_size_t=0
+   fi
+fi
+rm -rf conftest.dSYM
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_sizeof_size_t" >&5
+$as_echo "$ac_cv_sizeof_size_t" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_SIZE_T $ac_cv_sizeof_size_t
+_ACEOF
+
+
+if test $ac_cv_sizeof_size_t != 4; then
+  if test $ac_cv_sizeof_size_t != 8; then
+    { $as_echo "$as_me:$LINENO: WARNING: Unsupported size of size_t - this may affect FNV hashing." >&5
+$as_echo "$as_me: WARNING: Unsupported size of size_t - this may affect FNV hashing." >&2;}
+  else
+    MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_64BIT_SIZE_T"
+    cat >>confdefs.h <<\_ACEOF
+#define HAVE_64BIT_SIZE_T 1
+_ACEOF
+
+    BO="${BO} Have64BitSizeT"
+    if test "x${OCC}" = "xyes"; then
+      FLAGS="${FLAGS} -D_OCC64"
+    fi
+  fi
+fi
+
+DOX=""
+# Extract the first word of "doxygen", so it can be a program name with args.
+set dummy doxygen; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_DOX+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DOX"; then
+  ac_cv_prog_DOX="$DOX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_DOX=""yes""
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_prog_DOX" && ac_cv_prog_DOX=""no""
+fi
+fi
+DOX=$ac_cv_prog_DOX
+if test -n "$DOX"; then
+  { $as_echo "$as_me:$LINENO: result: $DOX" >&5
+$as_echo "$DOX" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+if test "x${DOX}" = "xyes"; then
+  DOXYGEN="doxygen"
+else
+  DOXYGEN=""
+fi
+
+
+ac_config_headers="$ac_config_headers MAdConfig.h:MAdConfig.h.in"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ac_config_files="$ac_config_files variables"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes (double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \).
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    test "x$cache_file" != "x/dev/null" &&
+      { $as_echo "$as_me:$LINENO: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+    cat confcache >$cache_file
+  else
+    { $as_echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+	test -d "$1/.";
+      else
+	case $1 in
+	-*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+
+# Save the log message, to keep $[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by MAdLib $as_me 1.2.3, which was
+generated by GNU Autoconf 2.63.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTION]... [FILE]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+      --header=FILE[:TEMPLATE]
+                   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to <bug-autoconf at gnu.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_version="\\
+MAdLib config.status 1.2.3
+configured by $0, generated by GNU Autoconf 2.63,
+  with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2008 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    CONFIG_FILES="$CONFIG_FILES '$ac_optarg'"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    CONFIG_HEADERS="$CONFIG_HEADERS '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    { $as_echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; };;
+  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) { $as_echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; } ;;
+
+  *) ac_config_targets="$ac_config_targets $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "MAdConfig.h") CONFIG_HEADERS="$CONFIG_HEADERS MAdConfig.h:MAdConfig.h.in" ;;
+    "variables") CONFIG_FILES="$CONFIG_FILES variables" ;;
+
+  *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+$as_echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp=
+  trap 'exit_status=$?
+  { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+' 0
+  trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -n "$tmp" && test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} ||
+{
+   $as_echo "$as_me: cannot create a temporary directory in ." >&2
+   { (exit 1); exit 1; }
+}
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr='
'
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\).*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\).*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = ""
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
+  || { { $as_echo "$as_me:$LINENO: error: could not setup config files machinery" >&5
+$as_echo "$as_me: error: could not setup config files machinery" >&2;}
+   { (exit 1); exit 1; }; }
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=/{
+s/:*\$(srcdir):*/:/
+s/:*\${srcdir}:*/:/
+s/:*@srcdir@:*/:/
+s/^\([^=]*=[	 ]*\):*/\1/
+s/:*$//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+  ac_t=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_t"; then
+    break
+  elif $ac_last_try; then
+    { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_HEADERS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_HEADERS" >&2;}
+   { (exit 1); exit 1; }; }
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any.  Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[	 ]*#[	 ]*define[	 ][	 ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  for (key in D) D_is_set[key] = 1
+  FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+  line = \$ 0
+  split(line, arg, " ")
+  if (arg[1] == "#") {
+    defundef = arg[2]
+    mac1 = arg[3]
+  } else {
+    defundef = substr(arg[1], 2)
+    mac1 = arg[2]
+  }
+  split(mac1, mac2, "(") #)
+  macro = mac2[1]
+  prefix = substr(line, 1, index(line, defundef) - 1)
+  if (D_is_set[macro]) {
+    # Preserve the white space surrounding the "#".
+    print prefix "define", macro P[macro] D[macro]
+    next
+  } else {
+    # Replace #undef with comments.  This is necessary, for example,
+    # in the case of _POSIX_SOURCE, which is predefined and required
+    # on some systems where configure will not decide to define it.
+    if (defundef == "undef") {
+      print "/*", prefix defundef, macro, "*/"
+      next
+    }
+  }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+  { { $as_echo "$as_me:$LINENO: error: could not setup config headers machinery" >&5
+$as_echo "$as_me: error: could not setup config headers machinery" >&2;}
+   { (exit 1); exit 1; }; }
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    "
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: invalid tag $ac_tag" >&5
+$as_echo "$as_me: error: invalid tag $ac_tag" >&2;}
+   { (exit 1); exit 1; }; };;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   { { $as_echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5
+$as_echo "$as_me: error: cannot find input file: $ac_f" >&2;}
+   { (exit 1); exit 1; }; };;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      ac_file_inputs="$ac_file_inputs '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+	`' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:$LINENO: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$tmp/stdin" \
+      || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; } ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  { as_dir="$ac_dir"
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+$as_echo "$as_me: error: cannot create directory $as_dir" >&2;}
+   { (exit 1); exit 1; }; }; }
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p
+'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+    s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
+  || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; }
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&2;}
+
+  rm -f "$tmp/stdin"
+  case $ac_file in
+  -) cat "$tmp/out" && rm -f "$tmp/out";;
+  *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
+  esac \
+  || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; }
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs"
+    } >"$tmp/config.h" \
+      || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; }
+    if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$tmp/config.h" "$ac_file" \
+	|| { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \
+      || { { $as_echo "$as_me:$LINENO: error: could not create -" >&5
+$as_echo "$as_me: error: could not create -" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+ ;;
+
+
+  esac
+
+done # for ac_tag
+
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  { { $as_echo "$as_me:$LINENO: error: write failure creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: write failure creating $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || { (exit 1); exit 1; }
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:$LINENO: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
+echo "********************************************************************"
+echo "MAdLib is configured for"
+echo "  - OS           : ${UNAME} on ${HOSTNAME}"
+echo "  - C++ compiler : ${CXX}"
+echo "  - Exe linker   : ${LINKER}"
+echo "  - Lib linker   : ${AR}"
+echo "  - Optimization : ${OPTIM}"
+echo "  - C++ flags    : ${CXXFLAGS}"
+echo "  - Build options: ${BO}"
+echo "********************************************************************"
+echo "Edit 'variables' and 'MAdConfig.h' to fine-tune the config"
+echo "********************************************************************"
+
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..6ff1238
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,694 @@
+dnl -------------------------------------------------------------------
+dnl MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+
+dnl See the Copyright.txt and License.txt files for license information. 
+dnl You should have received a copy of these files along with MAdLib. 
+dnl If not, see <http://www.madlib.be/license/>
+
+dnl Please report all bugs and problems to <contrib at madlib.be>
+
+dnl Authors: Gaetan Compere, Jean-Francois Remacle
+dnl -------------------------------------------------------------------
+
+dnl Process this file with autoconf to produce the configure script.
+
+dnl Check that this is the MAdLib source tree
+dnl AC_INIT(Mesh/MeshDataBaseInterface.h)
+AC_INIT([MAdLib], [1.2.3], [contrib at madlib.be])
+
+dnl Parse '--with' command-line options
+AC_ARG_WITH(blas-lapack-prefix,
+            AC_HELP_STRING([--with-blas-lapack-prefix=PFX],
+                           [prefix where BLAS and LAPACK are installed]),
+            [BLAS_LAPACK_PREFIX=$withval])
+dnl AC_ARG_WITH(gsl-prefix,
+dnl             AC_HELP_STRING([--with-gsl-prefix=PFX],
+dnl                            [prefix where the GSL is installed]),
+dnl             [GSL_PREFIX=$withval])
+AC_ARG_WITH(mpi-prefix,
+            AC_HELP_STRING([--with-mpi-prefix=PFX],
+                           [prefix where MPI is installed]),
+            [MPI_PREFIX=$withval])
+AC_ARG_WITH(autopack-prefix,
+            AC_HELP_STRING([--with-autopack-prefix=PFX],
+                           [prefix where Autopack is installed]),
+            [AUTOPACK_PREFIX=$withval])
+AC_ARG_WITH(metis-prefix,
+            AC_HELP_STRING([--with-metis-prefix=PFX],
+                           [prefix where Metis is installed]),
+            [METIS_PREFIX=$withval])
+AC_ARG_WITH(parmetis-prefix,
+            AC_HELP_STRING([--with-parmetis-prefix=PFX],
+                           [prefix where ParMetis is installed]),
+            [PARMETIS_PREFIX=$withval])
+AC_ARG_WITH(gmsh-prefix,
+            AC_HELP_STRING([--with-gmsh-prefix=PFX],
+                           [prefix where Gmsh is installed]),
+            [GMSH_PREFIX=$withval])
+AC_ARG_WITH(occ-prefix,
+            AC_HELP_STRING([--with-occ-prefix=PFX],
+                           [prefix where OpenCascade is installed]),
+            [OCC_PREFIX=$withval])
+AC_ARG_WITH(sparskit-prefix,
+            AC_HELP_STRING([--with-sparskit-prefix=PFX],
+                           [prefix where Sparskit is installed]),
+            [SPARSKIT_PREFIX=$withval])
+AC_ARG_WITH(petsc-prefix,
+            AC_HELP_STRING([--with-petsc-prefix=PFX],
+                           [prefix where PETSc is installed]),
+            [PETSC_PREFIX=$withval])
+AC_ARG_WITH(parser-prefix,
+            AC_HELP_STRING([--with-parser-prefix=PFX],
+                           [prefix where the parser is installed]),
+            [PARSER_PREFIX=$withval])
+
+dnl Parse '--enable' command line options
+AC_ARG_ENABLE(blas-lapack,
+              AC_HELP_STRING([--enable-blas-lapack],
+                             [use Blas/Lapack for linear algebra (default=yes)]))
+AC_ARG_ENABLE(ann,
+              AC_HELP_STRING([--enable-ann],
+                             [use ANN library (default=no)]))
+AC_ARG_ENABLE(mathex,
+              AC_HELP_STRING([--enable-mathex],
+                             [use Mathex library (default=yes)]))
+dnl AC_ARG_ENABLE(gsl,
+dnl               AC_HELP_STRING([--enable-gsl],
+dnl                              [use GSL as numerical toolkit (default=no)]))
+AC_ARG_ENABLE(mpi,
+              AC_HELP_STRING([--enable-mpi],
+                             [enable MPI support (default=no)]))
+AC_ARG_ENABLE(metis,
+              AC_HELP_STRING([--enable-metis],
+                             [use Metis partitioner (default=no)]))
+AC_ARG_ENABLE(parmetis,
+              AC_HELP_STRING([--enable-parmetis],
+                             [use ParMetis partitioner (default=no)]))
+AC_ARG_ENABLE(gmm,
+              AC_HELP_STRING([--enable-gmm],
+                             [compile gmm++ linear solvers (default=no)]))
+AC_ARG_ENABLE(gmsh,
+              AC_HELP_STRING([--enable-gmsh],
+                             [use Gmsh geometric model (default=no)]))
+AC_ARG_ENABLE(occ,
+              AC_HELP_STRING([--enable-occ],
+                             [use OpenCascade geometric model (through Gmsh) (default=no)]))
+AC_ARG_ENABLE(petsc,
+              AC_HELP_STRING([--enable-petsc],
+                             [use PETSc if available (default=no)]))
+AC_ARG_ENABLE(parser,
+              AC_HELP_STRING([--enable-parser],
+                             [use Parser (restricted, CENAERO, Belgium) if available (default=no)]))
+
+dnl Disable options when disabled by default and not marked as enabled
+if test "x$enable_ann" != "xyes"; then
+  enable_ann=no;
+fi
+dnl if test "x$enable_gsl" != "xyes"; then
+dnl   enable_gsl=no;
+dnl fi
+if test "x$enable_mpi" != "xyes"; then
+  enable_mpi=no;
+fi
+if test "x$enable_metis" != "xyes"; then
+  enable_metis=no;
+fi
+if test "x$enable_parmetis" != "xyes"; then
+  enable_parmetis=no;
+fi
+if test "x$enable_gmm" != "xyes"; then
+  enable_gmm=no;
+fi
+if test "x$enable_gmsh" != "xyes"; then
+  enable_gmsh=no;
+  enable_occ=no;
+fi
+if test "x$enable_occ" != "xyes"; then
+  enable_occ=no;
+fi
+if test "x$enable_petsc" != "xyes"; then
+  enable_petsc=no;
+fi
+if test "x$enable_parser" != "xyes"; then
+  enable_parser=no;
+fi
+
+dnl Get the operating system and machine names
+UNAME=`uname`
+HOSTNAME=`hostname`
+
+dnl Check for default compilers
+AC_PROG_CC
+AC_PROG_CXX
+if test "x${CC}" = "x" -o "x${CXX}" = "x" ; then
+  AC_MSG_ERROR([Could not find required compilers, aborting.])
+fi
+
+dnl Change the compiler if PETSc is used
+if test "x$enable_petsc" != "xno"; then
+  AC_CHECK_LIB(petsc,main,PETSC="yes",[],-lpetsc)
+  if test "x${PETSC}" = "xyes"; then
+    CXX="mpic++.openmpi"
+    LINKER="mpic++.openmpi"
+  fi
+fi
+
+dnl Set preprocessor and linker
+AC_PROG_CPP
+LINKER="${CXX}"
+
+dnl Set default compiler flags
+FLAGS="-D_FORTIFY_SOURCE=0 -ansi "
+OPTIM="${CXXFLAGS}"
+CXXFLAGS=""
+
+dnl Set default definitions
+MAdLib_DEFS=""
+
+dnl Take care of no-cygwin option before doing any other tests
+case "$UNAME" in
+  CYGWIN*)
+    if test "x$enable_cygwin" != "xyes"; then
+      UNAME="${UNAME}-no-cygwin"
+      CC="${CC} -mno-cygwin"
+      CXX="${CXX} -mno-cygwin"
+      LINKER="${LINKER} -mno-cygwin"
+    fi
+    ;;
+esac
+
+dnl Use c++ for all compilation tests
+AC_LANG(C++)
+
+dnl See if we need a .exe extension on executables
+AC_EXEEXT
+
+dnl Locate sources
+MAdROOT=`pwd`
+MAdLib_TMPDIR="/tmp/$USER/MAdLib"
+MAdLib_DIRS="Common Geo Mesh Adapt"
+MAdLib_LIBS="-L${MAdROOT}/lib -lMAdLib"
+MAdLib_INCLUDES=""
+dnl MAdLib_LIBS="-L${MAdROOT}/lib -lMAdAdapt -lMAdMesh -lMAdGeo -lMAdCommon"
+MAdLib_BENCHDIRS="Benchmarks/checkMesh Benchmarks/meshInfo Benchmarks/optimize Benchmarks/moveIt"
+
+dnl Check for standard math library (no rule given if found, so gets
+dnl added to $LIBS, used for further checks)
+AC_CHECK_LIB(m,main)
+
+dnl Check for gmm++ linear solver
+if test "x$enable_gmm" != "xno"; then
+  AC_CHECK_FILE(Contrib/gmm/gmm.h,GMM="yes")
+  if test "x${GMM}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_GMM_"
+    MAdLib_INCLUDES="${MAdLib_INCLUDES} -I${MAdROOT}/Contrib/gmm"
+    AC_DEFINE(_HAVE_GMM_)
+    BO="${BO} Gmm"
+    echo "********************************************************************"
+    echo "  You are building a version of MAdLib that contains the gmm++"
+    echo "  linear solvers. Gmm++ is available under the GNU LGPL."
+    echo "  To disable gmm++, run configure again with the --disable-gmm"
+    echo "  option."
+    echo "********************************************************************"
+  fi
+fi
+
+dnl Check for Gmsh
+if test "x$enable_gmsh" != "xno"; then
+  if test "x${GMSH_PREFIX}" != "x"; then
+    LDFLAGS="-L${GMSH_PREFIX} -L${GMSH_PREFIX}/lib ${LDFLAGS}"
+  fi
+  AC_CHECK_FILE("${GMSH_PREFIX}/include/gmsh/Gmsh.h",GMSH="yes") 
+dnl  AC_CHECK_LIB(Gmsh,main,GMSH="yes",[],-lGmsh)
+  if test "x${GMSH}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_GMSH_"
+    AC_DEFINE(_HAVE_GMSH_)
+    BO="${BO} Gmsh"
+    if test "x${GMSH_PREFIX}" = "x"; then
+dnl       MAdLib_LIBS="${MAdLib_LIBS} -lGmsh -lgsl"
+      MAdLib_LIBS="${MAdLib_LIBS} -lGmsh"
+    else
+dnl       MAdLib_LIBS="${MAdLib_LIBS} -L${GMSH_PREFIX} -L${GMSH_PREFIX}/lib -lGmsh -lgsl"
+      MAdLib_LIBS="${MAdLib_LIBS} -L${GMSH_PREFIX} -L${GMSH_PREFIX}/lib -lGmsh"
+      FLAGS="${FLAGS} -I${GMSH_PREFIX} -I${GMSH_PREFIX}/include"
+    fi
+dnl     echo "********************************************************************"
+dnl     echo "  You are building a version of MAdLib that uses Gmsh and" 
+dnl     echo "  the GNU GSL. Gmsh and the GNU GSL are available under the GNU GPL."
+dnl     echo "  To disable Gmsh and the GNU GSL, run configure again with"
+dnl     echo "  the --disable-gmsh and --disable-gsl options."
+dnl     echo "  Note that you should disable Chaco and Metis in Gmsh or add"
+dnl     echo "  the corresponding libraries in the current version of MAdLib."
+dnl     echo "********************************************************************"
+    echo "********************************************************************"
+    echo "  You are building a version of MAdLib that uses Gmsh and. Gmsh is "
+    echo "  available under the GNU GPL."
+    echo "  To disable Gmsh, run configure again with"
+    echo "  the --disable-gmsh and --disable-gsl options."
+    echo "  Note that you should disable Chaco and Metis in Gmsh or add"
+    echo "  the corresponding libraries in the current version of MAdLib."
+    echo "********************************************************************"
+  fi
+fi
+
+dnl Check for OpenCascade
+if test "x$enable_occ" != "xno"; then
+  if test "x${OCC_PREFIX}" != "x"; then
+    LDFLAGS="-L${OCC_PREFIX} -L${OCC_PREFIX}/lib ${LDFLAGS}"
+  fi
+dnl  AC_CHECK_FILE("${OCC_PREFIX}/inc/Geom_Curve.hxx",OCC="yes") 
+  AC_CHECK_LIB(TKernel,main,OCC="yes",[],-lTKernel)
+  if test "x${OCC}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_OCC_"
+    AC_DEFINE(_HAVE_OCC_)
+    BO="${BO} OpenCascade"
+    if test "x${OCC_PREFIX}" != "x"; then
+      MAdLib_LIBS="${MAdLib_LIBS} -L${OCC_PREFIX}/lib "
+      FLAGS="${FLAGS} -I${OCC_PREFIX}/include"
+    fi
+    # DataExchange (subset; see occ/ros/adm/make/Makefile for more info)
+    MAdLib_LIBS="${MAdLib_LIBS} -lTKSTEP -lTKSTEP209 -lTKSTEPAttr -lTKSTEPBase -lTKIGES -lTKXSBase"
+    # ModelingAlgorithms
+    MAdLib_LIBS="${MAdLib_LIBS} -lTKOffset -lTKFeat -lTKFillet -lTKBool -lTKShHealing"
+    MAdLib_LIBS="${MAdLib_LIBS} -lTKMesh -lTKHLR -lTKBO -lTKPrim -lTKTopAlgo -lTKGeomAlgo"
+    # ModelingData
+    MAdLib_LIBS="${MAdLib_LIBS} -lTKBRep -lTKGeomBase -lTKG3d -lTKG2d"
+    # FoundationClasses
+    MAdLib_LIBS="${MAdLib_LIBS} -lTKAdvTools -lTKMath -lTKernel"
+
+    #MAdLib_LIBS="${MAdLib_LIBS} -lTKAdvTools -lTKBO -lTKBool -lTKBRep -lTKernel -lTKFeat -lTKFillet -lTKG2d -lTKG3d -lTKGeomAlgo -lTKGeomBase -lTKHLR -lTKIGES -lTKMath -lTKMesh -lTKOffset -lTKPrim -lTKShHealing -lTKSTEP209 -lTKSTEP -lTKSTEPAttr -lTKSTEPBase -lTKTopAlgo -lTKXSBase"
+  fi
+fi
+
+dnl Check for ANN, the Approximate Nearest Neighbor library
+if test "x$enable_ann" != "xno"; then
+  AC_CHECK_FILE(Contrib/ANN/include/ANN/ANN.h,ANN="yes") 
+  if test "x${ANN}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_ANN_"
+    AC_DEFINE(_HAVE_ANN_)
+    BO="${BO} Ann"
+    MAdLib_DIRS="Contrib/ANN ${MAdLib_DIRS}"
+    MAdLib_INCLUDES="${MAdLib_INCLUDES} -I${MAdROOT}/Contrib/ANN/include" 
+    MAdLib_LIBS="${MAdLib_LIBS} -lMAdANN"
+    FLAGS="${FLAGS} -I${MAdROOT}/Contrib/ANN/include"
+    echo "********************************************************************"
+    echo "  You are building a version of MAdLib that uses ANN, the"
+    echo "  Approximate Nearest Neighbor library. ANN is available under the"
+    echo "  GNU LGPL. To disable ANN, run configure again with the"
+    echo "  --disable-ann option."
+    echo "********************************************************************"
+  fi
+fi
+
+dnl Check for Mathex
+if test "x$enable_mathex" != "xno"; then
+  AC_CHECK_FILE(Contrib/mathex/mathex.h,MATHEX="yes")
+  if test "x${MATHEX}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_MATHEX_"
+    MAdLib_INCLUDES="${MAdLib_INCLUDES} -I${MAdROOT}/Contrib/mathex"
+    AC_DEFINE(_HAVE_MATHEX_)
+    BO="${BO} Mathex"
+    echo "********************************************************************"
+    echo "  You are building a version of MAdLib that contains Mathex."
+    echo "  Mathex is available under the GNU LGPL. To disable Mathex, run "
+    echo "  configure again with the --disable-mathex option."
+    echo "********************************************************************"
+  fi
+fi
+
+dnl Check for PETSc solvers
+if test "x$enable_petsc" != "xno"; then
+  if test "x${PETSC_PREFIX}" != "x"; then
+    LDFLAGS="-L${PETSC_PREFIX} -L${PETSC_PREFIX}/lib ${LDFLAGS}"
+  fi
+  AC_CHECK_LIB(petsc,main,PETSC="yes",[],-lpetsc)
+  if test "x${PETSC}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_PETSC_"
+    AC_DEFINE(_HAVE_PETSC_)
+    BO="${BO} PETSc"
+    if test "x${PETSC_PREFIX}" = "x"; then
+      MAdLib_LIBS="${MAdLib_LIBS} -lpetsc -lpetscksp -lpetscmat -lpetscvec "
+    else
+      MAdLib_LIBS="${MAdLib_LIBS} -L${PETSC_PREFIX} -L${PETSC_PREFIX}/lib -lpetsc -lpetscksp -lpetscmat -lpetscvec "
+      FLAGS="${FLAGS} -I${PETSC_PREFIX} -I${PETSC_PREFIX}/include"
+    fi
+  fi
+fi
+
+dnl Check for Metis partitionner
+if test "x$enable_metis" != "xno"; then
+  if test "x${METIS_PREFIX}" != "x"; then
+    LDFLAGS="-L${METIS_PREFIX} -L${METIS_PREFIX}/lib ${LDFLAGS}"
+  fi
+  AC_CHECK_LIB(metis,main,METIS="yes",[],-lmetis)
+  if test "x${METIS}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_METIS_"
+    AC_DEFINE(_HAVE_METIS_)
+    BO="${BO} Metis"
+    if test "x${METIS_PREFIX}" = "x"; then
+      MAdLib_LIBS="${MAdLib_LIBS} -lmetis"
+    else
+      MAdLib_LIBS="${MAdLib_LIBS} -L${METIS_PREFIX} -L${METIS_PREFIX}/lib -lmetis"
+      FLAGS="${FLAGS} -I${METIS_PREFIX} -I${METIS_PREFIX}/include"
+    fi
+  fi
+fi
+
+dnl Check for ParMetis partitionner
+if test "x$enable_parmetis" != "xno"; then
+  if test "x${PARMETIS_PREFIX}" != "x"; then
+    LDFLAGS="-L${PARMETIS_PREFIX} -L${PARMETIS_PREFIX}/lib ${LDFLAGS}"
+  fi
+  AC_CHECK_LIB(metis,main,METIS="yes",[],-lmetis)
+  AC_CHECK_LIB(parmetis,main,PARMETIS="yes",[],-lparmetis)
+  if test "x${METIS}" = "xyes"; then
+    if test "x${PARMETIS}" = "xyes"; then
+      MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_PARMETIS_"
+      AC_DEFINE(_HAVE_PARMETIS_)
+      BO="${BO} Parmetis"
+      if test "x${PARMETIS_PREFIX}" = "x"; then
+        MAdLib_LIBS="${MAdLib_LIBS} -lparmetis -lmetis"
+      else
+        MAdLib_LIBS="${MAdLib_LIBS} -L${PARMETIS_PREFIX} -L${PARMETIS_PREFIX}/lib -lparmetis -lmetis"
+        FLAGS="${FLAGS} -I${PARMETIS_PREFIX} -I${PARMETIS_PREFIX}/include"
+      fi
+    fi
+  fi
+fi
+
+dnl Check for GSL
+dnl if test "x$enable_gsl" != "xno"; then
+dnl   if test "x${GSL_PREFIX}" != "x"; then
+dnl     LDFLAGS="-L${GSL_PREFIX} -L${GSL_PREFIX}/lib ${LDFLAGS}"
+dnl   fi
+dnl   AC_CHECK_LIB(gsl,main,GSL="yes",[],-lgslcblas)
+dnl   if test "x${GSL}" = "xyes"; then
+dnl     MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_GSL_"
+dnl     AC_DEFINE(_HAVE_GSL_)
+dnl     BO="${BO} Gsl"
+dnl     if test "x${GSL_PREFIX}" = "x"; then
+dnl       MAdLib_LIBS="${MAdLib_LIBS} -lgsl"
+dnl     else
+dnl       MAdLib_LIBS="${MAdLib_LIBS} -L${GSL_PREFIX} -L${GSL_PREFIX}/lib -lgsl"
+dnl       FLAGS="${FLAGS} -I${GSL_PREFIX} -I${GSL_PREFIX}/include"
+dnl     fi
+dnl   fi
+dnl fi
+
+dnl Check for C version of BLAS
+  if test "x${BLAS_LAPACK_PREFIX}" != "x"; then
+    LDFLAGS="-L${BLAS_LAPACK_PREFIX} -L${BLAS_LAPACK_PREFIX}/lib ${LDFLAGS}"
+  fi
+  AC_CHECK_LIB(cblas,cblas_dgemm,CBLAS="yes" BLAS_LIBS="-lcblas")
+  if test "x${CBLAS}" != "xyes"; then
+    AC_CHECK_LIB(cblas,cblas_dgemm,CBLAS="yes" BLAS_LIBS="-lcblas -latlas",[],-latlas)
+  fi
+  if test "x${CBLAS}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_BLAS_"
+    AC_DEFINE(_HAVE_BLAS_)
+    BO="${BO} Cblas"
+  else 
+    if test "x${GSL}" = "xyes"; then
+      dnl use unoptimized gsl version
+      BLAS_LIBS="-lgslcblas"
+      MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_BLAS_"
+      AC_DEFINE(_HAVE_BLAS_)
+      BO="${BO} Cblas"
+    fi
+  fi
+
+dnl Check for Fortran version of blas and lapack (only used when not
+dnl using GSL, or of FourierModel is linked in)
+if test "x${FM}" = "xyes" -o "x${GSL}" != "xyes"; then
+dnl   AC_PROG_F77
+dnl   case "${F77}" in
+dnl     *gfortran*)
+dnl       F77LIB="-lgfortran"
+dnl       ;;
+dnl     *g77*)
+dnl       F77LIB="-lg2c"
+dnl       ;;
+dnl     *)
+dnl       F77LIB=""
+dnl       ;;
+dnl   esac
+dnl   LDFLAGS="${LDFLAGS} ${F77LIB}"
+  AC_CHECK_LIB(atlas,ATL_xerbla,
+    AC_CHECK_LIB(f77blas,dgemm_,
+     [BLAS="yes" BLAS_LIBS="${BLAS_LIBS} -lf77blas -latlas"],[],-latlas))
+  if test "x${BLAS}" != "xyes"; then
+    AC_CHECK_LIB(blas,dgemm_,[BLAS="yes" BLAS_LIBS="${BLAS_LIBS} -lblas"])
+  fi
+  if test "x${BLAS}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_BLAS_"
+    MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_BLAS"
+    AC_DEFINE(HAVE_BLAS)
+    BO="${BO} Blas"
+    AC_CHECK_LIB(lapack,dbdsqr_,
+      [LAPACK="yes" BLAS_LIBS="-llapack ${BLAS_LIBS}"],[],${BLAS_LIBS})
+    if test "x${LAPACK}" = "xyes"; then
+      MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_LAPACK_"
+      MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_LAPACK"
+      AC_DEFINE(HAVE_LAPACK)
+      BO="${BO} Lapack"
+    fi
+  fi
+fi
+
+if test "x${BLAS_LIBS}" != "x"; then
+  if test "x${BLAS_LAPACK_PREFIX}" != "x"; then
+    MAdLib_LIBS="${MAdLib_LIBS} -L${BLAS_LAPACK_PREFIX} -L${BLAS_LAPACK_PREFIX}/lib ${BLAS_LIBS}"
+  else
+    MAdLib_LIBS="${MAdLib_LIBS} ${BLAS_LIBS}"
+  fi
+fi
+
+dnl Check for MPI
+if test "x$enable_mpi" = "xyes"; then
+  if test "x${MPI_PREFIX}" != "x"; then
+    LDFLAGS="-L${MPI_PREFIX}/lib ${LDFLAGS}"
+  fi
+  AC_CHECK_LIB(mpi,main,MPI="yes")
+  if test "x${MPI}" = "xyes"; then
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_MPI_ -DPARALLEL"
+    AC_DEFINE(_HAVE_MPI_)
+    AC_DEFINE(PARALLEL)
+    BO="${BO} Mpi"
+    echo "********************************************************************"
+    echo "Warning: MAdLib is configured with MPI enabled. It may be necessary"
+    echo "to specify the values of the CXX and LINKER variables."
+    echo "********************************************************************"
+    if test "x${MPI_PREFIX}" = "x"; then
+      MAdLib_LIBS="${MAdLib_LIBS} -lmpi"
+      FLAGS="${FLAGS} -I/usr/include/mpi"
+    else
+      MAdLib_LIBS="${MAdLib_LIBS} -L${MPI_PREFIX}/lib -lmpi"
+      FLAGS="${FLAGS} -I${MPI_PREFIX}/include"
+    fi
+  fi
+fi
+
+dnl Check for Autopack
+if test "x$enable_mpi" = "xyes"; then
+  if test "x${AUTOPACK_PREFIX}" != "x"; then
+    LDFLAGS="-L${AUTOPACK_PREFIX}/lib ${LDFLAGS}"
+  fi
+  AC_CHECK_LIB(autopack,main,AUTOPACK="yes")
+  if test "x${AUTOPACK}" = "xyes"; then
+    BO="${BO} Autopack"
+    if test "x${AUTOPACK_PREFIX}" = "x"; then
+      MAdLib_LIBS="${MAdLib_LIBS} -lautopack"
+    else
+      MAdLib_LIBS="${MAdLib_LIBS} -L${AUTOPACK_PREFIX}/lib -lautopack"
+      FLAGS="${FLAGS} -I${AUTOPACK_PREFIX}/include"
+    fi
+  fi
+fi
+
+dnl Check for Parser
+if test "x$enable_parser" = "xyes"; then
+  if test "x${PARSER_PREFIX}" != "x"; then
+    LDFLAGS="-L${PARSER_PREFIX}/lib ${LDFLAGS}"
+  fi
+  AC_CHECK_LIB(Parser,main,PARSER="yes")
+  if test "x${PARSER}" = "xyes"; then
+    BO="${BO} Parser"
+    MAdLib_DEFS="${MAdLib_DEFS} -D_HAVE_PARSER_"
+    AC_DEFINE(_HAVE_PARSER_)
+    if test "x${PARSER_PREFIX}" = "x"; then
+      MAdLib_LIBS="${MAdLib_LIBS} -lParser"
+    else
+      MAdLib_LIBS="${MAdLib_LIBS} -L${PARSER_PREFIX}/lib -lParser"
+      FLAGS="${FLAGS} -I${PARSER_PREFIX}/include"
+    fi
+  fi
+fi
+
+dnl How to build static libraries?
+dnl Done after every AC_CHECK_LIB, otherwise AC_CHECK_LIB fails-> to be fixed
+case "$UNAME" in
+  Darwin*)
+    RANLIB=true
+    AR="libtool -o"
+    LIBEXT=".a"
+    ;;
+  Linux*)
+    RANLIB=true
+    AR="${CXX} -shared -o"
+    LIBEXT=".so"
+    CXXFLAGS="${CXXFLAGS} -fPIC"
+    ;;
+  *)
+    AC_PROG_RANLIB
+    AC_PATH_PROG(AR, ar)
+    if test "x${AR}" = "x:"; then
+      AC_MSG_ERROR([Could not find the library archiver, aborting.])
+    fi
+    AR="${AR} ruvs"
+    LIBEXT=".a"
+    ;;
+esac
+
+dnl Finish link line
+MAdLib_LIBS="${MAdLib_LIBS} -lm"
+
+dnl Modify defaults according to OS
+case "$UNAME" in
+
+  CYGWIN* | MINGW*)
+    dnl increase stack size to 16Mb to avoid stack overflows in
+    dnl recursive tet classification for large 3D Delaunay grids
+    LINKER="${LINKER} -mwindows -Wl,--stack,16777216"
+    if test "x$enable_cygwin" != "xyes"; then
+      MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+      AC_DEFINE(HAVE_NO_DLL)
+      BO="${BO} NoDll"
+    fi
+    if test "x${OCC}" = "xyes"; then
+      MAdLib_LIBS="${MAdLib_LIBS} -lwinspool -lws2_32"
+    fi
+    if test "x$enable_gui" != "xno"; then
+      MAdLib_LIBS="${MAdLib_LIBS} Fltk/Win32Icon.res"
+    fi
+    ;;
+
+  Darwin*)
+    MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+    AC_DEFINE(HAVE_NO_DLL)
+    BO="${BO} NoDll"
+    if test "x$enable_universal" = "xyes"; then
+      FLAGS="-arch ppc -arch i386 ${FLAGS}"
+    fi
+    if test "x$enable_gui" = "xno"; then
+      MAdLib_LIBS="${MAdLib_LIBS} -framework ApplicationServices"
+    fi
+    ;;
+
+  AIX*)
+    MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+    AC_DEFINE(HAVE_NO_DLL)
+    BO="${BO} NoDll"
+    FLAGS="-D_BSD ${FLAGS}"
+    ;;
+
+  IRIX*)
+    dnl options for native SGI compiler
+    case "${CXX}" in
+      *CC*)
+        dnl add "-mips3 -n32" to FLAGS, AR and LINKER for portable 32 bit exe
+        dnl "-DOLDCINCLUDE" is for Netgen
+        FLAGS="-LANG:std -OPT:Olimit=0 -DOLDCINCLUDE ${FLAGS}"
+        AR="${CXX} -ar -o"
+        LINKER="${CXX}"
+        ;;
+    esac
+    ;;
+
+  OSF1*)
+    MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_SOCKLEN_T"
+    AC_DEFINE(HAVE_NO_SOCKLEN_T)
+    BO="${BO} NoSocklenT"
+    dnl options for native DEC compiler
+    case "${CXX}" in
+      *cxx*)
+        FLAGS="-D__USE_STD_IOSTREAM ${FLAGS}"
+        ;;
+    esac
+    ;;
+
+  SunOS*)
+    MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+    AC_DEFINE(HAVE_NO_DLL)
+    BO="${BO} NoDll"
+    MAdLib_LIBS="${MAdLib_LIBS} -lsocket -lnsl -ldl"
+    ;;
+
+  HP-UX*)
+    MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_NO_DLL"
+    AC_DEFINE(HAVE_NO_DLL)
+    BO="${BO} NoDll"
+    ;;
+
+esac
+
+dnl Check sizeof size_t (flag as 64 if not 32)
+AC_CHECK_SIZEOF([size_t])
+if test $ac_cv_sizeof_size_t != 4; then
+  if test $ac_cv_sizeof_size_t != 8; then
+    AC_MSG_WARN([Unsupported size of size_t - this may affect FNV hashing.])
+  else
+    MAdLib_DEFS="${MAdLib_DEFS} -DHAVE_64BIT_SIZE_T"
+    AC_DEFINE(HAVE_64BIT_SIZE_T)
+    BO="${BO} Have64BitSizeT"
+    if test "x${OCC}" = "xyes"; then
+      FLAGS="${FLAGS} -D_OCC64"
+    fi
+  fi
+fi
+
+dnl Check for Doxygen (to produce the documentation)
+DOX=""
+AC_CHECK_PROG(DOX,doxygen,"yes","no")
+if test "x${DOX}" = "xyes"; then
+  DOXYGEN="doxygen"
+else
+  DOXYGEN=""
+fi
+AC_SUBST(DOXYGEN)
+
+AC_CONFIG_HEADER(MAdConfig.h:MAdConfig.h.in)
+
+dnl Write output
+AC_SUBST(UNAME)
+AC_SUBST(HOSTNAME)
+AC_SUBST(FLAGS)
+AC_SUBST(OPTIM)
+AC_SUBST(CXX)
+AC_SUBST(CXXFLAGS)
+AC_SUBST(LINKER)
+AC_SUBST(AR)
+AC_SUBST(LIBEXT)
+AC_SUBST(MAdLib_DEFS)
+AC_SUBST(MAdROOT)
+AC_SUBST(MAdLib_TMPDIR)
+AC_SUBST(MAdLib_DIRS)
+AC_SUBST(MAdLib_LIBS)
+AC_SUBST(MAdLib_INCLUDES)
+AC_SUBST(MAdLib_BENCHDIRS)
+AC_CONFIG_FILES([variables])
+AC_OUTPUT
+
+dnl Print some information
+echo "********************************************************************"
+echo "MAdLib is configured for"
+echo "  - OS           : ${UNAME} on ${HOSTNAME}"
+echo "  - C++ compiler : ${CXX}"
+echo "  - Exe linker   : ${LINKER}"
+echo "  - Lib linker   : ${AR}"
+echo "  - Optimization : ${OPTIM}"
+echo "  - C++ flags    : ${CXXFLAGS}"
+echo "  - Build options: ${BO}"
+echo "********************************************************************"
+echo "Edit 'variables' and 'MAdConfig.h' to fine-tune the config"
+echo "********************************************************************"
+
diff --git a/doxygen.config b/doxygen.config
new file mode 100644
index 0000000..35140bb
--- /dev/null
+++ b/doxygen.config
@@ -0,0 +1,76 @@
+
+# Automatically generated by buildUtil 
+PROJECT_NAME           = MAdLib
+OUTPUT_DIRECTORY       = ./doc
+OUTPUT_LANGUAGE        = English
+INPUT                  = Common Geo Mesh Adapt 
+FILE_PATTERNS          = *.h *.c *.cc *.cpp *.ipp
+EXTRACT_ALL            = YES
+EXTRACT_PRIVATE        = NO
+EXTRACT_STATIC         = NO
+ALWAYS_DETAILED_SEC    = NO
+FULL_PATH_NAMES        = NO
+INTERNAL_DOCS          = NO
+CLASS_DIAGRAMS         = YES
+SOURCE_BROWSER         = NO
+INLINE_SOURCES         = NO
+STRIP_CODE_COMMENTS    = YES
+CASE_SENSE_NAMES       = YES
+SHORT_NAMES            = NO
+HIDE_SCOPE_NAMES       = NO
+VERBATIM_HEADERS       = NO
+SHOW_INCLUDE_FILES     = YES
+JAVADOC_AUTOBRIEF      = NO
+INHERIT_DOCS           = YES
+INLINE_INFO            = YES
+SORT_MEMBER_DOCS       = YES
+DISTRIBUTE_GROUP_DOC   = NO
+TAB_SIZE               = 4
+GENERATE_TODOLIST      = YES
+GENERATE_TESTLIST      = YES
+GENERATE_BUGLIST       = YES
+MAX_INITIALIZER_LINES  = 30
+OPTIMIZE_OUTPUT_FOR_C  = NO
+SHOW_USED_FILES        = YES
+QUIET                  = YES
+WARNINGS               = YES
+WARN_IF_UNDOCUMENTED   = YES
+RECURSIVE              = YES
+FILTER_SOURCE_FILES    = NO
+ALPHABETICAL_INDEX     = YES
+COLS_IN_ALPHA_INDEX    = 2
+GENERATE_HTML          = YES
+HTML_ALIGN_MEMBERS     = YES
+GENERATE_HTMLHELP      = NO
+GENERATE_CHI           = NO
+BINARY_TOC             = NO
+TOC_EXPAND             = NO
+DISABLE_INDEX          = NO
+ENUM_VALUES_PER_LINE   = 4
+GENERATE_TREEVIEW      = NO
+TREEVIEW_WIDTH         = 250
+GENERATE_LATEX         = NO
+COMPACT_LATEX          = NO
+PAPER_TYPE             = letter
+PDF_HYPERLINKS         = YES
+USE_PDFLATEX           = YES
+LATEX_BATCHMODE        = YES
+GENERATE_RTF           = NO
+GENERATE_MAN           = NO
+MAN_LINKS              = YES
+ENABLE_PREPROCESSING   = YES
+MACRO_EXPANSION        = NO
+EXPAND_ONLY_PREDEF     = NO
+SEARCH_INCLUDES        = YES
+ALLEXTERNALS           = NO
+HAVE_DOT               = NO
+CLASS_GRAPH            = YES
+COLLABORATION_GRAPH    = YES
+INCLUDE_GRAPH          = YES
+INCLUDED_BY_GRAPH      = YES
+GRAPHICAL_HIERARCHY    = YES
+MAX_DOT_GRAPH_WIDTH    = 1024
+MAX_DOT_GRAPH_HEIGHT   = 1024
+GENERATE_LEGEND        = YES
+DOT_CLEANUP            = YES
+SEARCHENGINE           = NO
diff --git a/variables.in b/variables.in
new file mode 100644
index 0000000..e85843b
--- /dev/null
+++ b/variables.in
@@ -0,0 +1,90 @@
+# -------------------------------------------------------------------
+# MAdLib - Copyright (C) 2008-2009 Universite catholique de Louvain
+#
+# See the Copyright.txt and License.txt files for license information. 
+# You should have received a copy of these files along with MAdLib. 
+# If not, see <http://www.madlib.be/license/>
+#
+# Please report all bugs and problems to <contrib at madlib.be>
+#
+# Authors: Gaetan Compere, Jean-Francois Remacle
+# -------------------------------------------------------------------
+
+# OS and host
+UNAME=@UNAME@
+HOSTNAME=@HOSTNAME@
+
+# The names of the C and C++ compilers
+CC=@CC@
+CXX=@CXX@
+
+# If you need to link to dynamic libraries installed in non-standard
+# locations and are using the GNU linker, you may want to add
+# '-Wl,--rpath,/path/to/dynamic/library' to the 'LINKER' variable
+# below. Alternatively, you could edit the 'LD_LIBARY_PATH'
+# environement variable or use the 'ldconfig' program.
+LINKER=@LINKER@
+
+# All compiler flags except optimization flags
+FLAGS=@FLAGS@
+
+# Flag for c++ compiler
+CXXFLAGS=@CXXFLAGS@
+
+# Additional system includes
+SYSINCLUDE=
+
+# Compiler optimization flags
+OPTIM=@OPTIM@
+
+# MAdLib definitions
+MAdLib_DEFS=@MAdLib_DEFS@
+
+# MAdLib root directory
+MAdROOT=@MAdROOT@
+
+# MAdLib subdirectories
+MAdLib_TMPDIR=@MAdLib_TMPDIR@
+
+# MAdLib subdirectories
+MAdLib_DIRS=@MAdLib_DIRS@
+
+# MAdLib libraries
+MAdLib_LIBS=@MAdLib_LIBS@
+
+# MAdLib include directories
+MAdLib_INCLUDES=@MAdLib_INCLUDES@
+
+# MAdLib benchmarks subdirectories
+MAdLib_BENCHDIRS=@MAdLib_BENCHDIRS@
+
+# How you create a static library on this machine
+AR=@AR@
+ARFLAGS=
+RANLIB=@RANLIB@
+
+# The symbol used in front of compiler flags
+DASH=-
+
+# The extension to use for object files, libraries and executables
+OBJEXT=.o
+LIBEXT=@LIBEXT@
+EXEEXT=@EXEEXT@
+
+# File handling commands
+RM=rm -f
+
+# Documentation genration
+DOXYGEN=@DOXYGEN@
+
+# Installation directories
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+datadir=@datadir@
+datarootdir=@datarootdir@
+includedir=@includedir@
+libdir=@libdir@
+docdir=@docdir@
+mandir=@mandir@
+infodir=@infodir@

-- 
MAdLib, a mesh adaptation library.



More information about the Pkg-scicomp-commits mailing list