diff --git a/src/model/contact_mechanics/contact_detector.cc b/src/model/contact_mechanics/contact_detector.cc
index 18748db70..a41cbd05d 100644
--- a/src/model/contact_mechanics/contact_detector.cc
+++ b/src/model/contact_mechanics/contact_detector.cc
@@ -1,291 +1,294 @@
 /**
  * @file contact_detector.cc
  *
  * @author Mohit Pundir <mohit.pundir@epfl.ch>
  *
  * @date creation: Wed Sep 12 2018
  * @date last modification: Fri Sep 21 2018
  *
  * @brief  Mother class for all detection algorithms
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu 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.
  *
  * Akantu 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 Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "contact_detector.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 ContactDetector::ContactDetector(Mesh & mesh, const ID & id,
                                  const MemoryID & memory_id)
     : ContactDetector(mesh, mesh.getNodes(), id, memory_id) {}
 
 /* -------------------------------------------------------------------------- */
 ContactDetector::ContactDetector(Mesh & mesh, Array<Real> positions,
                                  const ID & id, const MemoryID & memory_id)
     : Memory(id, memory_id), Parsable(ParserType::_contact_detector, id),
       mesh(mesh), positions(0, mesh.getSpatialDimension()) {
 
   AKANTU_DEBUG_IN();
 
   this->spatial_dimension = mesh.getSpatialDimension();
 
   this->positions.copy(positions);
 
   this->parseSection();
 
   AKANTU_DEBUG_OUT();
 }
 
   
 /* -------------------------------------------------------------------------- */
 void ContactDetector::parseSection() {
 
   const Parser & parser = getStaticParser();
 
   const ParserSection & section =
       *(parser.getSubSections(ParserType::_contact_detector).first);
 
   auto type = section.getParameterValue<std::string>("type");
 
   if (type == "implicit") {
     this->detection_type = _implicit;
   } else if (type == "explicit") {
     this->detection_type = _explicit;
   } else { 
     AKANTU_ERROR("Unknown detection type : " << type);
   }
 
   this->projection_tolerance =
     section.getParameterValue<Real>("projection_tolerance");
+  this->max_iterations =
+    section.getParameterValue<Real>("max_iterations");
   this->extension_tolerance =
     section.getParameterValue<Real>("extension_tolerance");
 }
 
 /* -------------------------------------------------------------------------- */
 void ContactDetector::search(Array<ContactElement> & elements,
 			     Array<Real> & gaps, Array<Real> & normals,
 			     Array<Real> & projections) {
 
   UInt surface_dimension = spatial_dimension - 1;
 
   this->mesh.fillNodesToElements(surface_dimension);
   this->computeMaximalDetectionDistance();
 
   contact_pairs.clear();
 
   SpatialGrid<UInt> master_grid(spatial_dimension);
   SpatialGrid<UInt> slave_grid(spatial_dimension);
 
   this->globalSearch(slave_grid, master_grid);
 
   this->localSearch(slave_grid, master_grid);
 
   this->createContactElements(elements, gaps, normals, projections);
 
 }
 
   
 /* -------------------------------------------------------------------------- */
 void ContactDetector::globalSearch(SpatialGrid<UInt> & slave_grid,
                                    SpatialGrid<UInt> & master_grid) {
 
   auto & master_list = surface_selector->getMasterList();
   auto & slave_list = surface_selector->getSlaveList();
 
   BBox bbox_master(spatial_dimension);
   this->constructBoundingBox(bbox_master, master_list);
 
   BBox bbox_slave(spatial_dimension);
   this->constructBoundingBox(bbox_slave, slave_list);
 
   auto && bbox_intersection = bbox_master.intersection(bbox_slave);
 
   AKANTU_DEBUG_INFO("Intersection BBox " << bbox_intersection);
 
   Vector<Real> center(spatial_dimension);
   bbox_intersection.getCenter(center);
 
   Vector<Real> spacing(spatial_dimension);
   this->computeCellSpacing(spacing);
 
   master_grid.setCenter(center);
   master_grid.setSpacing(spacing);
   this->constructGrid(master_grid, bbox_intersection, master_list);
 
   slave_grid.setCenter(center);
   slave_grid.setSpacing(spacing);
   this->constructGrid(slave_grid, bbox_intersection, slave_list);
 
   // search slave grid nodes in contactelement array and if they exits
   // and still have orthogonal projection on its associated master
   // facetremove it from the spatial grid or do not consider it for
   // local search, maybe better option will be to have spatial grid of
   // type node info and one of the variable of node info should be
   // facet already exits
   // so contact elements will be updated based on the above
   // consideration , this means only those contact elements will be
   // keep whose slave node is still in intersection bbox and still has
   // projection in its master facet
   // also if slave node is already exists in contact element and
   // orthogonal projection does not exits then search the associated
   // master facets with the current master facets within a given
   // radius , this is subjected to computational cost as searching
   // neighbbor cells can be more effective.
 }
 
 /* -------------------------------------------------------------------------- */
 void ContactDetector::localSearch(SpatialGrid<UInt> & slave_grid,
                                   SpatialGrid<UInt> & master_grid) {
 
   // local search
   // out of these array check each cell for closet node in that cell
   // and neighbouring cells find the actual orthogonally closet
   // check the projection of slave node on master facets connected to
   // the closet master node, if yes update the contact element with
   // slave node and master node and master surfaces connected to the
   // master node
   // these master surfaces will be needed later to update contact
   // elements
 
   /// find the closet master node for each slave node
   for (auto && cell_id : slave_grid) {
     /// loop over all the slave nodes of the current cell
     for (auto && slave_node : slave_grid.getCell(cell_id)) {
 
       bool pair_exists = false;
 
       Vector<Real> pos(spatial_dimension);
       for (UInt s : arange(spatial_dimension))
         pos(s) = this->positions(slave_node, s);
 
       Real closet_distance = std::numeric_limits<Real>::max();
       UInt closet_master_node;
 
       /// loop over all the neighboring cells of the current cell
       for (auto && neighbor_cell : cell_id.neighbors()) {
         /// loop over the data of neighboring cells from master grid
         for (auto && master_node : master_grid.getCell(neighbor_cell)) {
 
           /// check for self contact
           if (slave_node == master_node)
             continue;
 
 	  bool is_valid = true;
           Array<Element> elements;
           this->mesh.getAssociatedElements(slave_node, elements);
 
           for (auto & elem : elements) {
             if (elem.kind() != _ek_regular)
               continue;
 
             Vector<UInt> connectivity =
                 const_cast<const Mesh &>(this->mesh).getConnectivity(elem);
 
             auto node_iter = std::find(connectivity.begin(), connectivity.end(),
                                        master_node);
             if (node_iter != connectivity.end()) {
               is_valid = false;
 	      break;
             }
           }
 
           Vector<Real> pos2(spatial_dimension);
           for (UInt s : arange(spatial_dimension))
             pos2(s) = this->positions(master_node, s);
 
           Real distance = pos.distance(pos2);
 
           if (distance <= closet_distance and is_valid) {
             closet_master_node = master_node;
             closet_distance = distance;
             pair_exists = true;
           }
         }
       }
 
       if (pair_exists)
         contact_pairs.push_back(std::make_pair(slave_node, closet_master_node));
     }
   }
 }
 
 
 /* -------------------------------------------------------------------------- */
 void ContactDetector::createContactElements(Array<ContactElement> & contact_elements,
 					    Array<Real> & gaps, Array<Real> & normals,
 					    Array<Real> & projections) {
 
   auto surface_dimension = spatial_dimension - 1;
  
   Real alpha;
   switch (detection_type) {
   case _explicit: {
     alpha = 1.0;
     break;
   }
   case _implicit: {
     alpha = -1.0;
     break;
   }  
   default:
     AKANTU_EXCEPTION(detection_type << " is not a valid contact detection type");
     break;
   }
       
   for (auto & pairs : contact_pairs) {
 
     const auto & slave_node = pairs.first;
 
     Vector<Real> slave(spatial_dimension);
     for (UInt s : arange(spatial_dimension))
       slave(s) = this->positions(slave_node, s);
 
     const auto & master_node = pairs.second;
     Array<Element> elements;
     this->mesh.getAssociatedElements(master_node, elements);
 
     auto & gap = gaps.begin()[slave_node];
     Vector<Real> normal(normals.begin(spatial_dimension)[slave_node]);
     Vector<Real> projection(projections.begin(surface_dimension)[slave_node]);
     auto index = GeometryUtils::orthogonalProjection(mesh, positions, slave, elements,
 						     gap, projection, normal, alpha,
+						     this->max_iterations, 
 						     this->projection_tolerance, 
 						     this->extension_tolerance);
 
     // if a valid projection is not found on the patch of elements
     // index is -1 or if not a valid self contact, the contact element
     // is not created
     if (index == UInt(-1) or !isValidSelfContact(slave_node, gap, normal)) { 
       gap *= 0;
       normal *= 0;
       continue;
     }
     
     // create contact element
     contact_elements.push_back(ContactElement(slave_node, elements[index]));
   }
 
   contact_pairs.clear();
 }
 
 } // namespace akantu
