diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index a603e26925abb989998e4afc589be5081cef9a8d..0b534fb8ed5838a209def059c2fdd9bb7c259411 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -67,7 +67,7 @@ windows64_msvc_ci:
 # Official Linux builds (master branch only)
 # ------------------------------------------
 
-.linux64_official: &linux64_official
+.linux_official: &linux_official
   only:
     - master
   script:
@@ -77,19 +77,40 @@ windows64_msvc_ci:
     - make package -j 1
     - PKG=`ls gmsh-*.tar*`; scp -o StrictHostKeyChecking=no -i /home/gitlab-runner/.ssh/id_rsa ${PKG} geuzaine@gmsh.info:.wwwgmsh/bin/Linux/${PKG/\.tar\.gz/\.tgz}
     - /usr/local/bin/ctest -D Experimental -j 1 --output-on-failure
+
+linux64_official_snapshot:
+  <<: *linux_official
   tags:
     - linux64
     - official
-
-linux64_official_snapshot:
-  <<: *linux64_official
   except:
     - tags
 
 linux64_official_release:
   variables:
     EXTRA_VERSION: ""
-  <<: *linux64_official
+  <<: *linux_official
+  tags:
+    - linux64
+    - official
+  only:
+    - /^gmsh_.*$/
+
+linux32_official_snapshot:
+  <<: *linux_official
+  tags:
+    - linux32
+    - official
+  except:
+    - tags
+
+linux32_official_release:
+  variables:
+    EXTRA_VERSION: ""
+  <<: *linux_official
+  tags:
+    - linux32
+    - official
   only:
     - /^gmsh_.*$/
 
@@ -149,7 +170,7 @@ windows32_official_release:
 # Official MacOS builds (master branch only)
 # ------------------------------------------
 
-.macos64_official: &macos64_official
+.macos_official: &macos_official
   only:
     - master
   script:
@@ -163,19 +184,22 @@ windows32_official_release:
     - scp ace@ace36.montefiore.ulg.ac.be:/tmp/${PKG} .
     - scp ${PKG} geuzaine@gmsh.info:.wwwgmsh/bin/MacOSX/${PKG}
     - /usr/local/bin/ctest -D Experimental -j 1 --output-on-failure
+
+macos64_official_snapshot:
+  <<: *macos_official
   tags:
     - macos64
     - official
-
-macos64_official_snapshot:
-  <<: *macos64_official
   except:
     - tags
 
 macos64_official_release:
   variables:
     EXTRA_VERSION: ""
-  <<: *macos64_official
+  <<: *macos_official
+  tags:
+    - macos64
+    - official
   only:
     - /^gmsh_.*$/
 
@@ -192,12 +216,12 @@ macos64_official_release:
     - /usr/local/bin/cmake -DGMSH_EXTRA_VERSION=${EXTRA_VERSION:0:13} ..
     - make package_source
     - PKG=`ls gmsh-*.tar*`; scp -o StrictHostKeyChecking=no -i /home/gitlab-runner/.ssh/id_rsa ${PKG} geuzaine@gmsh.info:.wwwgmsh/src/${PKG/\.tar\.gz/\.tgz}
-  tags:
-    - linux64
-    - official
 
 source_official_snapshot:
   <<: *source_official
+  tags:
+    - linux64
+    - official
   except:
     - tags
 
@@ -205,5 +229,8 @@ source_official_release:
   variables:
     EXTRA_VERSION: ""
   <<: *source_official
+  tags:
+    - linux64
+    - official
   only:
     - /^gmsh_.*$/
