diff --git a/Plugin/Crack.cpp b/Plugin/Crack.cpp
index f24fcfc8aa1ef6e5267b4ff71947e83456517f44..ffbff8fc787aa8ffe38f0a0934e6e150c0a40a49 100644
--- a/Plugin/Crack.cpp
+++ b/Plugin/Crack.cpp
@@ -17,6 +17,7 @@
 StringXNumber CrackOptions_Number[] = {
   {GMSH_FULLRC, "Dimension", NULL, 1.},
   {GMSH_FULLRC, "PhysicalGroup", NULL, 1.},
+  {GMSH_FULLRC, "OpenBoundaryPhysicalGroup", NULL, 0.},
 };
 
 extern "C"
@@ -33,9 +34,14 @@ std::string GMSH_CrackPlugin::getHelp() const
     "group `PhysicalGroup' of dimension `Dimension' (1 or 2). "
     "The plugin duplicates the vertices and the elements on "
     "the crack and stores them in a new discrete curve "
-    "(Dimension = 1) or surface (Dimension = 2). The "
+    "(`Dimension' = 1) or surface (`Dimension' = 2). The "
     "elements touching the crack on the negative side "
-    "are modified to use the newly generated vertices.";
+    "are modified to use the newly generated vertices."
+    "If `OpenBoundaryPhysicalGroup' is given (> 0), its "
+    "vertices are duplicated and the crack will be left "
+    "open on that (part of the) boundary. Otherwise, the "
+    "lips of the crack are sealed, i.e., its vertices are "
+    "not duplicated.";
 }
 
 int GMSH_CrackPlugin::getNbOptions() const
@@ -69,6 +75,7 @@ PView *GMSH_CrackPlugin::execute(PView *view)
 {
   int dim = (int)CrackOptions_Number[0].def;
   int physical = (int)CrackOptions_Number[1].def;
+  int open = (int)CrackOptions_Number[2].def;
 
   if(dim != 1 && dim != 2){
     Msg::Error("Crack dimension should be 1 or 2");
@@ -85,13 +92,23 @@ PView *GMSH_CrackPlugin::execute(PView *view)
     return view;
   }
 
+  std::vector<GEntity*> openEntities;
+  if(open > 0){
+    openEntities = groups[dim - 1][open];
+    if(openEntities.empty()){
+      Msg::Error("Open boundary physical group %d (dimension %d) is empty",
+                 open, dim - 1);
+      return view;
+    }
+  }
+
   // get crack elements
   std::vector<MElement*> crackElements;
   for(unsigned int i = 0; i < entities.size(); i++)
     for(unsigned int j = 0; j < entities[i]->getNumMeshElements(); j++)
       crackElements.push_back(entities[i]->getMeshElement(j));
 
-  // get internal crack vertices
+  // get internal crack vertices and boundary vertices
   std::set<MVertex*> crackVertices, bndVertices;
   if(dim == 1){
     for(unsigned int i = 0; i < crackElements.size(); i++){
@@ -125,6 +142,18 @@ PView *GMSH_CrackPlugin::execute(PView *view)
     for(std::set<EdgeData, Less_EdgeData>::iterator it = bnd.begin(); it != bnd.end(); it++)
       bndVertices.insert(it->data.begin(), it->data.end());
   }
+
+  // get (forced) open boundary vertices and remove them from boundary vertices
+  for(unsigned int i = 0; i < openEntities.size(); i++){
+    for(unsigned int j = 0; j < openEntities[i]->getNumMeshElements(); j++){
+      MElement *e = openEntities[i]->getMeshElement(j);
+      for(int k = 0; k < e->getNumVertices(); k++){
+        MVertex *v = e->getVertex(k);
+        bndVertices.erase(v);
+      }
+    }
+  }
+
   for(std::set<MVertex*>::iterator it = bndVertices.begin();
       it != bndVertices.end(); it++)
     crackVertices.erase(*it);
@@ -195,7 +224,7 @@ PView *GMSH_CrackPlugin::execute(PView *view)
   GEntity *crackEntity = crackEdge ? (GEntity*)crackEdge : (GEntity*)crackFace;
   crackEntity->physicals.push_back(physical);
 
-  // duplicate crack vertices
+  // duplicate internal crack vertices
   std::map<MVertex*, MVertex*> vxv;
   for(std::set<MVertex*>::iterator it = crackVertices.begin();
       it != crackVertices.end(); it++){