diff --git a/src/model/contact_mechanics/contact_detector.hh b/src/model/contact_mechanics/contact_detector.hh
index 099c8169e..5076fa00d 100644
--- a/src/model/contact_mechanics/contact_detector.hh
+++ b/src/model/contact_mechanics/contact_detector.hh
@@ -1,213 +1,216 @@
 /**
  * @file contact_detection.hh
  *
  * @author Mohit Pundir <mohit.pundir@epfl.ch>
  *
  * @date creation: Wed Sep 12 2018
  * @date last modification: Tue Oct 23 2018
  *
  * @brief  Mother class for all detection algorithms
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu 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.
  *
  * Akantu 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 Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "aka_bbox.hh"
 #include "aka_common.hh"
 #include "aka_grid_dynamic.hh"
 #include "aka_memory.hh"
 #include "contact_element.hh"
 #include "element_class.hh"
 #include "element_group.hh"
 #include "fe_engine.hh"
 #include "mesh.hh"
 #include "mesh_io.hh"
 #include "parsable.hh"
 #include "surface_selector.hh"
 #include "geometry_utils.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_CONTACT_DETECTOR_HH__
 #define __AKANTU_CONTACT_DETECTOR_HH__
 
 namespace akantu {
 
 enum class Surface { master, slave };
 
 /* -------------------------------------------------------------------------- */
 
 class ContactDetector : private Memory,
 			public Parsable {
 
   /* ------------------------------------------------------------------------ */
   /* Constructor/Destructors                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   ContactDetector(Mesh &, const ID & id = "contact_detector",
                   const MemoryID & memory_id = 0);
 
   ContactDetector(Mesh &, Array<Real> positions,
                   const ID & id = "contact_detector",
                   const MemoryID & memory_id = 0);
 
   ~ContactDetector() = default;
 
   /* ------------------------------------------------------------------------ */
   /* Members                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /// performs all search steps
   void search(Array<ContactElement> & contact_map,
 	      Array<Real> & gaps, Array<Real> & normals,
 	      Array<Real> & projections);
   
   /// performs global spatial search to construct spatial grids
   void globalSearch(SpatialGrid<UInt> &, SpatialGrid<UInt> &);
 
   ///  performs local search to find closet master node to a slave node
   void localSearch(SpatialGrid<UInt> &, SpatialGrid<UInt> &);
 
   /// create contact elements
   void createContactElements(Array<ContactElement> & elements,
 			     Array<Real> & gaps, Array<Real> & normals,
 			     Array<Real> & projections);
   
 private:  
   /// reads the input file to get contact detection options
   void parseSection();
 
   /* ------------------------------------------------------------------------ */
   /* Inline Methods                                                           */
   /* ------------------------------------------------------------------------ */
 public:
   /// checks whether the natural projection is valid or not
   inline bool checkValidityOfProjection(Vector<Real> &);
 
   /// extracts the coordinates of an element
   inline void coordinatesOfElement(const Element &, Matrix<Real> &);
 
   /// computes the optimal cell size for grid
   inline void computeCellSpacing(Vector<Real> &);
 
   /// constructs a grid containing nodes lying within bounding box
   inline void constructGrid(SpatialGrid<UInt> &, BBox &, const Array<UInt> &);
 
   /// constructs the bounding box based on nodes list
   inline void constructBoundingBox(BBox &, const Array<UInt> &);
 
   /// computes the maximum in radius for a given mesh
   inline void computeMaximalDetectionDistance();
 
   /// constructs the connectivity for a contact element
   inline Vector<UInt> constructConnectivity(UInt &, const Element &);
 
   /// computes normal on an element
   inline void computeNormalOnElement(const Element &, Vector<Real> &);
 
   /// extracts vectors which forms the plane of element
   inline void vectorsAlongElement(const Element &, Matrix<Real> &);
 
   /// computes the gap between slave and its projection on master
   /// surface
   inline Real computeGap(Vector<Real> &, Vector<Real> &);
 
   /// filter boundary elements
   inline void filterBoundaryElements(Array<Element> & elements,
                                      Array<Element> & boundary_elements);
 
   /// checks whether self contact condition leads to a master element
   /// which is closet but not orthogonally opposite to slave surface
   //inline bool checkValidityOfSelfContact(const UInt &, ContactElement &);
 
   /// checks whether self contact condition leads to a master element
   /// which is closet but not orthogonally opposite to slave surface
   inline bool isValidSelfContact(const UInt &, const Real & , const Vector<Real> &);
 
   
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
   /// get the mesh
   AKANTU_GET_MACRO(Mesh, mesh, Mesh &)
 
   /// returns the maximum detection distance
   AKANTU_GET_MACRO(MaximumDetectionDistance, max_dd, Real);
   AKANTU_SET_MACRO(MaximumDetectionDistance, max_dd, Real);
 
   /// returns the bounding box extension
   AKANTU_GET_MACRO(MaximumBoundingBox, max_bb, Real);
   AKANTU_SET_MACRO(MaximumBoundingBox, max_bb, Real);
 
   /// returns the minimum detection distance
   AKANTU_GET_MACRO(MinimumDetectionDistance, min_dd, Real);
   AKANTU_SET_MACRO(MinimumDetectionDistance, min_dd, Real);
   
   AKANTU_GET_MACRO_NOT_CONST(Positions, positions, Array<Real> &);
   AKANTU_SET_MACRO(Positions, positions, Array<Real>);
 
   AKANTU_GET_MACRO_NOT_CONST(SurfaceSelector, *surface_selector,
                              SurfaceSelector &);
   AKANTU_SET_MACRO(SurfaceSelector, surface_selector,
                    std::shared_ptr<SurfaceSelector>);
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 private:
   /// maximal detection distance for grid spacing
   Real max_dd;
 
   /// minimal detection distance for grid spacing
   Real min_dd;
 
   /// maximal bounding box extension
   Real max_bb;
 
   /// tolerance for finding natural projection
   Real projection_tolerance;
 
+  /// iterations for finding natural projection
+  UInt max_iterations;
+
   /// tolerance for extending a master elements on all sides
   Real extension_tolerance;
 
   /// Mesh
   Mesh & mesh;
 
   /// dimension of the model
   UInt spatial_dimension{0};
 
   /// node selector for selecting master and slave nodes
   std::shared_ptr<SurfaceSelector> surface_selector;
 
   /// contact pair slave node to closet master node
   std::vector<std::pair<UInt, UInt>> contact_pairs;
 
   /// contains the updated positions of the nodes
   Array<Real> positions;
 
   /// type of detection explicit/implicit
   DetectionType detection_type;
 };
 
 } // namespace akantu
 
 #include "contact_detector_inline_impl.cc"
 
 #endif /* __AKANTU_CONTACT_DETECTOR_HH__ */