diff --git a/Common/gmsh.cpp b/Common/gmsh.cpp
index bffea8b6ab1a0c77b1ae453b8c20164be2d12002..2aa6a29a9e551d9c597e9b9e796a852ecd4869e8 100644
--- a/Common/gmsh.cpp
+++ b/Common/gmsh.cpp
@@ -2095,9 +2095,9 @@ void gmsh::view::probe(const int tag, const double x, const double y,
                        const double z, std::vector<double> &value,
                        const int step, const int numComp,
                        const bool gradient, const double tolerance,
-                       const std::vector<double> xElemCoord,
-                       const std::vector<double> yElemCoord,
-                       const std::vector<double> zElemCoord)
+                       const std::vector<double> &xElemCoord,
+                       const std::vector<double> &yElemCoord,
+                       const std::vector<double> &zElemCoord)
 {
   if(!_isInitialized()){ throw -1; }
 #if defined(HAVE_POST)
diff --git a/Common/gmsh.h b/Common/gmsh.h
index 594ecb6bd338e46d412ac0670c9ca615b3ee9638..8e5b1f4f4f50900cfd81fc196358ed0107275729 100644
--- a/Common/gmsh.h
+++ b/Common/gmsh.h
@@ -692,7 +692,7 @@ namespace gmsh { // Top-level functions
                                const double z, const double dx,
                                const double dy, const double dz,
                                const double r, const int tag = -1,
-                               double angle = 2*M_PI);
+                               const double angle = 2*M_PI);
       GMSH_API int addCone(const double x, const double y, const double z,
                            const double dx, const double dy, const double dz,
                            const double r1, const double r2,
@@ -849,11 +849,11 @@ namespace gmsh { // Top-level functions
                         const int step = -1, const int numComp = -1,
                         const bool gradient = false,
                         const double tolerance = 0.,
-                        const std::vector<double> xElemCoord
+                        const std::vector<double> &xElemCoord
                         = std::vector<double>(),
-                        const std::vector<double> yElemCoord
+                        const std::vector<double> &yElemCoord
                         = std::vector<double>(),
-                        const std::vector<double> zElemCoord
+                        const std::vector<double> &zElemCoord
                         = std::vector<double>());
 
     // Writes the view to a file. The export format is determined by the file
diff --git a/api/GenApi.py b/api/GenApi.py
new file mode 100644
index 0000000000000000000000000000000000000000..3cec0913dde36353254907e26669b27b5a9a9239
--- /dev/null
+++ b/api/GenApi.py
@@ -0,0 +1,587 @@
+import textwrap
+class arg:
+
+    def __init__(self,name,value,type_cpp,type_c,out):
+        self.name = name
+        self.value = value
+        self.out = out
+        self.type_cpp = type_cpp
+        self.type_c = type_c
+        self.cpp_value = (" = "+value) if value else ""
+
+        n = self.type_cpp 
+        n += " "
+        n += self.name
+        n += self.cpp_value
+        self.cpp = n
+
+        self.c_arg = self.name
+        self.c_pre = ""
+        self.c_post = ""
+        self.c = type_c + " " + name
+
+        self.python_arg = "not_implemented"
+        self.python_return = "not_implemented"
+        self.python_pre = ""
+
+def iint(name,value=None):
+    a = arg(name,value,"const int","const int",False)
+    a.python_arg = "c_int("+name+")"
+    return a
+
+class oint(arg):
+    rtype_cpp = "int"
+    rtype_c = "int"
+    def __init__(self,name,value=None):
+        arg.__init__(self,name,value,"int&","int*",True)
+        self.c_arg = "*"+name
+
+def istring(name,value=None):
+    #value = "\""+value+"\"" if value is not None else None
+    a = arg(name,value,"const std::string&","const char*",False)
+    a.python_arg = "c_char_p("+name+".encode())"
+    return a
+
+def ostring(name,value=None):
+    a = arg(name,value,"std::string &","char**",True)
+    a.c_arg = "api_"+name+"_"
+    a.c_pre = "  std::string "+a.c_arg +";\n"
+    a.c_post = "  *"+name+" = _strdup("+a.c_arg+".c_str());\n"
+    name_ = "api_"+name+"_"
+    a.python_pre = name_+" = c_char_p()"
+    a.python_arg = "byref("+name_+")"
+    a.python_return = "_ostring("+name_+")"
+    return a
+
+def idouble(name,value=None):
+     a = arg(name,value,"const double","const double",False)
+     a.python_arg = "c_double("+name+")"
+     return a
+
+def odouble(name,value=None):
+    a = arg(name,value,"double&","double*",True)
+    a.c_arg = "*"+name
+    name_ = "api_"+name+"_"
+    a.python_pre = name_+" = c_double()"
+    a.python_arg = "byref("+name_+")"
+    a.python_return = name_+".value"
+    return a
+
+def ovectorpair(name,value=None):
+    a = arg(name,value,"gmsh::vector_pair &","int**",True)
+    name_ = "api_"+name+"_"
+    name_n = name_ + "n_"
+    a.c_arg = name_
+    a.c_pre = "  gmsh::vector_pair "+name_ +";\n"
+    a.c_post = "  pairvector2intptr("+name_+"," + name + ","+name+"_n);\n"
+    a.c = "int** "+name+", size_t* "+name+"_n"
+    a.python_pre = name_+", "+name_n+" = POINTER(c_int)(), c_size_t()"
+    a.python_arg = "byref("+name_+"), byref("+name_n+")"
+    a.python_return = "_ovectorpair("+name_+", "+name_n+".value)"
+    return a
+
+def ovectorstring(name,value=None):
+    a = arg(name,value,"std::vector<std::string> &","char**",True)
+    name_ = "api_"+name+"_"
+    name_n = name_ + "n_"
+    a.c_arg = name_
+    a.c_pre = "  std::vector<std::string> "+name_ +";\n"
+    a.c_post = "  stringvector2charpp("+name_+"," + name + ","+name+"_n);\n"
+    a.c = "char*** "+name+",size_t* "+name+"_n"
+    a.python_pre = name_+", "+name_n+" = POINTER(c_char_p)(), c_size_t()"
+    a.python_arg = "byref("+name_+"), byref("+name_n+")"
+    a.python_return = "_ovectorstring("+name_+", "+name_n+".value)"
+    return a
+
+def ivectorpair(name,value=None):
+    a = arg(name,value,"const gmsh::vector_pair &","const int*",False)
+    a.c_arg = "intptr2pairvector("+name+","+name+"_n)"
+    a.c = "int* "+name+", size_t "+name+"_n"
+    a.python_pre = "api_"+name+"_, api"+name+"_n_ = _ivectorpair("+name+")"
+    a.python_arg = "api_"+name+"_, api"+name+"_n_"
+    return a
+
+def ibool(name,value=None):
+    a = arg(name,value,"const bool","const int",False)
+    a.python_arg = "c_int(bool("+name+"))"
+    return a
+    
+def obool(name,value=None):
+    a = arg(name,value,"bool &","int*",True)
+    a.c_arg = "api_"+name+"_"
+    a.c_pre = "  bool "+a.c_arg +";\n"
+    a.c_post = "  *"+name+" = (int)"+a.c_arg+";\n"
+    return a
+
+def ivectorint(name,value=None):
+    a = arg(name,value,"const std::vector<int> &","const int*",False)
+    a.c_arg = "ptr2vector("+name+","+name+"_n)"
+    a.c = "int* "+name+", size_t "+name+"_n"
+    a.python_pre = "api_"+name+"_, api"+name+"_n_ = _ivectorint("+name+")"
+    a.python_arg = "api_"+name+"_, api"+name+"_n_"
+    return a
+
+def ovectorint(name,value=None):
+    a = arg(name,value,"std::vector<int> &","int**",True)
+    name_ = "api_"+name+"_"
+    name_n = name_ + "n_"
+    a.c_arg = name_
+    a.c_pre = "  std::vector<int> "+name_ +";\n"
+    a.c_post = "  vector2ptr("+name_+"," + name + ","+name+"_n);\n"
+    a.c = "int** "+name+", size_t* "+name+"_n"
+    a.python_pre = name_+", "+name_n+" = POINTER(c_int)(), c_size_t()"
+    a.python_arg = "byref("+name_+"),byref("+name_n+")"
+    a.python_return = "_ovectorint("+name_+","+name_n+".value)"
+    return a
+
+def ivectordouble(name,value=None):
+    a = arg(name,value,"const std::vector<double> &","double**",False)
+    a.c_arg = "ptr2vector("+name+","+name+"_n)"
+    a.c  = "double* "+name+", size_t "+name+"_n"
+    a.python_pre = "api_"+name+"_, api"+name+"_n_ = _ivectordouble("+name+")"
+    a.python_arg = "api_"+name+"_, api"+name+"_n_"
+    return a
+
+def ovectordouble(name,value=None):
+    a = arg(name,value,"std::vector<double> &","double*",True)
+    name_ = "api_"+name+"_"
+    name_n = name_ + "n_"
+    a.c_arg = name_
+    a.c_pre = "  std::vector<double> "+a.c_arg +";\n"
+    a.c_post = "  vector2ptr("+name_+"," + name + ","+name+"_n);\n"
+    a.c  = "double** "+name+", size_t* "+name+"_n"
+    a.python_pre = name_+", "+name_n+" = POINTER(c_double)(), c_size_t()"
+    a.python_arg = "byref("+name_+"),byref("+name_n+")"
+    a.python_return = "_ovectordouble("+name_+","+name_n+".value)"
+    return a
+
+def ovectorvectorint(name,value=None):
+    a = arg(name,value,"std::vector<std::vector<int> > &","int**",True)
+    name_ = "api_"+name+"_"
+    name_n = name_ + "n_"
+    name_nn = name_ + "nn_"
+    a.c_arg = name_
+    a.c_pre = "  std::vector<std::vector<int> > "+a.c_arg +";\n"
+    a.c_post = "  vectorvector2ptrptr("+name_+"," + name + ","+name+"_n,"+name+"_nn);\n"
+    a.c  = "int*** "+name+", size_t** "+name+"_n, size_t *"+name+"_nn"
+    a.python_pre = name_+", "+name_n+", "+name_nn +" = POINTER(POINTER(c_int))(), POINTER(c_size_t)(), c_size_t()"
+    a.python_arg = "byref("+name_+"),byref("+name_n+"),byref("+name_nn+")"
+    a.python_return = "_ovectorvectorint("+name_+","+name_n+","+name_nn+")"
+    return a
+
+def ovectorvectorpair(name,value=None):
+    a = arg(name,value,"std::vector<gmsh::vector_pair> &","int**",True)
+    name_ = "api_"+name+"_"
+    name_n = name_ + "n_"
+    name_nn = name_ + "nn_"
+    a.c_arg = name_
+    a.c_pre = "  std::vector<gmsh::vector_pair >"+name_ +";\n"
+    a.c_post = "  pairvectorvector2intptrptr("+name_+"," + name + ","+name+"_n,"+name+"_nn);\n"
+    a.c  = "int*** "+name+", size_t** "+name+"_n, size_t *"+name+"_nn"
+    a.python_pre = name_+", "+name_n+", "+name_nn +" = POINTER(POINTER(c_int))(), POINTER(c_size_t)(), c_size_t()"
+    a.python_arg = "byref("+name_+"),byref("+name_n+"),byref("+name_nn+")"
+    a.python_return = "_ovectorvectorpair("+name_+","+name_n+","+name_nn+")"
+    return a
+
+class Module:
+
+    def __init__(self,name,doc):
+        self.name = name
+        self.doc = doc
+        self.fs = []
+        self.submodules = []
+
+    def add(self,name,doc,rtype,*args):
+        self.fs.append((rtype,name,args,doc))
+
+    def add_module(self, name,doc) :
+        module = Module(name,doc)
+        self.submodules.append(module)
+        return module
+
+
+cpp_header="""// Gmsh - Copyright (C) 1997-2017 C. Geuzaine,J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh@onelab.info>.
+
+#ifndef _GMSH_H_
+#define _GMSH_H_
+
+// This is the embryo of what will become the Gmsh API.
+//
+// Don't use it yet,it's not ready:-) We plan to release a first version in
+// Gmsh 3.1,and something more complete in Gmsh 4.0.
+//
+// Your input is welcome: please contribute your ideas on
+// https://gitlab.onelab.info/gmsh/gmsh/issues/188
+//
+// By design,the API is purely functional,and only uses elementary C++ types
+// from the standard library. This design should not and will not change.
+
+// All functions return 0 as the first entry of the returned vector on
+// successful completion. Additional integer results can be appends to this
+// returned value,depending on context.
+
+#include <cmath>
+#include <vector>
+#include <string>
+
+#if defined(WIN32)
+#define GMSH_API __declspec(dllexport)
+#else
+#define GMSH_API
+#endif
+
+
+namespace gmsh {
+  GMSH_API void initialize(int argc,char **argv);
+  typedef std::vector<std::pair<int,int> > vector_pair;
+}
+"""
+
+cpp_footer=""" 
+#undef GMSH_API
+
+#endif
+"""
+
+c_header="""// Gmsh - Copyright (C) 1997-2017 C. Geuzaine,J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh@onelab.info>.
+
+#ifndef _GMSHC_H_
+#define _GMSHC_H_
+
+// This is the embryo of what will become the Gmsh API.
+//
+// Don't use it yet,it's not ready:-) We plan to release a first version in
+// Gmsh 3.1,and something more complete in Gmsh 4.0.
+//
+// Your input is welcome: please contribute your ideas on
+// https://gitlab.onelab.info/gmsh/gmsh/issues/188
+//
+// By design,the API is purely functional,and only uses elementary C++ types
+// from the standard library. This design should not and will not change.
+
+// All functions return 0 as the first entry of the returned vector on
+// successful completion. Additional integer results can be appends to this
+// returned value,depending on context.
+
+#if defined(WIN32)
+#define GMSH_API __declspec(dllexport)
+#else
+#define GMSH_API
+#endif
+
+#include <stdlib.h>
+
+GMSH_API void gmshInitialize(char argc,char **argv);
+GMSH_API void gmshFree_(void *p);
+"""
+
+c_footer="""
+#undef GMSH_API
+
+#endif
+"""
+
+c_cpp_header="""// Gmsh - Copyright (C) 1997-2017 C. Geuzaine,J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh@onelab.info>.
+
+extern \"C\" {
+    #include "gmshc.h"
+}
+#include "gmsh.h"
+#include <cstring>
+
+char * _strdup(const char *i) {
+  size_t len = strlen(i);
+  char *o = (char*)malloc(sizeof(char)*(len+1));
+  memcpy(o,i,len+1);
+  return o;
+}
+
+template<typename t>
+std::vector<t> ptr2vector(const t *p,size_t size) {
+  return std::vector<t>(p,p+size);
+}
+
+template<typename t>
+void vector2ptr(const std::vector<t>&v,t **p,size_t *size) {
+  *p = (t*)malloc(sizeof(t)*(v.size()));
+  for (size_t i = 0; i < v.size(); ++i){
+    (*p)[i] = v[i];
+  }
+  *size = v.size();
+}
+
+void pairvector2intptr(const gmsh::vector_pair &v,int **p,size_t *size) {
+  *p = (int*)malloc(sizeof(int)*(v.size()*2));
+  for (size_t i = 0; i < v.size(); ++i){
+    (*p)[i*2+0] = v[i].first;
+    (*p)[i*2+1] = v[i].second;
+  }
+  *size = v.size()*2;
+}
+
+void stringvector2charpp(const std::vector<std::string> &v,char ***p,size_t *size) {
+  *p = (char**)malloc(sizeof(char*)*(v.size()*2));
+  for (size_t i = 0; i < v.size(); ++i){
+    (*p)[i] = _strdup(v[i].c_str());
+  }
+  *size = v.size();
+}
+
+gmsh::vector_pair intptr2pairvector(const int *p,size_t size){
+  gmsh::vector_pair v(size/2);
+  for (size_t i = 0; i < size/2; ++i) {
+    v[i].first = p[i*2+0];
+    v[i].second = p[i*2+1];
+  }
+  return v;
+}
+
+template<typename t>
+void vectorvector2ptrptr(const std::vector<std::vector<t> > &v,t ***p,size_t **size,size_t *sizeSize) {
+  *p = (t**)malloc(sizeof(t*)*v.size());
+  *size = (size_t*)malloc(sizeof(size_t)*v.size()); 
+  for (size_t i = 0; i < v.size(); ++i)
+    vector2ptr(v[i],&((*p)[i]),&((*size)[i]));
+  *sizeSize = v.size();
+}
+
+int** pairvectorvector2intptrptr(const std::vector<gmsh::vector_pair > &v,int ***p,size_t **size,size_t *sizeSize) {
+  *p = (int**)malloc(sizeof(int*)*v.size());
+  for (size_t i = 0; i < v.size(); ++i)
+    pairvector2intptr(v[i],p[i],size[i]);
+  *sizeSize = v.size();
+}
+
+void gmshInitialize(char argc,char **argv){
+  gmsh::initialize(argc,argv);
+}
+
+void gmshFree_(void *p) {
+  if(p) free(p);
+}
+"""
+
+python_header = """from ctypes import *
+import signal
+import os
+signal.signal(signal.SIGINT,signal.SIG_DFL)
+libdir = os.path.dirname(os.path.realpath(__file__))
+lib = CDLL(libdir+"/libgmshc.so")
+
+use_numpy = False
+try :
+    import numpy
+    use_numpy = True
+    try : 
+        import weakref
+    except :
+        from backports import weakref
+except :
+    pass
+
+def initialize() :
+    lib.gmshInitialize(c_int(0),c_voidp(None))
+
+def _ostring(s) :
+    sp = s.value.decode("utf-8")
+    lib.gmshFree_(s)
+    return sp
+
+def _ovectorpair(ptr,size):
+    if use_numpy :
+        v = numpy.ctypeslib.as_array(ptr, (size//2,2))
+        weakref.finalize(v, lib.gmshFree_, ptr)
+    else :
+        v = list((ptr[i*2],ptr[i*2+1]) for i in range(size//2))
+        lib.gmshFree_(ptr)
+    return v
+
+def _ovectorint(ptr,size):
+    if use_numpy :
+        v = numpy.ctypeslib.as_array(ptr, (size,))
+        weakref.finalize(v, lib.gmshFree_, ptr)
+    else :
+        v = list(ptr[i] for i in range(size))
+        lib.gmshFree_(ptr)
+    return v
+
+def _ovectordouble(ptr,size):
+    if use_numpy :
+        v = numpy.ctypeslib.as_array(ptr, (size,))
+        weakref.finalize(v, lib.gmshFree_, ptr)
+    else :
+        v = list(ptr[i] for i in range(size))
+        lib.gmshFree_(ptr)
+    return v
+
+
+def _ovectorvectorint(ptr,size,n):
+    v = [_ovectorint(pointer(ptr[i].contents),size[i]) for i in range(n.value)]
+    lib.gmshFree_(size)
+    lib.gmshFree_(ptr)
+    return v
+
+def _ovectorvectorpair(ptr,size,n):
+    v = [_ovectorpair(pointer(ptr[i].contents),size[i]) for i in range(n.value)]
+    lib.gmshFree_(size)
+    lib.gmshFree_(ptr)
+    return v
+
+def _ivectorint(o):
+    if use_numpy :
+        return  numpy.ascontiguousarray(o,numpy.int32).ctypes, c_size_t(len(o))
+    else :
+        return byref((c_int*len(o))(*o)), c_size_t(len(o))
+        
+
+def _ivectordouble(o):
+    if use_numpy :
+        return  numpy.ascontiguousarray(o,numpy.float64).ctypes, c_size_t(len(o))
+    else :
+        return byref((c_double*len(o))(*o)), c_size_t(len(o))
+
+def _ivectorpair(o):
+    if use_numpy :
+        return  numpy.ascontiguousarray(o,numpy.int32).reshape(len(o),2).ctypes, c_size_t(len(o)*2)
+    else :
+        return byref(((c_int*2)*len(o))(*o)), c_size_t(len(o)*2)
+
+"""
+
+class API:
+
+    def __init__(self):
+        self.modules = []
+
+    def add_module(self,name,doc):
+        module = Module(name,doc)
+        self.modules.append(module)
+        return module
+
+    def write_cpp(self):
+        def write_module(module,indent) :
+            f.write("\n"+indent+"namespace "+module.name +" { // " + module.doc + "\n\n")
+            indent += "  "
+            for rtype,name,args,doc in module.fs:
+                f.write("\n")
+                f.write(indent+"// "+("\n"+indent+"// ").join(textwrap.wrap(doc,75))+"\n\n")
+                rt = rtype.rtype_cpp if rtype else "void"
+                f.write(indent+"GMSH_API " + rt + " " + name + "(")
+                if args :
+                    f.write("\n"+indent+"    " +(",\n"+indent+"    ").join(a.cpp for a in args))
+                f.write(");\n\n")
+            for m in module.submodules :
+                write_module(m, indent)
+            f.write(indent[:-2]+"} // namespace "+ module.name+"\n\n")
+        with open("gmsh.h","w") as f:
+            f.write(cpp_header)
+            for m in self.modules:
+                write_module(m,"")
+            f.write(cpp_footer)
+
+    def write_c(self):
+        def write_module(module,c_namespace,cpp_namespace) :
+            cpp_namespace += module.name+"::"
+            if c_namespace :
+                c_namespace += module.name[0].upper()+module.name[1:]
+            else :
+                c_namespace = module.name
+            for rtype,name,args,doc in module.fs:
+                fname = c_namespace + name[0].upper()+name[1:]
+                f.write("\n/* "+"\n * ".join(textwrap.wrap(doc,75))+" */\n")
+                f.write("GMSH_API "+(rtype.rtype_c if rtype else "void"))
+                f.write(" "+fname+"(\n            "
+                        +",\n            ".join(list((a.c for a in args+(oint("ierr"),))))
+                        + ");\n")
+                fc.write(rtype.rtype_c if rtype else "void")
+                fc.write(" "+fname+"("
+                    +",".join(list((a.c for a in args+(oint("ierr"),))))+"){\n")
+                if rtype:
+                    fc.write("  "+ rtype.rtype_c + " result_api_;\n")
+                fc.write("  if(ierr) *ierr = 0;\n");
+                fc.write("  try {\n");
+                fc.write("".join((a.c_pre for a in args)))
+                fc.write("  ")
+                if rtype:
+                    fc.write("result_api_ = ")
+                fc.write(cpp_namespace+name+"("+",".join(
+                    list((a.c_arg for a in args)))+
+                    ");\n")
+                fc.write("".join((a.c_post for a in args)))
+                fc.write("  } catch(int api_ierr_) {if (ierr) *ierr = api_ierr_;}\n");
+                if rtype :
+                    fc.write("  return result_api_;\n");
+                fc.write("}\n\n")
+            for m in module.submodules :
+                write_module(m, c_namespace,cpp_namespace)
+
+        with open("gmshc.h","w") as f :
+            with open("gmshc.cc","w") as fc :
+                f.write(c_header)
+                fc.write(c_cpp_header)
+                for module in self.modules:
+                    write_module(module,"","")
+                f.write(c_footer)
+
+    def write_python(self) :
+        def write_function(f,rtype, name, args, doc, modulepath,indent):
+            iargs = list(a for a in args if not a.out)
+            oargs = list(a for a in args if a.out)
+            f.write("\n"+indent+"def "+name+"("
+                    +",".join((a.name for a in iargs))
+                    +"):\n")
+            indent += "    "
+            f.write(indent+'"""\n')
+            f.write(indent+("\n"+indent).join(textwrap.wrap(doc,75))+"\n")
+            if rtype or oargs :
+                f.write("\n"+indent+"return " + ", ".join(
+                    ([rtype.rtype_c] if rtype else[])
+                    +[a.name for a in oargs])
+                +"\n")
+            f.write(indent+'"""\n')
+            for a in args :
+                if a.python_pre : f.write(indent+a.python_pre+"\n")
+            f.write(indent+"ierr = c_int()\n")
+            f.write(indent+"api__result__ = " if rtype is oint else (indent))
+            c_name = modulepath + name[0].upper()+name[1:]
+            f.write("lib."+c_name+"(\n    "+indent
+                    +(",\n"+indent+"    ").join(tuple((a.python_arg for a in args))+("byref(ierr)",))
+                    +")\n")
+            f.write(indent+"if ierr.value != 0 :\n")
+            f.write(indent+"    raise ValueError(\n")
+            f.write(indent+"        \""+c_name+" returned non-zero error code : \",\n")
+            f.write(indent+"        ierr.value)\n")
+            r = (["api__result__"]) if rtype else []
+            r += list((o.python_return for o in oargs))
+            if len(r) != 0 :
+                if len(r) == 1 :
+                    f.write(indent+"return "+r[0]+"\n")
+                else :
+                    f.write(indent+"return (\n"+indent+"    "+(",\n"+indent+"    ").join(r)+")\n")
+        def write_module(f,m,modulepath,indent) :
+            if modulepath :
+                modulepath += m.name[0].upper()+m.name[1:]
+            else :
+                modulepath = m.name
+            for fun in m.fs :
+                write_function(f,*fun,modulepath,indent)
+            for module in m.submodules :
+                f.write("\n\n"+indent + "class " + module.name + ":\n")
+                indentm = indent + "    "
+                f.write(indentm+'"""\n')
+                f.write(indentm+("\n"+indentm).join(textwrap.wrap(module.doc,75))+"\n")
+                f.write(indentm+'"""\n')
+                write_module(f,module,modulepath,indentm)
+        with open("gmsh.py","w") as f :
+            f.write(python_header)
+            for module in self.modules:
+                write_module(f,module,"","")
diff --git a/api/Makefile b/api/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..2d0df2c5a137d18a24067bf808c2378550bf8e11
--- /dev/null
+++ b/api/Makefile
@@ -0,0 +1,5 @@
+all :
+	python extract.py
+	python gen.py
+	g++  gmshc.cc -shared -fPIC -L. -L../build -Wl,-rpath=../build -lstdc++ -lgmsh -o libgmshc.so
+	gcc main.c -L. -Wl,-rpath=. -L../build -Wl,-rpath=../build  -lgmshc -lgmsh -lstdc++ -o main
diff --git a/api/backports/__init__.py b/api/backports/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..36a5b559ffd1b8dd8ab0948c9799612aa3cc7848
--- /dev/null
+++ b/api/backports/__init__.py
@@ -0,0 +1,4 @@
+# See https://pypi.python.org/pypi/backports
+
+from pkgutil import extend_path
+__path__ = extend_path(__path__, __name__)
diff --git a/api/backports/weakref.py b/api/backports/weakref.py
new file mode 100644
index 0000000000000000000000000000000000000000..de6193bd74df35f6010862dd0fea183a01505cbf
--- /dev/null
+++ b/api/backports/weakref.py
@@ -0,0 +1,151 @@
+"""
+Partial backport of Python 3.6's weakref module:
+
+    finalize (new in Python 3.4)
+
+Backport modifications are marked with "XXX backport".
+"""
+from __future__ import absolute_import
+
+import itertools
+import sys
+from weakref import ref
+
+__all__ = ['finalize']
+
+
+class finalize(object):
+    """Class for finalization of weakrefable objects
+
+    finalize(obj, func, *args, **kwargs) returns a callable finalizer
+    object which will be called when obj is garbage collected. The
+    first time the finalizer is called it evaluates func(*arg, **kwargs)
+    and returns the result. After this the finalizer is dead, and
+    calling it just returns None.
+
+    When the program exits any remaining finalizers for which the
+    atexit attribute is true will be run in reverse order of creation.
+    By default atexit is true.
+    """
+
+    # Finalizer objects don't have any state of their own.  They are
+    # just used as keys to lookup _Info objects in the registry.  This
+    # ensures that they cannot be part of a ref-cycle.
+
+    __slots__ = ()
+    _registry = {}
+    _shutdown = False
+    _index_iter = itertools.count()
+    _dirty = False
+    _registered_with_atexit = False
+
+    class _Info(object):
+        __slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index")
+
+    def __init__(self, obj, func, *args, **kwargs):
+        if not self._registered_with_atexit:
+            # We may register the exit function more than once because
+            # of a thread race, but that is harmless
+            import atexit
+            atexit.register(self._exitfunc)
+            finalize._registered_with_atexit = True
+        info = self._Info()
+        info.weakref = ref(obj, self)
+        info.func = func
+        info.args = args
+        info.kwargs = kwargs or None
+        info.atexit = True
+        info.index = next(self._index_iter)
+        self._registry[self] = info
+        finalize._dirty = True
+
+    def __call__(self, _=None):
+        """If alive then mark as dead and return func(*args, **kwargs);
+        otherwise return None"""
+        info = self._registry.pop(self, None)
+        if info and not self._shutdown:
+            return info.func(*info.args, **(info.kwargs or {}))
+
+    def detach(self):
+        """If alive then mark as dead and return (obj, func, args, kwargs);
+        otherwise return None"""
+        info = self._registry.get(self)
+        obj = info and info.weakref()
+        if obj is not None and self._registry.pop(self, None):
+            return (obj, info.func, info.args, info.kwargs or {})
+
+    def peek(self):
+        """If alive then return (obj, func, args, kwargs);
+        otherwise return None"""
+        info = self._registry.get(self)
+        obj = info and info.weakref()
+        if obj is not None:
+            return (obj, info.func, info.args, info.kwargs or {})
+
+    @property
+    def alive(self):
+        """Whether finalizer is alive"""
+        return self in self._registry
+
+    @property
+    def atexit(self):
+        """Whether finalizer should be called at exit"""
+        info = self._registry.get(self)
+        return bool(info) and info.atexit
+
+    @atexit.setter
+    def atexit(self, value):
+        info = self._registry.get(self)
+        if info:
+            info.atexit = bool(value)
+
+    def __repr__(self):
+        info = self._registry.get(self)
+        obj = info and info.weakref()
+        if obj is None:
+            return '<%s object at %#x; dead>' % (type(self).__name__, id(self))
+        else:
+            return '<%s object at %#x; for %r at %#x>' % \
+                (type(self).__name__, id(self), type(obj).__name__, id(obj))
+
+    @classmethod
+    def _select_for_exit(cls):
+        # Return live finalizers marked for exit, oldest first
+        L = [(f,i) for (f,i) in cls._registry.items() if i.atexit]
+        L.sort(key=lambda item:item[1].index)
+        return [f for (f,i) in L]
+
+    @classmethod
+    def _exitfunc(cls):
+        # At shutdown invoke finalizers for which atexit is true.
+        # This is called once all other non-daemonic threads have been
+        # joined.
+        reenable_gc = False
+        try:
+            if cls._registry:
+                import gc
+                if gc.isenabled():
+                    reenable_gc = True
+                    gc.disable()
+                pending = None
+                while True:
+                    if pending is None or finalize._dirty:
+                        pending = cls._select_for_exit()
+                        finalize._dirty = False
+                    if not pending:
+                        break
+                    f = pending.pop()
+                    try:
+                        # gc is disabled, so (assuming no daemonic
+                        # threads) the following is the only line in
+                        # this function which might trigger creation
+                        # of a new finalizer
+                        f()
+                    except Exception:
+                        sys.excepthook(*sys.exc_info())
+                    assert f not in cls._registry
+        finally:
+            # prevent any more finalizers from executing during shutdown
+            finalize._shutdown = True
+            if reenable_gc:
+                gc.enable()
diff --git a/api/extract.py b/api/extract.py
new file mode 100644
index 0000000000000000000000000000000000000000..6a0363540eedbfe8dc67e3d1195bc2f51323640f
--- /dev/null
+++ b/api/extract.py
@@ -0,0 +1,96 @@
+import textwrap
+tmap = {
+        'int':'iint',
+        'char**':'icharpp',
+        'constbool':'ibool',
+        'constdouble':'idouble',
+        'constint':'iint',
+        'conststd::string&':'istring',
+        'conststd::vector<double>&':'ivectordouble',
+        'conststd::vector<int>&':'ivectorint',
+        'conststd::vector<std::vector<double>>&':'ivectorvectordouble',
+        'conststd::vector<std::vector<int>>&':'ivectorvectorint',
+        'constvector_pair&':'ivectorpair',
+        'double&': 'odouble',
+        'int&':'oint',
+        'std::string&':'ostring',
+        'std::vector<double>&':'ovectordouble',
+        'std::vector<int>&':'ovectorint',
+        'std::vector<std::string>&':'ovectorstring',
+        'std::vector<std::vector<int>>&':'ovectorvectorint',
+        'std::vector<vector_pair>&':'ovectorvectorpair',
+        'vector_pair&':'ovectorpair'
+}
+def parse_arg(a) :
+    value = None
+    eq = a.find("=")
+    if eq != -1 :
+        value = a[eq+1:].strip()
+        a = a[:eq].strip()
+    p = max(a.rfind(" "), a.rfind("*"), a.rfind("&"), a.rfind(">"))
+    name = a[p+1:]
+    typ = a[:p+1].replace(" ","")
+    return tmap[typ]+"('"+name+"'"+((",'"+value+"'") if value else "")+")"
+
+def parse_fun(f,fun,namespace,doc) :
+    iarg =fun.find("(")
+    earg =fun.rfind(")")
+    pre = fun[:iarg]
+    args = fun[iarg+1:earg].split(",")
+    w = pre.split()
+    t = w[1]
+    name = w[2]
+    ret = "None"
+    if t == "int" :
+        ret = "oint"
+    elif t != "void" :
+        raise NameError("Unknown return type : ", t)
+    if (args == ['']) :
+        args = []
+    #f.write("\ndoc = (\n"
+    #        "'''"+" '''\n'''".join(textwrap.wrap(doc))+"'''\n)\n")
+    f.write("\ndoc = '''"+doc+"'''\n")
+    if (name in ["initialize","setElements","addModelData"]) :
+        f.write("#")
+    f.write(namespace+".add("+",".join(["'"+name+"'","doc",ret]+[parse_arg(a) for a in args])+")\n")
+
+namespace = ["api"]
+
+with open("../Common/gmsh.h") as f :
+    with open("gen.py","w") as fo :
+        current_doc = ""
+        fo.write("from GenApi import *\n\napi = API()\n")
+        ls = f.readlines()
+        i = 0
+        while i < len(ls) :
+            l = ls[i].strip()
+            w = l.split()
+            i += 1
+            if not w :
+                continue
+            if w[0] == "GMSH_API" :
+                f = l
+                while f[-1] != ";" :
+                    l = ls[i].strip()
+                    i += 1
+                    f += " " + l
+                try :
+                    parse_fun(fo,f,namespace[-1],current_doc)
+                except :
+                    raise NameError(f)
+            elif l[:2] == "//":
+                current_doc = l[2:].strip()
+                while ls[i].strip()[:2]== "//":
+                    current_doc += ls[i].strip()[2:]
+                    i += 1
+            elif w[0] == "namespace" :
+                doc = " ".join(w[4:])
+                fo.write("\n"+w[1]+" = "+namespace[-1]+".add_module('"+w[1]+"','"+doc+"')\n")
+                namespace += [w[1]]
+                current_doc = ""
+            elif w[0] == "}" :
+                namespace.pop()
+        fo.write("\n")
+        fo.write("api.write_cpp()\n")
+        fo.write("api.write_c()\n")
+        fo.write("api.write_python()\n")
diff --git a/api/gen.py b/api/gen.py
new file mode 100644
index 0000000000000000000000000000000000000000..4c02099368394c6f526ae02198bb6489f13f85e9
--- /dev/null
+++ b/api/gen.py
@@ -0,0 +1,423 @@
+from GenApi import *
+
+api = API()
+
+gmsh = api.add_module('gmsh','Top-level functions')
+
+doc = '''Initializes Gmsh. This must be called before any call to the other functions in the API. If argc and argv are provided, they will be handled in the same way as the command line arguments in the Gmsh app.'''
+#gmsh.add('initialize',doc,None,iint('argc','0'),icharpp('argv','0'))
+
+doc = '''Finalizes Gmsh. This must be called when you are done using the Gmsh API.'''
+gmsh.add('finalize',doc,None)
+
+doc = '''Opens a file and adds one (or more) new model(s). Equivalent to the `File->Open' menu in the Gmsh app. Handling of the file depends on its extension and/or its contents.'''
+gmsh.add('open',doc,None,istring('fileName'))
+
+doc = '''Merges a file. Equivalent to the `File->Merge' menu in the Gmsh app. Handling of the file depends on its extension and/or its contents.'''
+gmsh.add('merge',doc,None,istring('fileName'))
+
+doc = '''Writes a file. The export format is determined by the file extension.'''
+gmsh.add('write',doc,None,istring('fileName'))
+
+doc = '''Clears all loaded models and post-processing data, and adds a new empty model.'''
+gmsh.add('clear',doc,None)
+
+option = gmsh.add_module('option','Global option handling functions')
+
+doc = '''Sets a numerical option to `value'. `name' is of the form "category.option" or "category[num].option". Available categories and options are listed in the Gmsh reference manual.'''
+option.add('setNumber',doc,None,istring('name'),idouble('value'))
+
+doc = '''Gets the `value' of a numerical option.'''
+option.add('getNumber',doc,None,istring('name'),odouble('value'))
+
+doc = '''Sets a string option to `value'.'''
+option.add('setString',doc,None,istring('name'),istring('value'))
+
+doc = '''Gets the `value' of a string option.'''
+option.add('getString',doc,None,istring('name'),ostring('value'))
+
+model = gmsh.add_module('model','Per-model functions')
+
+doc = '''Adds a new model, with name `name', and sets it as the current model.'''
+model.add('add',doc,None,istring('name'))
+
+doc = '''Removes the current model.'''
+model.add('remove',doc,None)
+
+doc = '''Lists the names of all models.'''
+model.add('list',doc,None,ovectorstring('names'))
+
+doc = '''Sets the current model to the model with name `name'. If several models have the same name, selects the one that was added first.'''
+model.add('setCurrent',doc,None,istring('name'))
+
+doc = '''Gets all the (elementary) geometrical entities in the current model. If `dim' is >= 0, returns only the entities of the specified dimension (e.g. points if `dim' == 0). The entities are returned as a vector of (dim, tag) integer pairs.'''
+model.add('getEntities',doc,None,ovectorpair('dimTags'),iint('dim','-1'))
+
+doc = '''Gets all the physical groups in the current model. If `dim' is >= 0, returns only the entities of the specified dimension (e.g. physical points if `dim' == 0). The entities are returned as a vector of (dim, tag) integer pairs.'''
+model.add('getPhysicalGroups',doc,None,ovectorpair('dimTags'),iint('dim','-1'))
+
+doc = '''Gets the tags of all the (elementary) geometrical entities making up the physical group of dimension `dim' and tag `tag'.'''
+model.add('getEntitiesForPhysicalGroup',doc,None,iint('dim'),iint('tag'),ovectorint('tags'))
+
+doc = '''Adds a physical group of dimension `dim', grouping the elementary entities with tags `tags'. The function returns the tag of the physical group, equal to `tag' if `tag' is positive, or a new tag if `tag' < 0.'''
+model.add('addPhysicalGroup',doc,oint,iint('dim'),ivectorint('tags'),iint('tag','-1'))
+
+doc = '''Sets the name of the physical group of dimension `dim' and tag `tag'.'''
+model.add('setPhysicalName',doc,None,iint('dim'),iint('tag'),istring('name'))
+
+doc = '''Gets the name of the physical group of dimension `dim' and tag `tag'.'''
+model.add('getPhysicalName',doc,None,iint('dim'),iint('tag'),ostring('name'))
+
+doc = '''Gets the boundary of the geometrical entities `dimTags'. Returns in `outDimTags' the boundary of the individual entities (if `combined' is false) or the boundary of the combined geometrical shape formed by all input entities (if `combined' is true). Returns tags multiplied by the sign of the boundary entity if `oriented' is true. Applies the boundary operator recursively down to dimension 0 (i.e. to points) if `recursive' is true.'''
+model.add('getBoundary',doc,None,ivectorpair('dimTags'),ovectorpair('outDimTags'),ibool('combined','true'),ibool('oriented','true'),ibool('recursive','false'))
+
+doc = '''Gets the (elementary) geometrical entities in the bounding box defined by the two points (xmin, ymin, zmin) and (xmax, ymax, zmax). If `dim' is >= 0, returns only the entities of the specified dimension (e.g. points if `dim' == 0).'''
+model.add('getEntitiesInBoundingBox',doc,None,idouble('xmin'),idouble('ymin'),idouble('zmin'),idouble('xmax'),idouble('ymax'),idouble('zmax'),ovectorpair('tags'),iint('dim','-1'))
+
+doc = '''Gets the bounding box (xmin, ymin, zmin), (xmax, ymax, zmax) of the geometrical entity of dimension `dim' and tag `tag'.'''
+model.add('getBoundingBox',doc,None,iint('dim'),iint('tag'),odouble('xmin'),odouble('ymin'),odouble('zmin'),odouble('xmax'),odouble('ymax'),odouble('zmax'))
+
+doc = '''Adds a discrete geometrical entity (defined by a mesh) of dimension `dim' in the current model. The function returns the tag of the new discrete entity, equal to `tag' if `tag' is positive, or a new tag if `tag' < 0. `boundary' specifies the tags of the entities on the boundary of the discrete entity, if any. Specyfing `boundary' allows Gmsh to construct the topology of the overall model.'''
+model.add('addDiscreteEntity',doc,oint,iint('dim'),iint('tag','-1'),ivectorint('boundary','std::vector<int>()'))
+
+doc = '''Removes the entities `dimTags' of the current model. If `recursive' is true, remove all the entities on their boundaries, down to dimension 0.'''
+model.add('removeEntities',doc,None,ivectorpair('dimTags'),ibool('recursive','false'))
+
+mesh = model.add_module('mesh','Per-model meshing functions')
+
+doc = '''Generates a mesh of the current model, up to dimension `dim' (0, 1, 2 or 3).'''
+mesh.add('generate',doc,None,iint('dim'))
+
+doc = '''Gets the last entities (if any) where a meshing error occurred. Currently only populated by the new 3D meshing algorithms.'''
+mesh.add('getLastEntityError',doc,None,ovectorpair('dimTags'))
+
+doc = '''Gets the last mesh vertices (if any) where a meshing error occurred. Currently only populated by the new 3D meshing algorithms.'''
+mesh.add('getLastVertexError',doc,None,ovectorint('vertexTags'))
+
+doc = '''Gets the mesh vertices of the entity of dimension `dim' and `tag' tag. `vertextags' contains the vertex tags (their unique, strictly positive identification numbers). `coord` is a vector of length `3 * vertexTags.size()' that contains the (x, y, z) coordinates of the vertices, concatenated. `parametricCoord` contains the parametric coordinates of the vertices, if available. The length of `parametricCoord` can be 0 or `dim * vertexTags.size()'.'''
+mesh.add('getVertices',doc,None,iint('dim'),iint('tag'),ovectorint('vertexTags'),ovectordouble('coord'),ovectordouble('parametricCoord'))
+
+doc = '''Gets the mesh elements of the entity of dimension `dim' and `tag' tag. `types' contains the MSH types of the elements (e.g. `2' for 3-node triangles: see the Gmsh reference manual). `elementTags' is a vector of length `types.size()'; each entry is a vector containing the tags (unique, strictly positive identifiers) of the elements of the corresponding type. `vertexTags' is also a vector of length `types.size()'; each entry is a vector of length equal to the number of elements of the given type times the number of vertices for this type of element, that contains the vertex tags of all the elements of the given type, concatenated.'''
+mesh.add('getElements',doc,None,iint('dim'),iint('tag'),ovectorint('types'),ovectorvectorint('elementTags'),ovectorvectorint('vertexTags'))
+
+doc = '''Sets the mesh vertices in the geometrical entity of dimension `dim' and tag `tag'. `vertextags' contains the vertex tags (their unique, strictly positive identification numbers). `coord` is a vector of length `3 * vertexTags.size()' that contains the (x, y, z) coordinates of the vertices, concatenated. The optional `parametricCoord` vector contains the parametric coordinates of the vertices, if any. The length of `parametricCoord` can be 0 or `dim * vertexTags.size()'.'''
+mesh.add('setVertices',doc,None,iint('dim'),iint('tag'),ivectorint('vertexTags'),ivectordouble('coord'),ivectordouble('parametricCoord','std::vector<double>()'))
+
+doc = '''Sets the mesh elements of the entity of dimension `dim' and `tag' tag. `types' contains the MSH types of the elements (e.g. `2' for 3-node triangles: see the Gmsh reference manual). `elementTags' is a vector of length `types.size()'; each entry is a vector containing the tags (unique, strictly positive identifiers) of the elements of the corresponding type. `vertexTags' is also a vector of length `types.size()'; each entry is a vector of length equal to the number of elements of the give type times the number of vertices per element, that contains the vertex tags of all the elements of the given type, concatenated.'''
+#mesh.add('setElements',doc,None,iint('dim'),iint('tag'),ivectorint('types'),ivectorvectorint('elementTags'),ivectorvectorint('vertexTags'))
+
+doc = '''Gets the coordinates and the parametric coordinates (if any) of the mesh vertex with tag `tag'. This is a useful by inefficient way of accessing mesh vertex data, as it relies on a cache stored in the model. For large meshes all the vertices in the model should be numbered in a continuous sequence of tags from 1 to N to maintain reasonnable performance (in this case the internal cache is based on a vector; otherwise it uses a map).'''
+mesh.add('getVertex',doc,None,iint('vertexTag'),ovectordouble('coord'),ovectordouble('parametricCoord'))
+
+doc = '''Gets the type and vertex tags of the mesh element with tag `tag'. This is a useful but inefficient way of accessing mesh element data, as it relies on a cache stored in the model. For large meshes all the elements in the model should be numbered in a continuous sequence of tags from 1 to N to maintain reasonnable performance (in this case the internal cache is based on a vector; otherwise it uses a map).'''
+mesh.add('getElement',doc,None,iint('elementTag'),oint('type'),ovectorint('vertexTags'))
+
+doc = '''Sets a mesh size constraint on the geometrical entities `dimTags'. Currently only entities of dimension 0 (points) are handled.'''
+mesh.add('setSize',doc,None,ivectorpair('dimTags'),idouble('size'))
+
+doc = '''Sets a transfinite meshing constraint on the line `tag', with `numVertices' mesh vertices distributed according to `type' and `coef'. Currently supported types are "Progression" (geometrical progression with power `coef') and "Bump" (refinement toward both extreminties of the line).'''
+mesh.add('setTransfiniteLine',doc,None,iint('tag'),iint('numVertices'),istring('type','"Progression"'),idouble('coef','1.'))
+
+doc = '''Sets a transfinite meshing constraint on the surface `tag'. `arrangement' describes the arrangement of the triangles when the surface is not flagged as recombined: currently supported values are "Left", "Right", "AlternateLeft" and "AlternateRight". `cornerTags' can be used to specify the (3 or 4) corners of the transfinite interpolation explicitly; specifying the corners explicitly is mandatory if the surface has more that 3 or 4 points on its boundary.'''
+mesh.add('setTransfiniteSurface',doc,None,iint('tag'),istring('arrangement','"Left"'),ivectorint('cornerTags','std::vector<int>()'))
+
+doc = '''Sets a transfinite meshing constraint on the surface `tag'. `cornerTags' can be used to specify the (6 or 8) corners of the transfinite interpolation explicitly.'''
+mesh.add('setTransfiniteVolume',doc,None,iint('tag'),ivectorint('cornerTags','std::vector<int>()'))
+
+doc = '''Sets a recombination meshing constraint on the geometrical entity of dimension `dim' and tag `tag'. Currently only entities of dimension 2 (to recombine triangles into quadrangles) are supported.'''
+mesh.add('setRecombine',doc,None,iint('dim'),iint('tag'))
+
+doc = '''Sets a smoothing meshing constraint on the geometrical entity of dimension `dim' and tag `tag'. `val' iterations of a Laplace smoother are applied.'''
+mesh.add('setSmoothing',doc,None,iint('dim'),iint('tag'),iint('val'))
+
+doc = '''Sets a reverse meshing constraint on the geometrical entity of dimension `dim' and tag `tag'. If `val' is true, the mesh orientation will be reversed with respect to the natural mesh orientation (i.e. the orientation consistent with the orientation of the geometrical entity). If `val' is false, the mesh is left as-is.'''
+mesh.add('setReverse',doc,None,iint('dim'),iint('tag'),ibool('val','true'))
+
+doc = '''Emebds the geometrical entities of dimension `dim' and tags `tags' in the (inDim, inTag) geometrical entity. `inDim' must be strictly greater than `dim'.'''
+mesh.add('embed',doc,None,iint('dim'),ivectorint('tags'),iint('inDim'),iint('inTag'))
+
+field = mesh.add_module('field','Per-model mesh size field functions')
+
+doc = '''Adds a new mesh size field of type `type'. If `tag' is positive, assign the tag explcitly; otherwise a new tag is assigned automatically. Returns the field tag.'''
+field.add('add',doc,oint,istring('type'),iint('tag','-1'))
+
+doc = '''Removes the field with tag `tag'.'''
+field.add('remove',doc,None,iint('tag'))
+
+doc = '''Sets the numerical option `option' to value `value' for field `tag'.'''
+field.add('setNumber',doc,None,iint('tag'),istring('option'),idouble('value'))
+
+doc = '''Sets the string option `option' to value `value' for field `tag'.'''
+field.add('setString',doc,None,iint('tag'),istring('option'),istring('value'))
+
+doc = '''Sets the numerical list option `option' to value `value' for field `tag'.'''
+field.add('setNumbers',doc,None,iint('tag'),istring('option'),ivectordouble('value'))
+
+doc = '''Sets the field `tag' as background mesh size field.'''
+field.add('setAsBackground',doc,None,iint('tag'))
+
+geo = model.add_module('geo','Internal per-model GEO CAD kernel functions')
+
+doc = '''Adds a geometrical point in the internal GEO CAD representation, at coordinates (x, y, z). If `meshSize' is > 0, adds a meshing constraint at that point. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. Returns the tag of the point. (Note that the point will be added in the current model only after gmshModelGeoSynchronize() is called. This behavior holds for all the entities added in the gmshModelGeo module.)'''
+geo.add('addPoint',doc,oint,idouble('x'),idouble('y'),idouble('z'),idouble('meshSize','0.'),iint('tag','-1'))
+
+doc = '''Adds a straight line segment between the two points with tags `startTag' and `endTag'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. Returns the tag of the line.'''
+geo.add('addLine',doc,oint,iint('startTag'),iint('endTag'),iint('tag','-1'))
+
+doc = '''Adds a circle arc (stricly smaller than Pi) between the two points with tags `startTag' and `endTag', with center `centertag'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. If (`nx', `ny', `nz') != (0,0,0), explicitely sets the plane of the circle arc. Returns the tag of the circle arc.'''
+geo.add('addCircleArc',doc,oint,iint('startTag'),iint('centerTag'),iint('endTag'),iint('tag','-1'),idouble('nx','0.'),idouble('ny','0.'),idouble('nz','0.'))
+
+doc = '''Adds an ellipse arc (stricly smaller than Pi) between the two points `startTag' and `endTag', with center `centertag' and major axis point `majorTag'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. If (`nx', `ny', `nz') != (0,0,0), explicitely sets the plane of the circle arc. Returns the tag of the ellipse arc.'''
+geo.add('addEllipseArc',doc,oint,iint('startTag'),iint('centerTag'),iint('majorTag'),iint('endTag'),iint('tag','-1'),idouble('nx','0.'),idouble('ny','0.'),idouble('nz','0.'))
+
+doc = '''Adds a spline curve going through `vertexTags' points. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically.  Returns the tag of the spline curve.'''
+geo.add('addSpline',doc,oint,ivectorint('vertexTags'),iint('tag','-1'))
+
+doc = '''Adds a b-spline curve with `vertexTags' control points. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically.  Returns the tag of the b-spline curve.'''
+geo.add('addBSpline',doc,oint,ivectorint('vertexTags'),iint('tag','-1'))
+
+doc = '''Adds a Bezier curve with `vertexTags' control points. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically.  Returns the tag of the Bezier curve.'''
+geo.add('addBezier',doc,oint,ivectorint('vertexTags'),iint('tag','-1'))
+
+doc = '''Adds a line loop (a closed wire) formed by `edgeTags'. `edgeTags' should contain (signed) tags of geometrical enties of dimension 1 forming a closed loop: a negative tag signifies that the underlying edge is considered with reversed orientation. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. Returns the tag of the line loop.'''
+geo.add('addLineLoop',doc,oint,ivectorint('edgeTags'),iint('tag','-1'))
+
+doc = '''Adds a plane surface defined by one or more line loops `wireTags'. The first line loop defines the exterior contour; additional line loop define holes. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. Returns the tag of the surface.'''
+geo.add('addPlaneSurface',doc,oint,ivectorint('wireTags'),iint('tag','-1'))
+
+doc = '''Adds a surface filling the line loops in `wireTags'. Currently only a single line loop is supported; this line loop should be composed by 3 or 4 edges only. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. Returns the tag of the surface.'''
+geo.add('addSurfaceFilling',doc,oint,ivectorint('wireTags'),iint('tag','-1'),iint('sphereCenterTag','-1'))
+
+doc = '''Adds a surface loop (a closed shell) formed by `faceTags'.  If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. Returns the tag of the surface loop.'''
+geo.add('addSurfaceLoop',doc,oint,ivectorint('faceTags'),iint('tag','-1'))
+
+doc = '''Adds a volume defined by one or more surface loops `shellTags'. The first surface loop defines the exterior boundary; additional surface loop define holes. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. Returns the tag of the volume.'''
+geo.add('addVolume',doc,oint,ivectorint('shellTags'),iint('tag','-1'))
+
+doc = '''Extrudes the geometrical entities in `dimTags' by translation along (`dx', `dy', `dz'). Returns extruded entities in `outDimTags'. If `numElements' is not empty, also extrude the mesh: the entries in `numElements' give the number of elements in each layer. If `height' is not empty, it provides the (cummulative) height of the different layers, normalized to 1.'''
+geo.add('extrude',doc,None,ivectorpair('dimTags'),idouble('dx'),idouble('dy'),idouble('dz'),ovectorpair('outDimTags'),ivectorint('numElements','std::vector<int>()'),ivectordouble('heights','std::vector<double>()'),ibool('recombine','false'))
+
+doc = '''Extrudes the geometrical entities in `dimTags' by rotation of `angle' radians around the axis of revolution defined by the point (`x', `y', `z') and the direction (`ax', `ay', `az'). Returns extruded entities in `outDimTags'. If `numElements' is not empty, also extrude the mesh: the entries in `numElements' give the number of elements in each layer. If `height' is not empty, it provides the (cummulative) height of the different layers, normalized to 1.'''
+geo.add('revolve',doc,None,ivectorpair('dimTags'),idouble('x'),idouble('y'),idouble('z'),idouble('ax'),idouble('ay'),idouble('az'),idouble('angle'),ovectorpair('outDimTags'),ivectorint('numElements','std::vector<int>()'),ivectordouble('heights','std::vector<double>()'),ibool('recombine','false'))
+
+doc = '''Extrudes the geometrical entities in `dimTags' by a combined translation and rotation of `angle' radians, along (`dx', `dy', `dz') and around the axis of revolution defined by the point (`x', `y', `z') and the direction (`ax', `ay', `az'). Returns extruded entities in `outDimTags'. If `numElements' is not empty, also extrude the mesh: the entries in `numElements' give the number of elements in each layer. If `height' is not empty, it provides the (cummulative) height of the different layers, normalized to 1.'''
+geo.add('twist',doc,None,ivectorpair('dimTags'),idouble('x'),idouble('y'),idouble('z'),idouble('dx'),idouble('dy'),idouble('dz'),idouble('ax'),idouble('ay'),idouble('az'),idouble('angle'),ovectorpair('outDimTags'),ivectorint('numElements','std::vector<int>()'),ivectordouble('heights','std::vector<double>()'),ibool('recombine','false'))
+
+doc = '''Translates the geometrical entities in `dimTags' along (`dx', `dy', `dz').'''
+geo.add('translate',doc,None,ivectorpair('dimTags'),idouble('dx'),idouble('dy'),idouble('dz'))
+
+doc = '''Rotates the geometrical entities in `dimTags' of `angle' radians around the axis of revolution defined by the point (`x', `y', `z') and the direction (`ax', `ay', `az').'''
+geo.add('rotate',doc,None,ivectorpair('dimTags'),idouble('x'),idouble('y'),idouble('z'),idouble('ax'),idouble('ay'),idouble('az'),idouble('angle'))
+
+doc = '''Scales the geometrical entities in `dimTag' by factors `a', `b' and `c' along the three coordinate axes; use (`x', `y', `z') as the center of the homothetic transformation.'''
+geo.add('dilate',doc,None,ivectorpair('dimTags'),idouble('x'),idouble('y'),idouble('z'),idouble('a'),idouble('b'),idouble('c'))
+
+doc = '''Applies a symmetry transformation to the geometrical entities in `dimTag', with respect to the plane of equation `a' * x + `b' * y + `c' * z + `d' = 0.'''
+geo.add('symmetry',doc,None,ivectorpair('dimTags'),idouble('a'),idouble('b'),idouble('c'),idouble('d'))
+
+doc = '''Copies the entities in `dimTags'; the new entities are returned in `outDimTags'.'''
+geo.add('copy',doc,None,ivectorpair('dimTags'),ovectorpair('outDimTags'))
+
+doc = '''Removes the entities `dimTags'. If `recursive' is true, remove all the entities on their boundaries, down to dimension 0.'''
+geo.add('remove',doc,None,ivectorpair('dimTags'),ibool('recursive','false'))
+
+doc = '''Remove all duplicate entities (different entities at the same geometrical location).'''
+geo.add('removeAllDuplicates',doc,None)
+
+doc = '''Synchronize the internal GEO CAD representation with the current Gmsh model. This can be called at any time, but since it involves a non trivial amount of processing, the number of synchronization points should normally be minimized.'''
+geo.add('synchronize',doc,None)
+
+mesh = geo.add_module('mesh','geo-specific meshing constraints')
+
+doc = '''Sets a mesh size constraint on the geometrical entities `dimTags'. Currently only entities of dimension 0 (points) are handled.'''
+mesh.add('setSize',doc,None,ivectorpair('dimTags'),idouble('size'))
+
+doc = '''Sets a transfinite meshing constraint on the line `tag', with `numVertices' mesh vertices distributed according to `type' and `coef'. Currently supported types are "Progression" (geometrical progression with power `coef') and "Bump" (refinement toward both extreminties of the line).'''
+mesh.add('setTransfiniteLine',doc,None,iint('tag'),iint('nPoints'),istring('type','"Progression"'),idouble('coef','1.'))
+
+doc = '''Sets a transfinite meshing constraint on the surface `tag'. `arrangement' describes the arrangement of the triangles when the surface is not flagged as recombined: currently supported values are "Left", "Right", "AlternateLeft" and "AlternateRight". `cornerTags' can be used to specify the (3 or 4) corners of the transfinite interpolation explicitly; specifying the corners explicitly is mandatory if the surface has more that 3 or 4 points on its boundary.'''
+mesh.add('setTransfiniteSurface',doc,None,iint('tag'),istring('arrangement','"Left"'),ivectorint('cornerTags','std::vector<int>()'))
+
+doc = '''Sets a transfinite meshing constraint on the surface `tag'. `cornerTags' can be used to specify the (6 or 8) corners of the transfinite interpolation explicitly.'''
+mesh.add('setTransfiniteVolume',doc,None,iint('tag'),ivectorint('cornerTags','std::vector<int>()'))
+
+doc = '''Sets a recombination meshing constraint on the geometrical entity of dimension `dim' and tag `tag'. Currently only entities of dimension 2 (to recombine triangles into quadrangles) are supported.'''
+mesh.add('setRecombine',doc,None,iint('dim'),iint('tag'),idouble('angle','45.'))
+
+doc = '''Sets a smoothing meshing constraint on the geometrical entity of dimension `dim' and tag `tag'. `val' iterations of a Laplace smoother are applied.'''
+mesh.add('setSmoothing',doc,None,iint('dim'),iint('tag'),iint('val'))
+
+doc = '''Sets a reverse meshing constraint on the geometrical entity of dimension `dim' and tag `tag'. If `val' is true, the mesh orientation will be reversed with respect to the natural mesh orientation (i.e. the orientation consistent with the orientation of the geometrical entity). If `val' is false, the mesh is left as-is.'''
+mesh.add('setReverse',doc,None,iint('dim'),iint('tag'),ibool('val','true'))
+
+occ = model.add_module('occ','Internal per-model OpenCASCADE CAD kernel functions')
+
+doc = '''Adds a geometrical point in the internal OpenCASCADE CAD representation, at coordinates (x, y, z). If `meshSize' is > 0, adds a meshing constraint at that point. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. Returns the tag of the point. (Note that the point will be added in the current model only after gmshModelGeoSynchronize() is called. This behavior holds for all the entities added in the gmshModelOcc module.)'''
+occ.add('addPoint',doc,oint,idouble('x'),idouble('y'),idouble('z'),idouble('meshSize','0.'),iint('tag','-1'))
+
+doc = '''Adds a straight line segment between the two points with tags `startTag' and `endTag'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. Returns the tag of the line.'''
+occ.add('addLine',doc,oint,iint('startTag'),iint('endTag'),iint('tag','-1'))
+
+doc = '''Adds a circle arc between the two points with tags `startTag' and `endTag', with center `centertag'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. Returns the tag of the circle arc.'''
+occ.add('addCircleArc',doc,oint,iint('startTag'),iint('centerTag'),iint('endTag'),iint('tag','-1'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addCircle',doc,oint,idouble('x'),idouble('y'),idouble('z'),idouble('r'),iint('tag','-1'),idouble('angle1','0.'),idouble('angle2','2*M_PI'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addEllipseArc',doc,oint,iint('startTag'),iint('centerTag'),iint('endTag'),iint('tag','-1'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addEllipse',doc,oint,idouble('x'),idouble('y'),idouble('z'),idouble('r1'),idouble('r2'),iint('tag','-1'),idouble('angle1','0.'),idouble('angle2','2*M_PI'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addSpline',doc,oint,ivectorint('vertexTags'),iint('tag','-1'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addBezier',doc,oint,ivectorint('vertexTags'),iint('tag','-1'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addBSpline',doc,oint,ivectorint('vertexTags'),iint('tag','-1'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addWire',doc,oint,ivectorint('edgeTags'),iint('tag','-1'),ibool('checkClosed','false'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addLineLoop',doc,oint,ivectorint('edgeTags'),iint('tag','-1'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addRectangle',doc,oint,idouble('x'),idouble('y'),idouble('z'),idouble('dx'),idouble('dy'),iint('tag','-1'),idouble('roundedRadius','0.'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addDisk',doc,oint,idouble('xc'),idouble('yc'),idouble('zc'),idouble('rx'),idouble('ry'),iint('tag','-1'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addPlaneSurface',doc,oint,ivectorint('wireTags'),iint('tag','-1'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addSurfaceFilling',doc,oint,iint('wireTag'),iint('tag','-1'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addSurfaceLoop',doc,oint,ivectorint('faceTags'),iint('tag','-1'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addVolume',doc,oint,ivectorint('shellTags'),iint('tag','-1'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addSphere',doc,oint,idouble('xc'),idouble('yc'),idouble('zc'),idouble('radius'),iint('tag','-1'),idouble('angle1','-M_PI/2'),idouble('angle2','M_PI/2'),idouble('angle3','2*M_PI'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addBox',doc,oint,idouble('x'),idouble('y'),idouble('z'),idouble('dx'),idouble('dy'),idouble('dz'),iint('tag','-1'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addCylinder',doc,oint,idouble('x'),idouble('y'),idouble('z'),idouble('dx'),idouble('dy'),idouble('dz'),idouble('r'),iint('tag','-1'),idouble('angle','2*M_PI'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addCone',doc,oint,idouble('x'),idouble('y'),idouble('z'),idouble('dx'),idouble('dy'),idouble('dz'),idouble('r1'),idouble('r2'),iint('tag','-1'),idouble('angle','2*M_PI'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addWedge',doc,oint,idouble('x'),idouble('y'),idouble('z'),idouble('dx'),idouble('dy'),idouble('dz'),iint('tag','-1'),idouble('ltx','0.'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addTorus',doc,oint,idouble('x'),idouble('y'),idouble('z'),idouble('r1'),idouble('r2'),iint('tag','-1'),idouble('angle','2*M_PI'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addThruSections',doc,oint,ivectorint('wireTags'),ovectorpair('outDimTags'),iint('tag','-1'),ibool('makeSolid','true'),ibool('makeRuled','false'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addThickSolid',doc,oint,iint('solidTag'),ivectorint('excludeFaceTags'),idouble('offset'),ovectorpair('outDimTags'),iint('tag','-1'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('extrude',doc,None,ivectorpair('dimTags'),idouble('dx'),idouble('dy'),idouble('dz'),ovectorpair('outDimTags'),ivectorint('numElements','std::vector<int>()'),ivectordouble('heights','std::vector<double>()'),ibool('recombine','false'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('revolve',doc,None,ivectorpair('dimTags'),idouble('x'),idouble('y'),idouble('z'),idouble('ax'),idouble('ay'),idouble('az'),idouble('angle'),ovectorpair('outDimTags'),ivectorint('numElements','std::vector<int>()'),ivectordouble('heights','std::vector<double>()'),ibool('recombine','false'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('addPipe',doc,None,ivectorpair('dimTags'),iint('wireTag'),ovectorpair('outDimTags'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('fillet',doc,None,ivectorint('regionTags'),ivectorint('edgeTags'),idouble('radius'),ovectorpair('outDimTags'),ibool('removeRegion','true'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('booleanUnion',doc,oint,ivectorpair('objectDimTags'),ivectorpair('toolDimTags'),ovectorpair('outDimTags'),ovectorvectorpair('outDimTagsMap'),iint('tag','-1'),ibool('removeObject','true'),ibool('removeTool','true'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('booleanIntersection',doc,oint,ivectorpair('objectDimTags'),ivectorpair('toolDimTags'),ovectorpair('outDimTags'),ovectorvectorpair('outDimTagsMap'),iint('tag','-1'),ibool('removeObject','true'),ibool('removeTool','true'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('booleanDifference',doc,oint,ivectorpair('objectDimTags'),ivectorpair('toolDimTags'),ovectorpair('outDimTags'),ovectorvectorpair('outDimTagsMap'),iint('tag','-1'),ibool('removeObject','true'),ibool('removeTool','true'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('booleanFragments',doc,oint,ivectorpair('objectDimTags'),ivectorpair('toolDimTags'),ovectorpair('outDimTags'),ovectorvectorpair('outDimTagsMap'),iint('tag','-1'),ibool('removeObject','true'),ibool('removeTool','true'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('translate',doc,None,ivectorpair('dimTags'),idouble('dx'),idouble('dy'),idouble('dz'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('rotate',doc,None,ivectorpair('dimTags'),idouble('x'),idouble('y'),idouble('z'),idouble('ax'),idouble('ay'),idouble('az'),idouble('angle'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('dilate',doc,None,ivectorpair('dimTags'),idouble('x'),idouble('y'),idouble('z'),idouble('a'),idouble('b'),idouble('c'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('symmetry',doc,None,ivectorpair('dimTags'),idouble('a'),idouble('b'),idouble('c'),idouble('d'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('copy',doc,None,ivectorpair('dimTags'),ovectorpair('outDimTags'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('remove',doc,None,ivectorpair('dimTags'),ibool('recursive','false'))
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('removeAllDuplicates',doc,None)
+
+doc = '''Adds a circle of center (`x', `y', `z') and radius `r'. If `tag' is positive, sets the tag explicitly; otherwise a new tag is selected automatically. `angle1' and `angle2' allow to add a circle arc. Returns the tag of the circle.'''
+occ.add('importShapes',doc,None,istring('fileName'),ovectorpair('outDimTags'),ibool('highestDimOnly','true'),istring('format','""'))
+
+doc = '''Sets a mesh size constraint on the geometrical entities `dimTags'. Currently only entities of dimension 0 (points) are handled.'''
+occ.add('setMeshSize',doc,None,ivectorpair('dimTags'),idouble('size'))
+
+doc = '''Synchronize the internal OpenCASCADE CAD representation with the current Gmsh model. This can be called at any time, but since it involves a non trivial amount of processing, the number of synchronization points should normally be minimized.'''
+occ.add('synchronize',doc,None)
+
+view = gmsh.add_module('view','Post-processing view functions')
+
+doc = '''Adds a new post-processing view, with name `name'. If `tag' is positive use it (and remove the view with that tag if it already exists), otherwise associate a new tag. Returns the view tag.'''
+view.add('add',doc,oint,istring('name'),iint('tag','-1'))
+
+doc = '''Removes the view with tag `tag'.'''
+view.add('remove',doc,None,iint('tag'))
+
+doc = '''Gets the index of the view with tag `tag' in the list of currently loaded views. This dynamic index (it can change when views are removed) is used to access view options with the gmshOption functions.'''
+view.add('getIndex',doc,oint,iint('tag'))
+
+doc = '''Gets the tags of all views.'''
+view.add('getTags',doc,None,ovectorint('tags'))
+
+doc = '''Adds model-based post-processing data to the view with tag `tag'. `modelName' identifies the model the data is attached to. `dataType' specifies the type of data, currently either "NodeData", "ElementData" or "ElementNodeData". `tags' gives the tags of the vertices or elements in the mesh to which the data is associated. `data' is a vector of length `tags.size()`: each entry is the vector of double precision numbers representing the data associated with the corresponding tag. The optional `step` and `time` arguments associate a time step and time value with the data. `numComponents' gives the number of data components (1 for scalar data, 3 for vector data, etc.) per entity; if negative, it is automatically inferred (when possible) from the input data. `partition' allows to specify data in several sub-sets.'''
+#view.add('addModelData',doc,None,iint('tag'),istring('modelName'),istring('dataType'),ivectorint('tags'),ivectorvectordouble('data'),iint('step','0'),iint('time','0.'),iint('numComponents','-1'),iint('partition','0'))
+
+doc = '''Adds list-based post-processing data to the view with tag `tag'. `type' identifies the data: "SP" for scalar points, "VP", for vector points, etc. `numEle' gives the number of elements in the data. `data' contains the data for the `numEle' elements.'''
+view.add('addListData',doc,None,iint('tag'),istring('type'),iint('numEle'),ivectordouble('data'))
+
+doc = '''Probes the view `tag' for its `value' at point (`x', `y', `z').'''
+view.add('probe',doc,None,iint('tag'),idouble('x'),idouble('y'),idouble('z'),ovectordouble('value'),iint('step','-1'),iint('numComp','-1'),ibool('gradient','false'),idouble('tolerance','0.'),ivectordouble('xElemCoord','std::vector<double>()'),ivectordouble('yElemCoord','std::vector<double>()'),ivectordouble('zElemCoord','std::vector<double>()'))
+
+doc = '''Writes the view to a file. The export format is determined by the file extension.'''
+view.add('write',doc,None,iint('tag'),istring('fileName'),ibool('append','false'))
+
+plugin = gmsh.add_module('plugin','Plugin functions')
+
+doc = '''Sets the numerical option `option` to the value `value' for plugin `name'.'''
+plugin.add('setNumber',doc,None,istring('name'),istring('option'),idouble('value'))
+
+doc = '''Sets the string option `option` to the value `value' for plugin `name'.'''
+plugin.add('setString',doc,None,istring('name'),istring('option'),istring('value'))
+
+doc = '''Runs the plugin `name'.'''
+plugin.add('run',doc,None,istring('name'))
+
+api.write_cpp()
+api.write_c()
+api.write_python()
diff --git a/api/main.c b/api/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..7baa31cc156ca1306292350028ad6299134f4f37
--- /dev/null
+++ b/api/main.c
@@ -0,0 +1,80 @@
+#include <stdio.h>
+#include "gmshc.h"
+
+#define chk(ierr) if (ierr != 0) {fprintf(stderr, "ERROR on line %i in function '%s': gmsh function return non-zero error code: %i\n",__LINE__, __FUNCTION__,ierr); gmshFinalize(NULL); exit(ierr);}
+
+void genGeometry() {
+  int ierr;
+  gmshModelAdd("square",&ierr);chk(ierr);
+  gmshModelGeoAddPoint(0,0,0,0.1,1,&ierr);chk(ierr);
+  gmshModelGeoAddPoint(1,0,0,0.1,2,&ierr);chk(ierr);
+  gmshModelGeoAddPoint(1,1,0,0.1,3,&ierr);chk(ierr);
+  gmshModelGeoAddPoint(0,1,0,0.1,4,&ierr);chk(ierr);
+  gmshModelGeoAddLine(1,2,1,&ierr); chk(ierr);
+  gmshModelGeoAddLine(2,3,2,&ierr); chk(ierr);
+  gmshModelGeoAddLine(3,4,3,&ierr); chk(ierr);
+  // try automatic assignement of tag
+  int line4 = gmshModelGeoAddLine(4,1,-1,&ierr); chk(ierr);
+  printf("line4 received tag %i\n\n", line4);
+  int ll[] = {1,2,3,line4};
+  gmshModelGeoAddLineLoop(ll,4,1,&ierr); chk(ierr);
+  int s[] = {1};
+  gmshModelGeoAddPlaneSurface(ll,1,6,&ierr); chk(ierr);
+  gmshModelGeoSynchronize(&ierr); chk(ierr);
+}
+
+void printMesh() {
+  int ierr;
+  int *dimTags;
+  size_t ndimTags;
+
+  gmshModelGetEntities(&dimTags, &ndimTags, -1,&ierr); chk(ierr);
+
+  for (size_t ie = 0; ie < ndimTags/2; ++ie) {
+    int *types, **elementTags, **vertexTags;
+    size_t ntypes, *nelementTags, nnelementTags, *nvertexTags, nnvertexTags;
+
+    gmshModelMeshGetElements(dimTags[ie*2+0], dimTags[ie*2+1], &types, &ntypes, &elementTags, &nelementTags, &nnelementTags, &vertexTags, &nvertexTags, &nnvertexTags,&ierr); chk(ierr);
+
+    printf("entity %i of dim %i\n", dimTags[ie*2+1], dimTags[ie*2+0]);
+    for (size_t i = 0; i < nnelementTags; ++i) {
+      printf("  %lu elements of type %i : ", nelementTags[i], types[i]);
+      size_t nnodesbyel = nvertexTags[i]/nelementTags[i];
+      for (size_t j = 0; j < nelementTags[i] && j < 3; ++j) {
+        printf("%i ( ", elementTags[i][j]);
+        for (size_t k = 0; k < nnodesbyel; ++k)
+          printf("%i ", vertexTags[i][j*nnodesbyel+k]);
+        printf(") ");
+      }
+      if (nelementTags[i] > 3)
+        printf("...");
+      printf("\n");
+    }
+
+    free(types);
+    for (size_t i = 0; i < nnelementTags; ++i)
+      free(elementTags[i]);
+    for (size_t i = 0; i < nnvertexTags; ++i)
+      free(vertexTags[i]);
+    free(nelementTags);
+    free(nvertexTags);
+  }
+  free(dimTags);
+}
+
+void genError() {
+  int ierr;
+  printf("\n** generate an error **\n");
+  gmshModelMeshGetElements(999, 999, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,&ierr); chk(ierr);
+}
+
+int main(int argc, char **argv) {
+  int ierr;
+  gmshInitialize(argc, argv);
+  genGeometry();
+  gmshModelMeshGenerate(2,&ierr); chk(ierr);
+  gmshWrite("square.msh",&ierr); chk(ierr);
+  printMesh();
+  genError();
+  gmshFinalize(&ierr); chk(ierr);
+}
diff --git a/api/test.py b/api/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..6021727d4c8aef2eb9323f93344c3bfc25bad3fd
--- /dev/null
+++ b/api/test.py
@@ -0,0 +1,51 @@
+import gmsh
+
+gmsh.initialize()
+gmsh.open("square.msh")
+
+model = gmsh.model
+
+model.add("square")
+factory = model.geo
+factory.addPoint(0,0,0,0.1,1)
+factory.addPoint(1,0,0,0.1,2)
+factory.addPoint(1,1,0,0.1,3)
+factory.addPoint(0,1,0,0.1,4)
+factory.addLine(1,2,1)
+factory.addLine(2,3,2)
+factory.addLine(3,4,3)
+line4 = factory.addLine(4,1,-1)
+print("line4 received tag ", line4)
+factory.addLineLoop([1,2,3,line4],1)
+factory.addPlaneSurface([1],6)
+factory.synchronize()
+
+ptag = model.addPhysicalGroup(1,[1,2,3,4],-1)
+ent = model.getEntitiesForPhysicalGroup(1,ptag)
+print("new physical group ",ptag,":",ent, type(ent))
+
+model.addPhysicalGroup(2,[6],-1)
+
+print(gmsh.option.getString("General.BuildOptions"))
+print(gmsh.option.getNumber("Mesh.Algorithm"))
+gmsh.option.setNumber("Mesh.Algorithm", 3.0)
+print(gmsh.option.getNumber("Mesh.Algorithm"))
+model.mesh.generate(2)
+
+gmsh.write("square.msh")
+
+print("Entities")
+entities = model.getEntities(-1)
+for e in entities :
+    print("entity ",e)
+    types,tags,vertices = model.mesh.getElements(e[0],e[1])
+    for i in range(len(types)):
+        print("type ", types[i])
+        print("tags : ", list(tags[i]))
+        print("vertices : ", list(vertices[i]))
+
+print("Vertices")
+tags, coord, _ = model.mesh.getVertices(2,6)
+print(tags)
+print(coord)
+gmsh.finalize()