diff --git a/src/model/contact_mechanics/geometry_utils.cc b/src/model/contact_mechanics/geometry_utils.cc
index 1153d8e4e..87b9ec1a5 100644
--- a/src/model/contact_mechanics/geometry_utils.cc
+++ b/src/model/contact_mechanics/geometry_utils.cc
@@ -1,438 +1,440 @@
 /**
  * @file   geometry_utils.cc
  *
  * @author Mohit Pundir <mohit.pundir@epfl.ch>
  *
  * @date creation: Mon Mmay 20 2019
  * @date last modification: Mon May 20 2019
  *
  * @brief  Implementation of various utilities needed for contact geometry 
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu 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.
  *
  * Akantu 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 Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "geometry_utils.hh"
 /* -------------------------------------------------------------------------- */
 
 
 namespace akantu {
   
 /* -------------------------------------------------------------------------- */
 void GeometryUtils::normal(const Mesh & mesh, const Array<Real> & positions,
 			   const Element & element, Vector<Real> & normal, bool outward) {
 
   UInt spatial_dimension = mesh.getSpatialDimension();
   UInt surface_dimension = spatial_dimension - 1;
   
   UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(element.type);
   Matrix<Real> coords(spatial_dimension, nb_nodes_per_element);
 
   UInt * elem_val = mesh.getConnectivity(element.type, _not_ghost).storage();
   mesh.extractNodalValuesFromElement(positions, coords.storage(),
                                      elem_val + element.element * nb_nodes_per_element,
                                      nb_nodes_per_element, spatial_dimension);
 
   Matrix<Real> vectors(spatial_dimension, surface_dimension);
   switch (spatial_dimension) {
   case 1: {
     normal[0] = 1;
     break;
   }
   case 2: {
     vectors(0) = Vector<Real>(coords(1)) - Vector<Real>(coords(0));
     Math::normal2(vectors.storage(), normal.storage());
     break;
   }
   case 3: {
     vectors(0) = Vector<Real>(coords(1)) - Vector<Real>(coords(0));
     vectors(1) = Vector<Real>(coords(2)) - Vector<Real>(coords(0));
     Math::normal3(vectors(0).storage(), vectors(1).storage(), normal.storage());
     break;
   }
   default: { AKANTU_ERROR("Unknown dimension : " << spatial_dimension); }
   }
 
   // to ensure that normal is always outwards from master surface
   if (outward) {
       
    const auto & element_to_subelement =
      mesh.getElementToSubelement(element.type)(element.element);
 
    Vector<Real> outside(spatial_dimension);
    mesh.getBarycenter(element, outside);
 
    // check if mesh facets exists for cohesive elements contact
    Vector<Real> inside(spatial_dimension);
    if (mesh.isMeshFacets()) {
      mesh.getMeshParent().getBarycenter(element_to_subelement[0], inside);
    } else {
      mesh.getBarycenter(element_to_subelement[0], inside);
    }
 
    Vector<Real> inside_to_outside = outside - inside;
    auto projection = inside_to_outside.dot(normal);
 
    if (projection < 0) {
      normal *= -1.0;
    }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void GeometryUtils::covariantBasis(const Mesh & mesh, const Array<Real> & positions,
 				   const Element & element, const Vector<Real> & normal,
 				   Vector<Real> & natural_coord,
 				   Matrix<Real> & tangents) {
 
   UInt spatial_dimension = mesh.getSpatialDimension();
   
   const ElementType & type = element.type;
   UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type);
   UInt * elem_val = mesh.getConnectivity(type, _not_ghost).storage();
   Matrix<Real> nodes_coord(spatial_dimension, nb_nodes_per_element);
 
   mesh.extractNodalValuesFromElement(positions, nodes_coord.storage(),
                                      elem_val + element.element * nb_nodes_per_element,
                                      nb_nodes_per_element, spatial_dimension);
 
   UInt surface_dimension = spatial_dimension - 1;
   Matrix<Real> dnds(surface_dimension, nb_nodes_per_element);
   
 #define GET_SHAPE_DERIVATIVES_NATURAL(type)				\
   ElementClass<type>::computeDNDS(natural_coord, dnds)
   AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_DERIVATIVES_NATURAL);
 #undef GET_SHAPE_DERIVATIVES_NATURAL
 
   tangents.mul<false, true>(dnds, nodes_coord);
 
   auto temp_tangents = tangents.transpose();
   for (UInt i = 0; i < spatial_dimension - 1; ++i) {
     auto temp = Vector<Real>(temp_tangents(i));
     temp_tangents(i) = temp.normalize();
   }
 
   tangents = temp_tangents.transpose();
 
   // to ensure that direction of tangents are correct, cross product
   // of tangents should give the normal vector computed earlier
   switch (spatial_dimension) {
   case 2: {
     Vector<Real> e_z(3);
     e_z[0] = 0.;
     e_z[1] = 0.;
     e_z[2] = 1.;
 
     Vector<Real> tangent(3);
     tangent[0] = tangents(0, 0);
     tangent[1] = tangents(0, 1);
     tangent[2] = 0.;
 
     auto exp_normal = e_z.crossProduct(tangent);
 
     auto ddot = normal.dot(exp_normal);
     if (ddot < 0) {
       tangents *= -1.0;
     }
     break;
   }
   case 3: {
     auto tang_trans = tangents.transpose();
     auto tang1 = Vector<Real>(tang_trans(0));
     auto tang2 = Vector<Real>(tang_trans(1));
 
     auto tang1_cross_tang2 = tang1.crossProduct(tang2);
     auto exp_normal = tang1_cross_tang2 / tang1_cross_tang2.norm();
 
     auto ddot = normal.dot(exp_normal);
     if (ddot < 0) {
       tang_trans(1) *= -1.0;
     }
 
     tangents = tang_trans.transpose();
     break;
   }
   default:
     break;
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void GeometryUtils::curvature(const Mesh & mesh, const Array<Real> & positions,
 			      const Element & element, const Vector<Real> & natural_coord,
 			      Matrix<Real> & curvature) {
   UInt spatial_dimension = mesh.getSpatialDimension();
   auto surface_dimension = spatial_dimension - 1;
 
   const ElementType & type = element.type;
   UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type);
   UInt * elem_val = mesh.getConnectivity(type, _not_ghost).storage();
   
   Matrix<Real> dn2ds2(surface_dimension * surface_dimension,
 		      Mesh::getNbNodesPerElement(type));
   
 #define GET_SHAPE_SECOND_DERIVATIVES_NATURAL(type)			\
     ElementClass<type>::computeDN2DS2(natural_coord, dn2ds2)
     AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_SECOND_DERIVATIVES_NATURAL);
 #undef GET_SHAPE_SECOND_DERIVATIVES_NATURAL
 
     Matrix<Real> coords(spatial_dimension, nb_nodes_per_element);
     mesh.extractNodalValuesFromElement(positions, coords.storage(),
 				       elem_val + element.element * nb_nodes_per_element,
 				       nb_nodes_per_element, spatial_dimension);
 
     curvature.mul<false, true>(coords, dn2ds2);
 }
 
   
 /* -------------------------------------------------------------------------- */
 UInt GeometryUtils::orthogonalProjection(const Mesh & mesh, const Array<Real> & positions,
 					 const Vector<Real> & slave,
 					 const Array<Element> & elements,
 					 Real & gap, Vector<Real> & natural_projection,
 					 Vector<Real> & normal, Real alpha,
+					 UInt max_iterations,
 					 Real projection_tolerance, 
 					 Real extension_tolerance) {
 
   UInt index = UInt(-1);
   Real min_gap = std::numeric_limits<Real>::max();
 
   UInt spatial_dimension = mesh.getSpatialDimension();
 
   UInt nb_same_sides{0};
   UInt nb_boundary_elements{0};
 
   UInt counter{0};
   for (auto & element : elements) {
     if (!GeometryUtils::isBoundaryElement(mesh, element))
       continue;
 
     nb_boundary_elements++;
 
     Vector<Real> normal_ele(spatial_dimension);
     GeometryUtils::normal(mesh, positions, element, normal_ele);
     
     Vector<Real> master(spatial_dimension);
     GeometryUtils::realProjection(mesh, positions, slave, element, normal_ele, master);
 
     Vector<Real> xi(natural_projection.size());
     GeometryUtils::naturalProjection(mesh, positions, element, master, xi,
-				     projection_tolerance);
+				     max_iterations, projection_tolerance);
 
     // if gap between master projection and slave point is zero, then
     // it means that slave point lies on the master element, hence the
     // normal from master to slave cannot be computed in that case
     
     auto master_to_slave = slave - master;
     Real temp_gap = master_to_slave.norm();
     
     if (temp_gap != 0) 
       master_to_slave /= temp_gap;
     
     // also the slave point should lie inside the master surface in
     // case of explicit or outside in case of implicit, one way to
     // check that is by checking the dot product of normal at each
     // master element, if the values of all dot product is same then
     // the slave point lies on the same side of each master element
     
     
     // A alpha parameter is introduced which is 1 in case of explicit
     // and -1 in case of implicit, therefor the variation (dot product
     // + alpha) should be close to zero (within tolerance) for both
     // cases
 
     Real direction_tolerance = 1e-8;
     auto product = master_to_slave.dot(normal_ele);
     auto variation = std::abs(product + alpha);
          
     if (variation <= direction_tolerance and
 	temp_gap <= min_gap and
 	GeometryUtils::isValidProjection(xi, extension_tolerance)) {
 
       gap     = -temp_gap;
       min_gap = temp_gap;
       index   = counter;
       natural_projection = xi;
       normal = normal_ele;
       
     }
 
     if(temp_gap == 0 or variation <= direction_tolerance)
       nb_same_sides++;
     
     counter++;
   }
 
   // if point is not on the same side of all the boundary elements
   // than it is not consider even if the closet master element is
   // found
   if(nb_same_sides != nb_boundary_elements)
     index = UInt(-1);
   
   return index;
 }
 
 /* -------------------------------------------------------------------------- */
 void GeometryUtils::realProjection(const Mesh & mesh, const Array<Real> & positions,
 				   const Vector<Real> & slave, const Element & element,
 				   const Vector<Real> & normal, 
 				   Vector<Real> & projection) {
 
   UInt spatial_dimension = mesh.getSpatialDimension();
 
   const ElementType & type = element.type;
   UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(element.type);
 
   UInt * elem_val = mesh.getConnectivity(type, _not_ghost).storage();
   Matrix<Real> nodes_coord(spatial_dimension, nb_nodes_per_element);
 
   mesh.extractNodalValuesFromElement(positions, nodes_coord.storage(),
                                      elem_val + element.element * nb_nodes_per_element,
                                      nb_nodes_per_element, spatial_dimension);
   
   Vector<Real> point(nodes_coord(0));
   Real alpha = (slave - point).dot(normal);
 
   projection = slave - alpha * normal;
 }
 
 /* -------------------------------------------------------------------------- */
 void GeometryUtils::realProjection(const Mesh & mesh, const Array<Real> & positions,
 				   const Element & element, const Vector<Real> & natural_coord,
 				   Vector<Real> & projection) {
 
   UInt spatial_dimension = mesh.getSpatialDimension();
 
   const ElementType & type = element.type;
 
   UInt nb_nodes_per_element = mesh.getNbNodesPerElement(element.type);
   
   Vector<Real> shapes(nb_nodes_per_element);  
 #define GET_SHAPE_NATURAL(type)		\
   ElementClass<type>::computeShapes(natural_coord, shapes)
   AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_NATURAL);
 #undef GET_SHAPE_NATURAL
 
   Matrix<Real> nodes_coord(spatial_dimension, nb_nodes_per_element);
   UInt * elem_val = mesh.getConnectivity(type, _not_ghost).storage();
   mesh.extractNodalValuesFromElement(positions, nodes_coord.storage(),
                                      elem_val + element.element * nb_nodes_per_element,
                                      nb_nodes_per_element, spatial_dimension);
 
   projection.mul<false>(nodes_coord, shapes);
 }
 
 /* -------------------------------------------------------------------------- */
 void GeometryUtils::naturalProjection(const Mesh & mesh, const Array<Real> & positions,
 				      const Element & element,
 				      Vector<Real> & real_projection,
 				      Vector<Real> & natural_projection,
+				      UInt max_iterations, 
 				      Real projection_tolerance) {
 
   UInt spatial_dimension = mesh.getSpatialDimension();
   
   const ElementType & type = element.type;
   UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type);
   UInt * elem_val = mesh.getConnectivity(type, _not_ghost).storage();
   Matrix<Real> nodes_coord(spatial_dimension, nb_nodes_per_element);
 
   mesh.extractNodalValuesFromElement(positions, nodes_coord.storage(),
                                      elem_val + element.element * nb_nodes_per_element,
                                      nb_nodes_per_element, spatial_dimension);
 
 #define GET_NATURAL_COORDINATE(type)                                           \
   ElementClass<type>::inverseMap(real_projection, nodes_coord,                 \
-                                 natural_projection, projection_tolerance)
+                                 natural_projection, max_iterations, projection_tolerance)
   AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NATURAL_COORDINATE);
 #undef GET_NATURAL_COORDINATE
 }
 
 
 /* -------------------------------------------------------------------------- */
 void GeometryUtils::contravariantBasis(const Matrix<Real> & covariant,
 				       Matrix<Real> & contravariant) {
   
   auto inv_A = GeometryUtils::contravariantMetricTensor(covariant);
   contravariant.mul<false, false>(inv_A, covariant); 
 }
 
 
 /* -------------------------------------------------------------------------- */
 Matrix<Real> GeometryUtils::covariantMetricTensor(const Matrix<Real> & covariant_bases) {
   
   Matrix<Real> A(covariant_bases.rows(), covariant_bases.rows());
   A.mul<false, true>(covariant_bases, covariant_bases);
   return A;
 }
   
 
 /* -------------------------------------------------------------------------- */
 Matrix<Real> GeometryUtils::contravariantMetricTensor(const Matrix<Real> & covariant_bases)  {
 
   auto A = GeometryUtils::covariantMetricTensor(covariant_bases);
   auto inv_A = A.inverse();
   return inv_A;
 }
 
 /* -------------------------------------------------------------------------- */
 Matrix<Real> GeometryUtils::covariantCurvatureTensor(const Mesh & mesh,
 						     const Array<Real> & positions,
 						     const Element & element,
 						     const Vector<Real> & natural_coord,
 						     const Vector<Real> & normal) {
 
   UInt spatial_dimension = mesh.getSpatialDimension();
   auto surface_dimension = spatial_dimension - 1;
 
   const ElementType & type = element.type;
   UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   UInt * elem_val = mesh.getConnectivity(type, _not_ghost).storage();
   
   Matrix<Real> dn2ds2(surface_dimension * surface_dimension,
 		      nb_nodes_per_element);
   
 #define GET_SHAPE_SECOND_DERIVATIVES_NATURAL(type)			\
   ElementClass<type>::computeDN2DS2(natural_coord, dn2ds2)
   AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SHAPE_SECOND_DERIVATIVES_NATURAL);
 #undef GET_SHAPE_SECOND_DERIVATIVES_NATURAL
 
   Matrix<Real> coords(spatial_dimension, nb_nodes_per_element);
   mesh.extractNodalValuesFromElement(positions, coords.storage(),
 				     elem_val + element.element * nb_nodes_per_element,
 				     nb_nodes_per_element, spatial_dimension);
 
   Matrix<Real> curvature(spatial_dimension, surface_dimension*surface_dimension);
   curvature.mul<false, true>(coords, dn2ds2);
 
   Matrix<Real> H(surface_dimension, surface_dimension);
 
   UInt i = 0;
   for (auto alpha : arange(surface_dimension)) {
     for (auto beta : arange(surface_dimension)) {
       Vector<Real> temp(curvature(i));
       H(alpha, beta) = temp.dot(normal);
       i++;
     }
   }
 
   return H;
 }
 
 }
diff --git a/src/model/contact_mechanics/geometry_utils.hh b/src/model/contact_mechanics/geometry_utils.hh
index 82a503c73..3dba0b63a 100644
--- a/src/model/contact_mechanics/geometry_utils.hh
+++ b/src/model/contact_mechanics/geometry_utils.hh
@@ -1,121 +1,125 @@
 /**
  * @file   geometry_utils.hh
  *
  * @author Mohit Pundir <mohit.pundir@epfl.ch>
  *
  * @date creation: Mon Sep 30 2019
  * @date last modification: Mon Sep 30 2019
  *
  * @brief  class to compute geometry related quantities 
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu 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.
  *
  * Akantu 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 Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "aka_common.hh"
 #include "fe_engine.hh"
 #include "mesh.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_GEOMETRY_UTILS_HH__
 #define __AKANTU_GEOMETRY_UTILS_HH__
 
 namespace akantu {
 
 class GeometryUtils {
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /// computes the normal on an element
   static void normal(const Mesh & mesh, const Array<Real> & positions,
 		     const Element & element, Vector<Real> & normal, bool outward=true);
 
   /// computes the orthogonal projection on a set of elements and
   /// returns natural projection and normal gap and index of element
   static UInt orthogonalProjection(const Mesh & mesh, const Array<Real> & positions,
 				   const Vector<Real> & slave,
 				   const Array<Element> & elements,
 				   Real & gap, Vector<Real> & natural_projection,
-				   Vector<Real> & normal, Real alpha, Real tolerance = 1e-10, 
+				   Vector<Real> & normal, Real alpha,
+				   UInt max_iterations = 100,
+				   Real tolerance = 1e-10, 
 				   Real extension_tolerance = 1e-5);
 
   /// computes the natural projection on an element
   static void naturalProjection(const Mesh & mesh, const Array<Real> & positions,
 				const Element & element, Vector<Real> & real_projection,
-				Vector<Real> & natural_projection, Real tolerance = 1e-10);
+				Vector<Real> & natural_projection,
+				UInt max_iterations = 100,
+				Real tolerance = 1e-10);
   
   /// computes the real projection on an element
   static void realProjection(const Mesh & mesh, const Array<Real> & positions,
 				    const Vector<Real> & slave,  const Element & element,
 				    const Vector<Real> & normal, Vector<Real> & projection);
 
   /// computes the real projection from a natural coordinate
   static void realProjection(const Mesh & mesh, const Array<Real> & positions,
 			     const Element & element, const Vector<Real> & natural_coord,
 			     Vector<Real> & projection);
   
   /// computes the covariant basis/ local surface basis/ tangents on projection
   /// point
   static void covariantBasis(const Mesh & mesh, const Array<Real> & positions,
 			     const Element & element,  const Vector<Real> & normal,
 			     Vector<Real> & natural_coord,
 			     Matrix<Real> & basis);
 
   // computes the curvature on projection
   static void curvature(const Mesh & mesh, const Array<Real> & positions,
 			const Element & element, const Vector<Real> & natural_coord,
 			Matrix<Real> & curvature);
 
   
   /// computes the contravariant basis on projection point
   static void contravariantBasis(const Matrix<Real> & covariant,
 				 Matrix<Real> & contravariant);
 
   /// computes metric tesnor with covariant components
   static Matrix<Real> covariantMetricTensor(const Matrix<Real> & );
 
   /// computes metric tensor with contravariant components
   static Matrix<Real> contravariantMetricTensor(const Matrix<Real> & );
 
   // computes curvature tensor with convariant components
   static Matrix<Real> covariantCurvatureTensor(const Mesh &,
 					       const Array<Real> &,
 					       const Element &,
 					       const Vector<Real> &,
 					       const Vector<Real> &);  
   
   /// checks if the element is truly a boundary element or not
   inline static bool isBoundaryElement(const Mesh & mesh, const Element & element);
 
   /// checks if the natural projection is valid for not
   inline static bool isValidProjection(const Vector<Real> & projection, 
 				       Real extension_tolerance = 1e-5);
 
 
 };
   
 }
 
 
 #include "geometry_utils_inline_impl.cc"  
 
 
 #endif /* __AKANTU_GEOMETRY_UTILS_HH__ */