Salome HOME
Fix MinDistance for node-group (SALOME_TESTS/Grids/smesh/imps_09/K0)
[modules/smesh.git] / src / SMESH_SWIG / smeshBuilder.py
index 05710d64c2853f408ab41c40654f6194f17a92d2..cf5facce8bf828eb22d885810a5953152efc049a 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+# Copyright (C) 2007-2019  CEA/DEN, EDF R&D, OPEN CASCADE
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -24,12 +24,101 @@ import salome
 from salome.geom import geomBuilder
 
 import SMESH # This is necessary for back compatibility
+import omniORB                                       # back compatibility
+SMESH.MED_V2_1    = 11 #omniORB.EnumItem("MED_V2_1", 11) # back compatibility: use number > MED minor version
+SMESH.MED_V2_2    = 12 #omniORB.EnumItem("MED_V2_2", 12) # back compatibility: latest minor will be used
+SMESH.MED_MINOR_0 = 20 # back compatibility
+SMESH.MED_MINOR_1 = 21 # back compatibility
+SMESH.MED_MINOR_2 = 22 # back compatibility
+SMESH.MED_MINOR_3 = 23 # back compatibility
+SMESH.MED_MINOR_4 = 24 # back compatibility
+SMESH.MED_MINOR_5 = 25 # back compatibility
+SMESH.MED_MINOR_6 = 26 # back compatibility
+SMESH.MED_MINOR_7 = 27 # back compatibility
+SMESH.MED_MINOR_8 = 28 # back compatibility
+SMESH.MED_MINOR_9 = 29 # back compatibility
+
 from   SMESH import *
 from   salome.smesh.smesh_algorithm import Mesh_Algorithm
 
 import SALOME
 import SALOMEDS
 import os
+import inspect
+
+# In case the omniORBpy EnumItem class does not fully support Python 3
+# (for instance in version 4.2.1-2), the comparison ordering methods must be
+# defined
+#
+try:
+    SMESH.Entity_Triangle < SMESH.Entity_Quadrangle
+except TypeError:
+    def enumitem_eq(self, other):
+        try:
+            if isinstance(other, omniORB.EnumItem):
+                if other._parent_id == self._parent_id:
+                    return self._v == other._v
+                else:
+                    return self._parent_id == other._parent_id
+            else:
+                return id(self) == id(other)
+        except:
+            return id(self) == id(other)
+
+    def enumitem_lt(self, other):
+        try:
+            if isinstance(other, omniORB.EnumItem):
+                if other._parent_id == self._parent_id:
+                    return self._v < other._v
+                else:
+                    return self._parent_id < other._parent_id
+            else:
+                return id(self) < id(other)
+        except:
+            return id(self) < id(other)
+
+    def enumitem_le(self, other):
+        try:
+            if isinstance(other, omniORB.EnumItem):
+                if other._parent_id == self._parent_id:
+                    return self._v <= other._v
+                else:
+                    return self._parent_id <= other._parent_id
+            else:
+                return id(self) <= id(other)
+        except:
+            return id(self) <= id(other)
+
+    def enumitem_gt(self, other):
+        try:
+            if isinstance(other, omniORB.EnumItem):
+                if other._parent_id == self._parent_id:
+                    return self._v > other._v
+                else:
+                    return self._parent_id > other._parent_id
+            else:
+                return id(self) > id(other)
+        except:
+            return id(self) > id(other)
+
+    def enumitem_ge(self, other):
+        try:
+            if isinstance(other, omniORB.EnumItem):
+                if other._parent_id == self._parent_id:
+                    return self._v >= other._v
+                else:
+                    return self._parent_id >= other._parent_id
+            else:
+                return id(self) >= id(other)
+        except:
+            return id(self) >= id(other)
+
+    omniORB.EnumItem.__eq__ = enumitem_eq
+    omniORB.EnumItem.__lt__ = enumitem_lt
+    omniORB.EnumItem.__le__ = enumitem_le
+    omniORB.EnumItem.__gt__ = enumitem_gt
+    omniORB.EnumItem.__ge__ = enumitem_ge
+
 
 class MeshMeta(type):
     """Private class used to workaround a problem that sometimes isinstance(m, Mesh) returns False
@@ -63,7 +152,7 @@ def ParseParameters(*args):
     Parameters = ""
     hasVariables = False
     varModifFun=None
-    if args and callable( args[-1] ):
+    if args and callable(args[-1]):
         args, varModifFun = args[:-1], args[-1]
     for parameter in args:
 
@@ -72,7 +161,7 @@ def ParseParameters(*args):
         if isinstance(parameter,str):
             # check if there is an inexistent variable name
             if not notebook.isVariable(parameter):
-                raise ValueError, "Variable with name '" + parameter + "' doesn't exist!!!"
+                raise ValueError("Variable with name '" + parameter + "' doesn't exist!!!")
             parameter = notebook.get(parameter)
             hasVariables = True
             if varModifFun:
@@ -108,8 +197,7 @@ def __initAxisStruct(ax,*args):
     Parameters are stored in AxisStruct.parameters attribute
     """
     if len( args ) != 6:
-        raise RuntimeError,\
-              "Bad nb args (%s) passed in SMESH.AxisStruct(x,y,z,dx,dy,dz)"%(len( args ))
+        raise RuntimeError("Bad nb args (%s) passed in SMESH.AxisStruct(x,y,z,dx,dy,dz)"%(len( args )))
     ax.x, ax.y, ax.z, ax.vx, ax.vy, ax.vz, ax.parameters,hasVars = ParseParameters(*args)
     pass
 SMESH.AxisStruct.__init__ = __initAxisStruct
@@ -141,13 +229,8 @@ def GetName(obj):
         except:
             ior = None
         if ior:
-            # CORBA object
-            studies = salome.myStudyManager.GetOpenStudies()
-            for sname in studies:
-                s = salome.myStudyManager.GetStudyByName(sname)
-                if not s: continue
-                sobj = s.FindObjectIOR(ior)
-                if not sobj: continue
+            sobj = salome.myStudy.FindObjectIOR(ior)
+            if sobj:
                 return sobj.GetName()
             if hasattr(obj, "GetName"):
                 # unknown CORBA object, having GetName() method
@@ -160,7 +243,7 @@ def GetName(obj):
             # unknown non-CORBA object, having GetName() method
             return obj.GetName()
         pass
-    raise RuntimeError, "Null or invalid object"
+    raise RuntimeError("Null or invalid object")
 
 def TreatHypoStatus(status, hypName, geomName, isAlgo, mesh):
     """
@@ -173,21 +256,21 @@ def TreatHypoStatus(status, hypName, geomName, isAlgo, mesh):
         pass
     reason = ""
     if hasattr( status, "__getitem__" ):
-        status,reason = status[0],status[1]
-    if status == HYP_UNKNOWN_FATAL :
+        status, reason = status[0], status[1]
+    if status == HYP_UNKNOWN_FATAL:
         reason = "for unknown reason"
-    elif status == HYP_INCOMPATIBLE :
+    elif status == HYP_INCOMPATIBLE:
         reason = "this hypothesis mismatches the algorithm"
-    elif status == HYP_NOTCONFORM :
+    elif status == HYP_NOTCONFORM:
         reason = "a non-conform mesh would be built"
-    elif status == HYP_ALREADY_EXIST :
+    elif status == HYP_ALREADY_EXIST:
         if isAlgo: return # it does not influence anything
         reason = hypType + " of the same dimension is already assigned to this shape"
-    elif status == HYP_BAD_DIM :
+    elif status == HYP_BAD_DIM:
         reason = hypType + " mismatches the shape"
     elif status == HYP_CONCURRENT :
         reason = "there are concurrent hypotheses on sub-shapes"
-    elif status == HYP_BAD_SUBSHAPE :
+    elif status == HYP_BAD_SUBSHAPE:
         reason = "the shape is neither the main one, nor its sub-shape, nor a valid group"
     elif status == HYP_BAD_GEOMETRY:
         reason = "the algorithm is not applicable to this geometry"
@@ -209,25 +292,22 @@ def TreatHypoStatus(status, hypName, geomName, isAlgo, mesh):
             if meshName and meshName != NO_NAME:
                 where = '"%s" shape in "%s" mesh ' % ( geomName, meshName )
     if status < HYP_UNKNOWN_FATAL and where:
-        print '"%s" was assigned to %s but %s' %( hypName, where, reason )
+        print('"%s" was assigned to %s but %s' %( hypName, where, reason ))
     elif where:
-        print '"%s" was not assigned to %s : %s' %( hypName, where, reason )
+        print('"%s" was not assigned to %s : %s' %( hypName, where, reason ))
     else:
-        print '"%s" was not assigned : %s' %( hypName, reason )
+        print('"%s" was not assigned : %s' %( hypName, reason ))
         pass
 
 def AssureGeomPublished(mesh, geom, name=''):
     """
     Private method. Add geom (sub-shape of the main shape) into the study if not yet there
     """
+    if not mesh.smeshpyD.IsEnablePublish():
+        return
     if not isinstance( geom, geomBuilder.GEOM._objref_GEOM_Object ):
         return
-    if not geom.GetStudyEntry() and \
-           mesh.smeshpyD.GetCurrentStudy():
-        ## set the study
-        studyID = mesh.smeshpyD.GetCurrentStudy()._get_StudyId()
-        if studyID != mesh.geompyD.myStudyId:
-            mesh.geompyD.init_geom( mesh.smeshpyD.GetCurrentStudy())
+    if not geom.GetStudyEntry():
         ## get a name
         if not name and geom.GetShapeType() != geomBuilder.GEOM.COMPOUND:
             # for all groups SubShapeName() return "Compound_-1"
@@ -245,7 +325,7 @@ def FirstVertexOnCurve(mesh, edge):
     """
     vv = mesh.geompyD.SubShapeAll( edge, geomBuilder.geomBuilder.ShapeType["VERTEX"])
     if not vv:
-        raise TypeError, "Given object has no vertices"
+        raise TypeError("Given object has no vertices")
     if len( vv ) == 1: return vv[0]
     v0   = mesh.geompyD.MakeVertexOnCurve(edge,0.)
     xyz  = mesh.geompyD.PointCoordinates( v0 ) # coords of the first vertex
@@ -269,7 +349,7 @@ engine = None
 doLcc = False
 created = False
 
-class smeshBuilder(object, SMESH._objref_SMESH_Gen):
+class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
     """
     This class allows to create, load or manipulate meshes.
     It has a set of methods to create, load or copy meshes, to combine several meshes, etc.
@@ -288,16 +368,16 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
     PrecisionConfusion = smeshPrecisionConfusion
 
     # TopAbs_State enumeration
-    [TopAbs_IN, TopAbs_OUT, TopAbs_ON, TopAbs_UNKNOWN] = range(4)
+    [TopAbs_IN, TopAbs_OUT, TopAbs_ON, TopAbs_UNKNOWN] = list(range(4))
 
     # Methods of splitting a hexahedron into tetrahedra
     Hex_5Tet, Hex_6Tet, Hex_24Tet, Hex_2Prisms, Hex_4Prisms = 1, 2, 3, 1, 2
 
-    def __new__(cls):
+    def __new__(cls, *args):
         global engine
         global smeshInst
         global doLcc
-        #print "==== __new__", engine, smeshInst, doLcc
+        #print("==== __new__", engine, smeshInst, doLcc)
 
         if smeshInst is None:
             # smesh engine is either retrieved from engine, or created
@@ -312,30 +392,31 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
                     # FindOrLoadComponent called:
                     # 1. CORBA resolution of server
                     # 2. the __new__ method is called again
-                    #print "==== smeshInst = lcc.FindOrLoadComponent ", engine, smeshInst, doLcc
+                    #print("==== smeshInst = lcc.FindOrLoadComponent ", engine, smeshInst, doLcc)
                     smeshInst = salome.lcc.FindOrLoadComponent( "FactoryServer", "SMESH" )
             else:
                 # FindOrLoadComponent not called
                 if smeshInst is None:
                     # smeshBuilder instance is created from lcc.FindOrLoadComponent
-                    #print "==== smeshInst = super(smeshBuilder,cls).__new__(cls) ", engine, smeshInst, doLcc
+                    #print("==== smeshInst = super(smeshBuilder,cls).__new__(cls) ", engine, smeshInst, doLcc)
                     smeshInst = super(smeshBuilder,cls).__new__(cls)
                 else:
                     # smesh engine not created: existing engine found
-                    #print "==== existing ", engine, smeshInst, doLcc
+                    #print("==== existing ", engine, smeshInst, doLcc)
                     pass
-            #print "====1 ", smeshInst
+            #print("====1 ", smeshInst)
             return smeshInst
 
-        #print "====2 ", smeshInst
+        #print("====2 ", smeshInst)
         return smeshInst
 
-    def __init__(self):
+    def __init__(self, *args):
         global created
-        #print "--------------- smeshbuilder __init__ ---", created
+        #print("--------------- smeshbuilder __init__ ---", created)
         if not created:
-          created = True
-          SMESH._objref_SMESH_Gen.__init__(self)
+            created = True
+            SMESH._objref_SMESH_Gen.__init__(self, *args)
+
 
     def DumpPython(self, theStudy, theIsPublished=True, theIsMultiFile=True):
         """
@@ -358,16 +439,13 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
         else:            val = "false"
         SMESH._objref_SMESH_Gen.SetOption(self, "historical_python_dump", val)
 
-    def init_smesh(self,theStudy,geompyD = None):
-        """
-        Set the current study and Geometry component
+    def init_smesh(self,geompyD = None):
         """
-
-        #print "init_smesh"
-        self.SetCurrentStudy(theStudy,geompyD)
-        if theStudy:
-            global notebook
-            notebook.myStudy = theStudy
+        Set Geometry component
+        """    
+        #print("init_smesh")
+        self.UpdateStudy(geompyD)
+        notebook.myStudy = salome.myStudy
 
     def Mesh(self, obj=0, name=0):
         """
@@ -395,7 +473,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
 
         if isinstance(obj,str):
             obj,name = name,obj
-        return Mesh(self,self.geompyD,obj,name)
+        return Mesh(self, self.geompyD, obj, name)
 
     def EnumToLong(self,theItem):
         """
@@ -422,7 +500,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
         elif isinstance(c, str):
             val = c
         else:
-            raise ValueError, "Color value should be of string or SALOMEDS.Color type"
+            raise ValueError("Color value should be of string or SALOMEDS.Color type")
         return val
 
     def GetPointStruct(self,theVertex):
@@ -452,7 +530,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
 
         vertices = self.geompyD.SubShapeAll( theVector, geomBuilder.geomBuilder.ShapeType["VERTEX"] )
         if(len(vertices) != 2):
-            print "Error: vector object is incorrect."
+            print("Error: vector object is incorrect.")
             return None
         p1 = self.geompyD.PointCoordinates(vertices[0])
         p2 = self.geompyD.PointCoordinates(vertices[1])
@@ -544,37 +622,37 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
 
         return SMESH._objref_SMESH_Gen.IsEmbeddedMode(self)
 
-    def SetCurrentStudy( self, theStudy, geompyD = None ):
+    def UpdateStudy( self, geompyD = None  ):
         """
-        Set the current study. Calling SetCurrentStudy( None ) allows to
-        switch **off** automatic pubilishing in the Study of mesh objects.
+        Update the current study. Calling UpdateStudy() allows to
+        update meshes at switching GEOM->SMESH
         """
-
+        #self.UpdateStudy()
         if not geompyD:
             from salome.geom import geomBuilder
             geompyD = geomBuilder.geom
+            if not geompyD:
+                geompyD = geomBuilder.New()
             pass
         self.geompyD=geompyD
         self.SetGeomEngine(geompyD)
-        SMESH._objref_SMESH_Gen.SetCurrentStudy(self,theStudy)
-        global notebook
-        if theStudy:
-            notebook = salome_notebook.NoteBook( theStudy )
-        else:
-            notebook = salome_notebook.NoteBook( salome_notebook.PseudoStudyForNoteBook() )
-        if theStudy:
-            sb = theStudy.NewBuilder()
-            sc = theStudy.FindComponent("SMESH")
-            if sc: sb.LoadWith(sc, self)
-            pass
+        SMESH._objref_SMESH_Gen.UpdateStudy(self)
+        sb = salome.myStudy.NewBuilder()
+        sc = salome.myStudy.FindComponent("SMESH")
+        if sc:
+            sb.LoadWith(sc, self)
         pass
-
-    def GetCurrentStudy(self):
+    
+    def SetEnablePublish( self, theIsEnablePublish ):
         """
-        Get the current study
+        Set enable publishing in the study. Calling SetEnablePublish( False ) allows to
+        switch **off** publishing in the Study of mesh objects.
         """
+       #self.SetEnablePublish(theIsEnablePublish)
+        SMESH._objref_SMESH_Gen.SetEnablePublish(self,theIsEnablePublish)
+        global notebook
+        notebook = salome_notebook.NoteBook( theIsEnablePublish )
 
-        return SMESH._objref_SMESH_Gen.GetCurrentStudy(self)
 
     def CreateMeshesFromUNV( self,theFileName ):
         """
@@ -650,15 +728,15 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
         aSmeshMesh, error = SMESH._objref_SMESH_Gen.CreateMeshesFromGMF(self,
                                                                         theFileName,
                                                                         True)
-        if error.comment: print "*** CreateMeshesFromGMF() errors:\n", error.comment
+        if error.comment: print("*** CreateMeshesFromGMF() errors:\n", error.comment)
         return Mesh(self, self.geompyD, aSmeshMesh), error
 
     def Concatenate( self, meshes, uniteIdenticalGroups,
                      mergeNodesAndElements = False, mergeTolerance = 1e-5, allGroups = False,
-                     name = ""):
+                     name = "", meshToAppendTo = None):
         """
-        Concatenate the given meshes into one mesh. All groups of input meshes will be
-        present in the new mesh.
+        Concatenate the given meshes into one mesh, optionally to meshToAppendTo.
+        All groups of input meshes will be present in the new mesh.
 
         Parameters:
                 meshes: :class:`meshes, sub-meshes, groups or filters <SMESH.SMESH_IDSource>` to combine into one mesh
@@ -667,24 +745,38 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
                 mergeTolerance: tolerance for merging nodes
                 allGroups: forces creation of groups corresponding to every input mesh
                 name: name of a new mesh
+                meshToAppendTo: a mesh to append all given meshes
 
         Returns:
                 an instance of class :class:`Mesh`
+
+        See also: 
+                :meth:`Mesh.Append`
         """
 
         if not meshes: return None
-        for i,m in enumerate(meshes):
-            if isinstance(m, Mesh):
+        if not isinstance( meshes, list ):
+            meshes = [ meshes ]
+        for i,m in enumerate( meshes ):
+            if isinstance( m, Mesh ):
                 meshes[i] = m.GetMesh()
-        mergeTolerance,Parameters,hasVars = ParseParameters(mergeTolerance)
-        meshes[0].SetParameters(Parameters)
+        mergeTolerance,Parameters,hasVars = ParseParameters( mergeTolerance )
+        if hasattr(meshes[0], "SetParameters"):
+            meshes[0].SetParameters( Parameters )
+        else:
+            meshes[0].GetMesh().SetParameters( Parameters )
+        if isinstance( meshToAppendTo, Mesh ):
+            meshToAppendTo = meshToAppendTo.GetMesh()
         if allGroups:
             aSmeshMesh = SMESH._objref_SMESH_Gen.ConcatenateWithGroups(
-                self,meshes,uniteIdenticalGroups,mergeNodesAndElements,mergeTolerance)
+                self,meshes,uniteIdenticalGroups,mergeNodesAndElements,
+                mergeTolerance,meshToAppendTo )
         else:
             aSmeshMesh = SMESH._objref_SMESH_Gen.Concatenate(
-                self,meshes,uniteIdenticalGroups,mergeNodesAndElements,mergeTolerance)
-        aMesh = Mesh(self, self.geompyD, aSmeshMesh, name=name)
+                self,meshes,uniteIdenticalGroups,mergeNodesAndElements,
+                mergeTolerance,meshToAppendTo )
+
+        aMesh = Mesh( self, self.geompyD, aSmeshMesh, name=name )
         return aMesh
 
     def CopyMesh( self, meshPart, meshName, toCopyGroups=False, toKeepIDs=False):
@@ -704,11 +796,46 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
                 an instance of class :class:`Mesh`
         """
 
-        if (isinstance( meshPart, Mesh )):
+        if isinstance( meshPart, Mesh ):
             meshPart = meshPart.GetMesh()
         mesh = SMESH._objref_SMESH_Gen.CopyMesh( self,meshPart,meshName,toCopyGroups,toKeepIDs )
         return Mesh(self, self.geompyD, mesh)
 
+    def CopyMeshWithGeom( self, sourceMesh, newGeom, meshName="", toCopyGroups=True,
+                          toReuseHypotheses=True, toCopyElements=True):
+        """
+        Create a mesh by copying a mesh definition (hypotheses and groups) to a new geometry.
+        It is supposed that the new geometry is a modified geometry of *sourceMesh*.
+        To facilitate and speed up the operation, consider using
+        "Set presentation parameters and sub-shapes from arguments" option in
+        a dialog of geometrical operation used to create the new geometry.
+
+        Parameters:
+                sourceMesh: the mesh to copy definition of.
+                newGeom: the new geomtry.
+                meshName: an optional name of the new mesh. If omitted, the mesh name is kept.
+                toCopyGroups: to create groups in the new mesh.
+                toReuseHypotheses: to reuse hypotheses of the *sourceMesh*.
+                toCopyElements: to copy mesh elements present on non-modified sub-shapes of 
+                                *sourceMesh*.
+        Returns:
+                tuple ( ok, newMesh, newGroups, newSubMeshes, newHypotheses, invalidEntries )
+                *invalidEntries* are study entries of objects whose
+                counterparts are not found in the *newGeom*, followed by entries
+                of mesh sub-objects that are invalid because they depend on a not found
+                preceeding sub-shape
+        """
+        if isinstance( sourceMesh, Mesh ):
+            sourceMesh = sourceMesh.GetMesh()
+
+        ok, newMesh, newGroups, newSubMeshes, newHypotheses, invalidEntries = \
+           SMESH._objref_SMESH_Gen.CopyMeshWithGeom( self, sourceMesh, newGeom, meshName,
+                                                     toCopyGroups,
+                                                     toReuseHypotheses,
+                                                     toCopyElements)
+        return ( ok, Mesh(self, self.geompyD, newMesh),
+                 newGroups, newSubMeshes, newHypotheses, invalidEntries )
+
     def GetSubShapesId( self, theMainObject, theListOfSubObjects ):
         """
         Return IDs of sub-shapes
@@ -797,7 +924,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
         """
 
         if not CritType in SMESH.FunctorType._items:
-            raise TypeError, "CritType should be of SMESH.FunctorType"
+            raise TypeError("CritType should be of SMESH.FunctorType")
         aCriterion               = self.GetEmptyCriterion()
         aCriterion.TypeOfElement = elementType
         aCriterion.Type          = self.EnumToLong(CritType)
@@ -832,7 +959,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
             elif isinstance( aThreshold, str ):
                 aCriterion.ThresholdStr = aThreshold
             else:
-                raise TypeError, "The Threshold should be a shape."
+                raise TypeError("The Threshold should be a shape.")
             if isinstance(UnaryOp,float):
                 aCriterion.Tolerance = UnaryOp
                 UnaryOp = FT_Undefined
@@ -841,10 +968,10 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
             # Check that Threshold is a group
             if isinstance(aThreshold, SMESH._objref_SMESH_GroupBase):
                 if aThreshold.GetType() != elementType:
-                    raise ValueError, "Group type mismatches Element type"
+                    raise ValueError("Group type mismatches Element type")
                 aCriterion.ThresholdStr = aThreshold.GetName()
                 aCriterion.ThresholdID  = salome.orb.object_to_string( aThreshold )
-                study = self.GetCurrentStudy()
+                study = salome.myStudy
                 if study:
                     so = study.FindObjectIOR( aCriterion.ThresholdID )
                     if so:
@@ -852,13 +979,13 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
                         if entry:
                             aCriterion.ThresholdID = entry
             else:
-                raise TypeError, "The Threshold should be a Mesh Group"
+                raise TypeError("The Threshold should be a Mesh Group")
         elif CritType == FT_RangeOfIds:
             # Check that Threshold is string
             if isinstance(aThreshold, str):
                 aCriterion.ThresholdStr = aThreshold
             else:
-                raise TypeError, "The Threshold should be a string."
+                raise TypeError("The Threshold should be a string.")
         elif CritType == FT_CoplanarFaces:
             # Check the Threshold
             if isinstance(aThreshold, int):
@@ -866,11 +993,10 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
             elif isinstance(aThreshold, str):
                 ID = int(aThreshold)
                 if ID < 1:
-                    raise ValueError, "Invalid ID of mesh face: '%s'"%aThreshold
+                    raise ValueError("Invalid ID of mesh face: '%s'"%aThreshold)
                 aCriterion.ThresholdID = aThreshold
             else:
-                raise TypeError,\
-                      "The Threshold should be an ID of mesh face and not '%s'"%aThreshold
+                raise TypeError("The Threshold should be an ID of mesh face and not '%s'"%aThreshold)
         elif CritType == FT_ConnectedElements:
             # Check the Threshold
             if isinstance(aThreshold, geomBuilder.GEOM._objref_GEOM_Object): # shape
@@ -884,7 +1010,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
                 aCriterion.Threshold = aThreshold
             elif isinstance(aThreshold, list): # 3 point coordinates
                 if len( aThreshold ) < 3:
-                    raise ValueError, "too few point coordinates, must be 3"
+                    raise ValueError("too few point coordinates, must be 3")
                 aCriterion.ThresholdStr = " ".join( [str(c) for c in aThreshold[:3]] )
             elif isinstance(aThreshold, str):
                 if aThreshold.isdigit():
@@ -892,9 +1018,8 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
                 else:
                     aCriterion.ThresholdStr = aThreshold # hope that it's point coordinates
             else:
-                raise TypeError,\
-                      "The Threshold should either a VERTEX, or a node ID, "\
-                      "or a list of point coordinates and not '%s'"%aThreshold
+                raise TypeError("The Threshold should either a VERTEX, or a node ID, "\
+                      "or a list of point coordinates and not '%s'"%aThreshold)
         elif CritType == FT_ElemGeomType:
             # Check the Threshold
             try:
@@ -904,7 +1029,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
                 if isinstance(aThreshold, int):
                     aCriterion.Threshold = aThreshold
                 else:
-                    raise TypeError, "The Threshold should be an integer or SMESH.GeometryType."
+                    raise TypeError("The Threshold should be an integer or SMESH.GeometryType.")
                 pass
             pass
         elif CritType == FT_EntityType:
@@ -916,7 +1041,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
                 if isinstance(aThreshold, int):
                     aCriterion.Threshold = aThreshold
                 else:
-                    raise TypeError, "The Threshold should be an integer or SMESH.EntityType."
+                    raise TypeError("The Threshold should be an integer or SMESH.EntityType.")
                 pass
             pass
 
@@ -925,7 +1050,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
             try:
                 aCriterion.ThresholdStr = self.ColorToString(aThreshold)
             except:
-                raise TypeError, "The threshold value should be of SALOMEDS.Color type"
+                raise TypeError("The threshold value should be of SALOMEDS.Color type")
             pass
         elif CritType in [FT_FreeBorders, FT_FreeEdges, FT_FreeNodes, FT_FreeFaces,
                           FT_LinearOrQuadratic, FT_BadOrientedVolume,
@@ -943,7 +1068,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
                 aThreshold = float(aThreshold)
                 aCriterion.Threshold = aThreshold
             except:
-                raise TypeError, "The Threshold should be a number."
+                raise TypeError("The Threshold should be a number.")
                 return None
 
         if Threshold ==  FT_LogicalNOT or UnaryOp ==  FT_LogicalNOT:
@@ -1068,6 +1193,8 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
             functor = aFilterMgr.CreateLength()
         elif theCriterion == FT_Length2D:
             functor = aFilterMgr.CreateLength2D()
+        elif theCriterion == FT_Length3D:
+            functor = aFilterMgr.CreateLength3D()
         elif theCriterion == FT_Deflection2D:
             functor = aFilterMgr.CreateDeflection2D()
         elif theCriterion == FT_NodeConnectivityNumber:
@@ -1075,7 +1202,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
         elif theCriterion == FT_BallDiameter:
             functor = aFilterMgr.CreateBallDiameter()
         else:
-            print "Error: given parameter is not numerical functor type."
+            print("Error: given parameter is not numerical functor type.")
         aFilterMgr.UnRegister()
         return functor
 
@@ -1108,8 +1235,6 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
     def GetMeshInfo(self, obj):
         """
         Get the mesh statistic.
-        Use :meth:`smeshBuilder.EnumToLong` to get an integer from 
-        an item of :class:`SMESH.EntityType`.
 
         Returns:
                 dictionary { :class:`SMESH.EntityType` - "count of elements" }
@@ -1317,13 +1442,16 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
 
     def GetGravityCenter(self, obj):
         """
-        Get gravity center of all nodes of the mesh object.
+        Get gravity center of all nodes of a mesh object.
         
         Parameters:            
                 obj: :class:`mesh, sub-mesh, group or filter <SMESH.SMESH_IDSource>`
 
         Returns:        
-            Three components of the gravity center (x,y,z)
+                Three components of the gravity center (x,y,z)
+
+        See also: 
+                :meth:`Mesh.BaryCenter`
         """
         if isinstance(obj, Mesh): obj = obj.mesh
         if isinstance(obj, Mesh_Algorithm): obj = obj.GetSubMesh()
@@ -1332,6 +1460,28 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
         aMeasurements.UnRegister()
         return pointStruct.x, pointStruct.y, pointStruct.z
 
+    def GetAngle(self, p1, p2, p3 ):
+        """
+        Computes a radian measure of an angle defined by 3 points: <(p1,p2,p3)
+
+        Parameters:            
+                p1,p2,p3: coordinates of 3 points defined by either SMESH.PointStruct 
+                          or list [x,y,z]
+
+        Returns:        
+            Angle in radians
+        """
+        if isinstance( p1, list ): p1 = PointStruct(*p1)
+        if isinstance( p2, list ): p2 = PointStruct(*p2)
+        if isinstance( p3, list ): p3 = PointStruct(*p3)
+
+        aMeasurements = self.CreateMeasurements()
+        angle = aMeasurements.Angle(p1,p2,p3)
+        aMeasurements.UnRegister()
+
+        return angle
+
+
     pass # end of class smeshBuilder
 
 import omniORB
@@ -1339,7 +1489,7 @@ omniORB.registerObjref(SMESH._objref_SMESH_Gen._NP_RepositoryId, smeshBuilder)
 """Registering the new proxy for SMESH.SMESH_Gen"""
 
 
-def New( study, instance=None, instanceGeom=None):
+def New( instance=None, instanceGeom=None):
     """
     Create a new smeshBuilder instance. The smeshBuilder class provides the Python
     interface to create or load meshes.
@@ -1349,10 +1499,9 @@ def New( study, instance=None, instanceGeom=None):
         import salome
         salome.salome_init()
         from salome.smesh import smeshBuilder
-        smesh = smeshBuilder.New(salome.myStudy)
+        smesh = smeshBuilder.New()
 
     Parameters:
-        study:         SALOME study, generally obtained by salome.myStudy.
         instance:      CORBA proxy of SMESH Engine. If None, the default Engine is used.
         instanceGeom:  CORBA proxy of GEOM  Engine. If None, the default Engine is used.
     Returns:
@@ -1361,33 +1510,38 @@ def New( study, instance=None, instanceGeom=None):
     global engine
     global smeshInst
     global doLcc
+    if instance and isinstance( instance, SALOMEDS._objref_Study ):
+        import sys
+        sys.stderr.write("Warning: 'study' argument is no more needed in smeshBuilder.New(). Consider updating your script!!!\n\n")
+        instance = None
     engine = instance
     if engine is None:
-      doLcc = True
+        doLcc = True
     smeshInst = smeshBuilder()
     assert isinstance(smeshInst,smeshBuilder), "Smesh engine class is %s but should be smeshBuilder.smeshBuilder. Import salome.smesh.smeshBuilder before creating the instance."%smeshInst.__class__
-    smeshInst.init_smesh(study, instanceGeom)
+    smeshInst.init_smesh(instanceGeom)
     return smeshInst
 
 
 # Public class: Mesh
 # ==================
 
-class Mesh:
+
+class Mesh(metaclass = MeshMeta):
     """
     This class allows defining and managing a mesh.
     It has a set of methods to build a mesh on the given geometry, including the definition of sub-meshes.
     It also has methods to define groups of mesh elements, to modify a mesh (by addition of
     new nodes and elements and by changing the existing entities), to get information
     about a mesh and to export a mesh in different formats.
-    """
-    __metaclass__ = MeshMeta
+    """    
 
     geom = 0
     mesh = 0
     editor = 0
 
     def __init__(self, smeshpyD, geompyD, obj=0, name=0):
+
         """
         Constructor
 
@@ -1401,8 +1555,8 @@ class Mesh:
                 name: Study name of the mesh
         """
 
-        self.smeshpyD=smeshpyD
-        self.geompyD=geompyD
+        self.smeshpyD = smeshpyD
+        self.geompyD = geompyD
         if obj is None:
             obj = 0
         objHasName = False
@@ -1411,12 +1565,9 @@ class Mesh:
                 self.geom = obj
                 objHasName = True
                 # publish geom of mesh (issue 0021122)
-                if not self.geom.GetStudyEntry() and smeshpyD.GetCurrentStudy():
+                if not self.geom.GetStudyEntry():
                     objHasName = False
-                    studyID = smeshpyD.GetCurrentStudy()._get_StudyId()
-                    if studyID != geompyD.myStudyId:
-                        geompyD.init_geom( smeshpyD.GetCurrentStudy())
-                        pass
+                    geompyD.init_geom()
                     if name:
                         geo_name = name + " shape"
                     else:
@@ -1484,6 +1635,18 @@ class Mesh:
 
         return self.mesh
 
+    def GetEngine(self):
+        """
+        Return a smeshBuilder instance created this mesh
+        """
+        return self.smeshpyD
+
+    def GetGeomEngine(self):
+        """
+        Return a geomBuilder instance
+        """
+        return self.geompyD
+
     def GetName(self):
         """
         Get the name of the mesh
@@ -1523,7 +1686,7 @@ class Mesh:
 
                    algo1D = mesh.Segment(geom=Edge_1)
 
-                creates a sub-mesh on *Edge_1* and assign Wire Discretization algorithm to it.
+                create a sub-mesh on *Edge_1* and assign Wire Discretization algorithm to it.
                 The created sub-mesh can be retrieved from the algorithm::
 
                    submesh = algo1D.GetSubMesh()
@@ -1553,6 +1716,12 @@ class Mesh:
 
         self.mesh = self.smeshpyD.CreateMesh(geom)
 
+    def HasShapeToMesh(self):
+        """
+        Return ``True`` if this mesh is based on geometry
+        """
+        return self.mesh.HasShapeToMesh()
+
     def Load(self):
         """
         Load mesh from the study after opening the study
@@ -1671,12 +1840,12 @@ class Mesh:
             if discardModifs and self.mesh.HasModificationsToDiscard(): # issue 0020693
                 self.mesh.Clear()
             ok = self.smeshpyD.Compute(self.mesh, geom)
-        except SALOME.SALOME_Exception, ex:
-            print "Mesh computation failed, exception caught:"
-            print "    ", ex.details.text
+        except SALOME.SALOME_Exception as ex:
+            print("Mesh computation failed, exception caught:")
+            print("    ", ex.details.text)
         except:
             import traceback
-            print "Mesh computation failed, exception caught:"
+            print("Mesh computation failed, exception caught:")
             traceback.print_exc()
         if True:#not ok:
             allReasons = ""
@@ -1753,15 +1922,12 @@ class Mesh:
                 else:  msg += " has not been computed"
                 if allReasons != "": msg += ":"
                 else:                msg += "."
-                print msg
-                print allReasons
+                print(msg)
+                print(allReasons)
             pass
-        if salome.sg.hasDesktop() and self.mesh.GetStudyId() >= 0:
+        if salome.sg.hasDesktop():
             if not isinstance( refresh, list): # not a call from subMesh.Compute()
-                smeshgui = salome.ImportComponentGUI("SMESH")
-                smeshgui.Init(self.mesh.GetStudyId())
-                smeshgui.SetMeshIcon( salome.ObjectToID( self.mesh ), ok, (self.NbNodes()==0) )
-                if refresh: salome.sg.updateObjBrowser(True)
+                if refresh: salome.sg.updateObjBrowser()
 
         return ok
 
@@ -1797,11 +1963,9 @@ class Mesh:
         try:
             shapeText = ""
             mainIOR  = salome.orb.object_to_string( self.GetShape() )
-            for sname in salome.myStudyManager.GetOpenStudies():
-                s = salome.myStudyManager.GetStudyByName(sname)
-                if not s: continue
-                mainSO = s.FindObjectIOR(mainIOR)
-                if not mainSO: continue
+            s = salome.myStudy
+            mainSO = s.FindObjectIOR(mainIOR)
+            if mainSO:
                 if subShapeID == 1:
                     shapeText = '"%s"' % mainSO.GetName()
                 subIt = s.NewChildIterator(mainSO)
@@ -1854,7 +2018,7 @@ class Mesh:
             pass
 
         groups = []
-        for algoName, shapes in algo2shapes.items():
+        for algoName, shapes in list(algo2shapes.items()):
             while shapes:
                 groupType = self.smeshpyD.EnumToLong( shapes[0].GetShapeType() )
                 otherTypeShapes = []
@@ -1907,12 +2071,8 @@ class Mesh:
         """
 
         self.mesh.Clear()
-        if ( salome.sg.hasDesktop() and
-             salome.myStudyManager.GetStudyByID( self.mesh.GetStudyId() ) ):
-            smeshgui = salome.ImportComponentGUI("SMESH")
-            smeshgui.Init(self.mesh.GetStudyId())
-            smeshgui.SetMeshIcon( salome.ObjectToID( self.mesh ), False, True )
-            if refresh: salome.sg.updateObjBrowser(True)
+        if ( salome.sg.hasDesktop() ):
+            if refresh: salome.sg.updateObjBrowser()
 
     def ClearSubMesh(self, geomId, refresh=False):
         """
@@ -1925,10 +2085,7 @@ class Mesh:
 
         self.mesh.ClearSubMesh(geomId)
         if salome.sg.hasDesktop():
-            smeshgui = salome.ImportComponentGUI("SMESH")
-            smeshgui.Init(self.mesh.GetStudyId())
-            smeshgui.SetMeshIcon( salome.ObjectToID( self.mesh ), False, True )
-            if refresh: salome.sg.updateObjBrowser(True)
+            if refresh: salome.sg.updateObjBrowser()
 
     def AutomaticTetrahedralization(self, fineness=0):
         """
@@ -2011,7 +2168,7 @@ class Mesh:
             AssureGeomPublished( self, geom, "shape for %s" % hyp.GetName())
             status = self.mesh.AddHypothesis(geom, hyp)
         else:
-            status = HYP_BAD_GEOMETRY,""
+            status = HYP_BAD_GEOMETRY, ""
         hyp_name = GetName( hyp )
         geom_name = ""
         if geom:
@@ -2068,7 +2225,7 @@ class Mesh:
             return self.mesh.RemoveHypothesis( shape, hyp )
         hypName = GetName( hyp )
         geoName = GetName( shape )
-        print "WARNING: RemoveHypothesis() failed as '%s' is not assigned to '%s' shape" % ( hypName, geoName )
+        print("WARNING: RemoveHypothesis() failed as '%s' is not assigned to '%s' shape" % ( hypName, geoName ))
         return None
 
     def GetHypothesisList(self, geom):
@@ -2094,22 +2251,21 @@ class Mesh:
             self.mesh.RemoveHypothesis( self.geom, hyp )
             pass
         pass
-
-    def ExportMED(self, f, auto_groups=0, version=MED_V2_2,
-                  overwrite=1, meshPart=None, autoDimension=True, fields=[], geomAssocFields=''):
+    def ExportMED(self, *args, **kwargs):
         """
         Export the mesh in a file in MED format
         allowing to overwrite the file if it exists or add the exported data to its contents
 
         Parameters:
-                f: is the file name
-                auto_groups: boolean parameter for creating/not creating
+                fileName: is the file name
+                auto_groups (boolean): parameter for creating/not creating
                         the groups Group_On_All_Nodes, Group_On_All_Faces, ... ;
                         the typical use is auto_groups=False.
-                version: MED format version (MED_V2_1 or MED_V2_2,
-                        the latter meaning any current version). The parameter is
-                        obsolete since MED_V2_1 is no longer supported.
-                overwrite: boolean parameter for overwriting/not overwriting the file
+                minor (int): define the minor version (y, where version is x.y.z) of MED file format.
+                        The minor must be between 0 and the current minor version of MED file library.
+                        If minor is equal to -1, the minor version is not changed (default).
+                        The major version (x, where version is x.y.z) cannot be changed.
+                overwrite (boolean): parameter for overwriting/not overwriting the file
                 meshPart: a part of mesh (:class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>`) to export instead of the mesh
                 autoDimension: if *True* (default), a space dimension of a MED mesh can be either
 
@@ -2120,22 +2276,53 @@ class Mesh:
                         If *autoDimension* is *False*, the space dimension is always 3.
                 fields: list of GEOM fields defined on the shape to mesh.
                 geomAssocFields: each character of this string means a need to export a 
-                        corresponding field; correspondence between fields and characters is following:
-                        - 'v' stands for "_vertices _" field;
-                        - 'e' stands for "_edges _" field;
-                        - 'f' stands for "_faces _" field;
-                        - 's' stands for "_solids _" field.
-        """
-
-        if meshPart or fields or geomAssocFields:
+                        corresponding field; correspondence between fields and characters 
+                        is following:
+
+                        - 'v' stands for "_vertices_" field;
+                        - 'e' stands for "_edges_" field;
+                        - 'f' stands for "_faces_" field;
+                        - 's' stands for "_solids_" field.
+
+                zTolerance (float): tolerance in Z direction. If Z coordinate of a node is 
+                             close to zero within a given tolerance, the coordinate is set to zero.
+                             If *ZTolerance* is negative (default), the node coordinates are kept as is.
+        """
+        # process positional arguments
+        #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]] # backward compatibility
+        fileName        = args[0]
+        auto_groups     = args[1] if len(args) > 1 else False
+        minor           = args[2] if len(args) > 2 else -1
+        overwrite       = args[3] if len(args) > 3 else True
+        meshPart        = args[4] if len(args) > 4 else None
+        autoDimension   = args[5] if len(args) > 5 else True
+        fields          = args[6] if len(args) > 6 else []
+        geomAssocFields = args[7] if len(args) > 7 else ''
+        z_tolerance     = args[8] if len(args) > 8 else -1.
+        # process keywords arguments
+        auto_groups     = kwargs.get("auto_groups", auto_groups)
+        minor           = kwargs.get("minor", minor)
+        overwrite       = kwargs.get("overwrite", overwrite)
+        meshPart        = kwargs.get("meshPart", meshPart)
+        autoDimension   = kwargs.get("autoDimension", autoDimension)
+        fields          = kwargs.get("fields", fields)
+        geomAssocFields = kwargs.get("geomAssocFields", geomAssocFields)
+        z_tolerance     = kwargs.get("zTolerance", z_tolerance)
+
+        # invoke engine's function
+        if meshPart or fields or geomAssocFields or z_tolerance > 0:
             unRegister = genObjUnRegister()
             if isinstance( meshPart, list ):
                 meshPart = self.GetIDSource( meshPart, SMESH.ALL )
                 unRegister.set( meshPart )
-            self.mesh.ExportPartToMED( meshPart, f, auto_groups, version, overwrite, autoDimension,
-                                       fields, geomAssocFields)
+
+            z_tolerance,Parameters,hasVars = ParseParameters(z_tolerance)
+            self.mesh.SetParameters(Parameters)
+
+            self.mesh.ExportPartToMED( meshPart, fileName, auto_groups, minor, overwrite, autoDimension,
+                                       fields, geomAssocFields, z_tolerance)
         else:
-            self.mesh.ExportToMEDX(f, auto_groups, version, overwrite, autoDimension)
+            self.mesh.ExportMED(fileName, auto_groups, minor, overwrite, autoDimension)
 
     def ExportSAUV(self, f, auto_groups=0):
         """
@@ -2250,18 +2437,50 @@ class Mesh:
             meshPart = self.mesh
         self.mesh.ExportGMF(meshPart, f, True)
 
-    def ExportToMED(self, f, version=MED_V2_2, opt=0, overwrite=1, autoDimension=True):
+    def ExportToMED(self, *args, **kwargs):
         """
         Deprecated, used only for compatibility! Please, use :meth:`ExportMED` method instead.
         Export the mesh in a file in MED format
         allowing to overwrite the file if it exists or add the exported data to its contents
 
         Parameters:
-                f: the file name
-                version: MED format version (MED_V2_1 or MED_V2_2,
-                        the latter meaning any current version). The parameter is
-                        obsolete since MED_V2_1 is no longer supported.
-                opt: boolean parameter for creating/not creating
+                fileName: the file name
+                opt (boolean): parameter for creating/not creating
+                        the groups Group_On_All_Nodes, Group_On_All_Faces, ...
+                overwrite: boolean parameter for overwriting/not overwriting the file
+                autoDimension: if *True* (default), a space dimension of a MED mesh can be either
+
+                        - 1D if all mesh nodes lie on OX coordinate axis, or
+                        - 2D if all mesh nodes lie on XOY coordinate plane, or
+                        - 3D in the rest cases.
+
+                        If **autoDimension** is *False*, the space dimension is always 3.
+        """
+    
+        print("WARNING: ExportToMED() is deprecated, use ExportMED() instead")
+        # process positional arguments
+        #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]] # backward compatibility
+        fileName      = args[0]
+        auto_groups   = args[1] if len(args) > 1 else False
+        overwrite     = args[2] if len(args) > 2 else True
+        autoDimension = args[3] if len(args) > 3 else True
+        # process keywords arguments
+        auto_groups   = kwargs.get("opt", auto_groups)         # old keyword name
+        auto_groups   = kwargs.get("auto_groups", auto_groups) # new keyword name
+        overwrite     = kwargs.get("overwrite", overwrite)
+        autoDimension = kwargs.get("autoDimension", autoDimension)
+        minor = -1
+        # invoke engine's function
+        self.mesh.ExportMED(fileName, auto_groups, minor, overwrite, autoDimension)
+
+    def ExportToMEDX(self, *args, **kwargs):
+        """
+        Deprecated, used only for compatibility! Please, use ExportMED() method instead.
+        Export the mesh in a file in MED format
+
+        Parameters:
+                fileName: the file name
+                opt (boolean): parameter for creating/not creating
                         the groups Group_On_All_Nodes, Group_On_All_Faces, ...
                 overwrite: boolean parameter for overwriting/not overwriting the file
                 autoDimension: if *True* (default), a space dimension of a MED mesh can be either
@@ -2271,16 +2490,47 @@ class Mesh:
                         - 3D in the rest cases.
 
                         If **autoDimension** is *False*, the space dimension is always 3.
+                """
+
+        print("WARNING: ExportToMEDX() is deprecated, use ExportMED() instead")
+        # process positional arguments
+        #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]] # backward compatibility
+        fileName      = args[0]
+        auto_groups   = args[1] if len(args) > 1 else False
+        overwrite     = args[2] if len(args) > 2 else True
+        autoDimension = args[3] if len(args) > 3 else True
+        # process keywords arguments
+        auto_groups   = kwargs.get("auto_groups", auto_groups)
+        overwrite     = kwargs.get("overwrite", overwrite)
+        autoDimension = kwargs.get("autoDimension", autoDimension)
+        minor = -1
+        # invoke engine's function
+        self.mesh.ExportMED(fileName, auto_groups, minor, overwrite, autoDimension)
+        return
+
+
+    def Append(self, meshes, uniteIdenticalGroups = True,
+                     mergeNodesAndElements = False, mergeTolerance = 1e-5, allGroups = False):
         """
+        Append given meshes into this mesh.
+        All groups of input meshes will be created in this mesh.
 
-        self.mesh.ExportToMEDX(f, opt, version, overwrite, autoDimension)
+        Parameters:
+                meshes: :class:`meshes, sub-meshes, groups or filters <SMESH.SMESH_IDSource>` to append
+                uniteIdenticalGroups: if True, groups with same names are united, else they are renamed
+                mergeNodesAndElements: if True, equal nodes and elements are merged
+                mergeTolerance: tolerance for merging nodes
+                allGroups: forces creation of groups corresponding to every input mesh
+        """
+        self.smeshpyD.Concatenate( meshes, uniteIdenticalGroups,
+                                   mergeNodesAndElements, mergeTolerance, allGroups,
+                                   meshToAppendTo = self.GetMesh() )
 
     # Operations with groups:
     # ----------------------
-
     def CreateEmptyGroup(self, elementType, name):
         """
-        Create an empty mesh group
+        Create an empty standalone mesh group
 
         Parameters:
                 elementType: the :class:`type <SMESH.ElementType>` of elements in the group; 
@@ -2315,7 +2565,7 @@ class Mesh:
     def GroupOnGeom(self, grp, name="", typ=None):
         """
         Create a mesh group based on the geometrical object *grp*
-        and gives a *name*.
+        and give it a *name*.
         if *name* is not defined the name of the geometric group is used
 
         Parameters:
@@ -2352,17 +2602,16 @@ class Mesh:
         elif tgeo == "COMPOUND":
             sub = self.geompyD.SubShapeAll( shape, self.geompyD.ShapeType["SHAPE"])
             if not sub:
-                raise ValueError,"_groupTypeFromShape(): empty geometric group or compound '%s'" % GetName(shape)
+                raise ValueError("_groupTypeFromShape(): empty geometric group or compound '%s'" % GetName(shape))
             return self._groupTypeFromShape( sub[0] )
         else:
-            raise ValueError, \
-                  "_groupTypeFromShape(): invalid geometry '%s'" % GetName(shape)
+            raise ValueError("_groupTypeFromShape(): invalid geometry '%s'" % GetName(shape))
         return typ
 
     def GroupOnFilter(self, typ, name, filter):
         """
-        Create a mesh group with given *name* based on the *filter* which
-        is a special type of group dynamically updating it's contents during
+        Create a mesh group with given *name* based on the *filter*.
+        It is a special type of group dynamically updating it's contents during
         mesh modification
 
         Parameters:
@@ -2512,15 +2761,15 @@ class Mesh:
 
     def GetGroups(self, elemType = SMESH.ALL):
         """
-        Get the list of groups existing in the mesh in the order
-        of creation (starting from the oldest one)
+        Get the list of groups existing in the mesh in the order of creation 
+        (starting from the oldest one)
 
         Parameters:
                 elemType (SMESH.ElementType): type of elements the groups contain;
                         by default groups of elements of all types are returned
 
         Returns:
-                a sequence of :class:`SMESH.SMESH_GroupBase`
+                a list of :class:`SMESH.SMESH_GroupBase`
         """
 
         groups = self.mesh.GetGroups()
@@ -2610,7 +2859,6 @@ class Mesh:
         Returns:
                 instance of :class:`SMESH.SMESH_Group`
         """
-
         return self.mesh.UnionListOfGroups(groups, name)
 
     def IntersectGroups(self, group1, group2, name):
@@ -2641,7 +2889,6 @@ class Mesh:
         Returns:
                 instance of :class:`SMESH.SMESH_Group`
         """
-
         return self.mesh.IntersectListOfGroups(groups, name)
 
     def CutGroups(self, main_group, tool_group, name):
@@ -2682,7 +2929,7 @@ class Mesh:
         Create a standalone group of entities basing on nodes of other groups.
 
         Parameters:
-                groups: list of reference :class:`sub-meshes, groups or filters <SMESH.SMESH_IDSource>`, of any type.
+                groups: list of :class:`sub-meshes, groups or filters <SMESH.SMESH_IDSource>`, of any type.
                 elemType: a type of elements to include to the new group; either of
                         (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME).
                 name: a name of the new group.
@@ -2708,6 +2955,22 @@ class Mesh:
             groups = [groups]
         return self.mesh.CreateDimGroup(groups, elemType, name, nbCommonNodes, underlyingOnly)
 
+    def FaceGroupsSeparatedByEdges( self, sharpAngle, createEdges=False, useExistingEdges=False ):
+        """
+        Distribute all faces of the mesh among groups using sharp edges and optionally
+        existing 1D elements as group boundaries.
+
+        Parameters:
+                sharpAngle: edge is considered sharp if an angle between normals of
+                            adjacent faces is more than \a sharpAngle in degrees.
+                createEdges (boolean): to create 1D elements for detected sharp edges.
+                useExistingEdges (boolean): to use existing edges as group boundaries
+        Returns:
+                ListOfGroups - the created :class:`groups <SMESH.SMESH_Group>`
+        """
+        sharpAngle,Parameters,hasVars = ParseParameters( sharpAngle )
+        self.mesh.SetParameters(Parameters)
+        return self.mesh.FaceGroupsSeparatedByEdges( sharpAngle, createEdges, useExistingEdges );
 
     def ConvertToStandalone(self, group):
         """
@@ -2772,16 +3035,6 @@ class Mesh:
 
         return self.mesh.GetId()
 
-    def GetStudyId(self):
-        """
-        Get the study Id
-
-        Returns:
-            integer value, which is the study Id of the mesh
-        """
-
-        return self.mesh.GetStudyId()
-
     def HasDuplicatedGroupNamesMED(self):
         """
         Check the group names for duplications.
@@ -2836,8 +3089,6 @@ class Mesh:
     def GetMeshInfo(self, obj = None):
         """
         Get the mesh statistic.
-        Use :meth:`smeshBuilder.EnumToLong` to get an integer from 
-        an item of :class:`SMESH.EntityType`.
 
         Returns:
                 dictionary { :class:`SMESH.EntityType` - "count of elements" }
@@ -3327,16 +3578,20 @@ class Mesh:
 
         return self.mesh.GetNodeXYZ(id)
 
-    def GetNodeInverseElements(self, id):
+    def GetNodeInverseElements(self, id, elemType=SMESH.ALL):
         """
         Return list of IDs of inverse elements for the given node.
         If there is no node for the given ID - return an empty list
 
+        Parameters:
+                id: node ID
+                elementType: :class:`type of elements <SMESH.ElementType>` (SMESH.EDGE, SMESH.FACE, SMESH.VOLUME, etc.)
+
         Returns:
             list of integer values
         """
 
-        return self.mesh.GetNodeInverseElements(id)
+        return self.mesh.GetNodeInverseElements(id,elemType)
 
     def GetNodePosition(self,NodeID):
         """
@@ -3510,26 +3765,40 @@ class Mesh:
 
         Returns:
             a list of three double values
+
+        See also: 
+                :meth:`smeshBuilder.GetGravityCenter`
         """
 
         return self.mesh.BaryCenter(id)
 
-    def GetIdsFromFilter(self, theFilter):
+    def GetIdsFromFilter(self, filter, meshParts=[] ):
         """
         Pass mesh elements through the given filter and return IDs of fitting elements
 
         Parameters:
-                theFilter: :class:`SMESH.Filter`
+                filter: :class:`SMESH.Filter`
+                meshParts: list of mesh parts (:class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>`) to filter
 
         Returns:
             a list of ids
 
         See Also:
             :meth:`SMESH.Filter.GetIDs`
+            :meth:`SMESH.Filter.GetElementsIdFromParts`
         """
 
-        theFilter.SetMesh( self.mesh )
-        return theFilter.GetIDs()
+        filter.SetMesh( self.mesh )
+
+        if meshParts:
+            if isinstance( meshParts, Mesh ):
+                filter.SetMesh( meshParts.GetMesh() )
+                return theFilter.GetIDs()
+            if isinstance( meshParts, SMESH._objref_SMESH_IDSource ):
+                meshParts = [ meshParts ]
+            return filter.GetElementsIdFromParts( meshParts )
+
+        return filter.GetIDs()
 
     # Get mesh measurements information:
     # ------------------------------------
@@ -3561,7 +3830,9 @@ class Mesh:
                 isElem2: *True* if *id2* is element id, *False* if it is node id
 
         Returns:
-            minimum distance value **GetMinDistance()**
+            minimum distance value
+        See Also:
+            :meth:`GetMinDistance`
         """
 
         aMeasure = self.GetMinDistance(id1, id2, isElem1, isElem2)
@@ -3886,7 +4157,7 @@ class Mesh:
 
     def SetNodeOnVertex(self, NodeID, Vertex):
         """
-        Binds a node to a vertex
+        Bind a node to a vertex
 
         Parameters:
                 NodeID: a node ID
@@ -3902,14 +4173,14 @@ class Mesh:
             VertexID = Vertex
         try:
             self.editor.SetNodeOnVertex(NodeID, VertexID)
-        except SALOME.SALOME_Exception, inst:
-            raise ValueError, inst.details.text
+        except SALOME.SALOME_Exception as inst:
+            raise ValueError(inst.details.text)
         return True
 
 
     def SetNodeOnEdge(self, NodeID, Edge, paramOnEdge):
         """
-        Stores the node position on an edge
+        Store the node position on an edge
 
         Parameters:
                 NodeID: a node ID
@@ -3926,13 +4197,13 @@ class Mesh:
             EdgeID = Edge
         try:
             self.editor.SetNodeOnEdge(NodeID, EdgeID, paramOnEdge)
-        except SALOME.SALOME_Exception, inst:
-            raise ValueError, inst.details.text
+        except SALOME.SALOME_Exception as inst:
+            raise ValueError(inst.details.text)
         return True
 
     def SetNodeOnFace(self, NodeID, Face, u, v):
         """
-        Stores node position on a face
+        Store node position on a face
 
         Parameters:
                 NodeID: a node ID
@@ -3950,13 +4221,13 @@ class Mesh:
             FaceID = Face
         try:
             self.editor.SetNodeOnFace(NodeID, FaceID, u, v)
-        except SALOME.SALOME_Exception, inst:
-            raise ValueError, inst.details.text
+        except SALOME.SALOME_Exception as inst:
+            raise ValueError(inst.details.text)
         return True
 
     def SetNodeInVolume(self, NodeID, Solid):
         """
-        Binds a node to a solid
+        Bind a node to a solid
 
         Parameters:
                 NodeID: a node ID
@@ -3972,8 +4243,8 @@ class Mesh:
             SolidID = Solid
         try:
             self.editor.SetNodeInVolume(NodeID, SolidID)
-        except SALOME.SALOME_Exception, inst:
-            raise ValueError, inst.details.text
+        except SALOME.SALOME_Exception as inst:
+            raise ValueError(inst.details.text)
         return True
 
     def SetMeshElementOnShape(self, ElementID, Shape):
@@ -3994,8 +4265,8 @@ class Mesh:
             ShapeID = Shape
         try:
             self.editor.SetMeshElementOnShape(ElementID, ShapeID)
-        except SALOME.SALOME_Exception, inst:
-            raise ValueError, inst.details.text
+        except SALOME.SALOME_Exception as inst:
+            raise ValueError(inst.details.text)
         return True
 
 
@@ -4049,8 +4320,6 @@ class Mesh:
             the ID of a node
         """
 
-        #preview = self.mesh.GetMeshEditPreviewer()
-        #return preview.MoveClosestNodeToPoint(x, y, z, -1)
         return self.editor.FindNodeClosestTo(x, y, z)
 
     def FindElementsByPoint(self, x, y, z, elementType = SMESH.ALL, meshPart=None):
@@ -4066,16 +4335,28 @@ class Mesh:
         Returns:
             list of IDs of found elements
         """
-
         if meshPart:
             return self.editor.FindAmongElementsByPoint( meshPart, x, y, z, elementType );
         else:
             return self.editor.FindElementsByPoint(x, y, z, elementType)
 
+    def ProjectPoint(self, x,y,z, elementType, meshObject=None):
+        """
+        Project a point to a mesh object.
+        Return ID of an element of given type where the given point is projected
+        and coordinates of the projection point.
+        In the case if nothing found, return -1 and []
+        """
+        if isinstance( meshObject, Mesh ):
+            meshObject = meshObject.GetMesh()
+        if not meshObject:
+            meshObject = self.GetMesh()
+        return self.editor.ProjectPoint( x,y,z, elementType, meshObject )
+
     def GetPointState(self, x, y, z):
         """
         Return point state in a closed 2D mesh in terms of TopAbs_State enumeration:
-        0-IN, 1-OUT, 2-ON, 3-UNKNOWN.
+        smesh.TopAbs_IN, smesh.TopAbs_OUT, smesh.TopAbs_ON and smesh.TopAbs_UNKNOWN.
         UNKNOWN state means that either mesh is wrong or the analysis fails.
         """
 
@@ -4095,6 +4376,41 @@ class Mesh:
 
         return self.editor.IsCoherentOrientation2D()
 
+    def Get1DBranches( self, edges, startNode = 0 ):
+        """
+        Partition given 1D elements into groups of contiguous edges.
+        A node where number of meeting edges != 2 is a group end.
+        An optional startNode is used to orient groups it belongs to.
+
+        Returns:
+             A list of edge groups and a list of corresponding node groups,
+             where the group is a list of IDs of edges or elements, like follows
+             [[[branch_edges_1],[branch_edges_2]], [[branch_nodes_1],[branch_nodes_2]]].
+             If a group is closed, the first and last nodes of the group are same.
+        """
+        if isinstance( edges, Mesh ):
+            edges = edges.GetMesh()
+        unRegister = genObjUnRegister()
+        if isinstance( edges, list ):
+            edges = self.GetIDSource( edges, SMESH.EDGE )
+            unRegister.set( edges )
+        return self.editor.Get1DBranches( edges, startNode )
+    
+    def FindSharpEdges( self, angle, addExisting=False ):
+        """
+        Return sharp edges of faces and non-manifold ones.
+        Optionally add existing edges.
+
+        Parameters:
+                angle: angle (in degrees) between normals of adjacent faces to detect sharp edges
+                addExisting: to return existing edges (1D elements) as well
+
+        Returns:
+            list of FaceEdge structures
+        """
+        angle = ParseParameters( angle )[0]
+        return self.editor.FindSharpEdges( angle, addExisting )
+
     def MeshToPassThroughAPoint(self, x, y, z):
         """
         Find the node closest to a point and moves it to a point location
@@ -4369,7 +4685,7 @@ class Mesh:
 
         Parameters:
                 IDsOfElements: the faces to be splitted
-                Diag13:        is used to choose a diagonal for splitting.
+                Diag13 (boolean):        is used to choose a diagonal for splitting.
 
         Returns:
             True in case of success, False otherwise.
@@ -4385,7 +4701,7 @@ class Mesh:
         Parameters:
                 theObject: the object from which the list of elements is taken,
                         this is :class:`mesh, sub-mesh, group or filter <SMESH.SMESH_IDSource>`
-                Diag13:    is used to choose a diagonal for splitting.
+                Diag13 (boolean):    is used to choose a diagonal for splitting.
 
         Returns:
             True in case of success, False otherwise.
@@ -4585,12 +4901,12 @@ class Mesh:
         pattern = self.smeshpyD.GetPattern()
         isDone  = pattern.LoadFromFile(pattern_tetra)
         if not isDone:
-            print 'Pattern.LoadFromFile :', pattern.GetErrorCode()
+            print('Pattern.LoadFromFile :', pattern.GetErrorCode())
             return isDone
 
         pattern.ApplyToHexahedrons(self.mesh, theObject.GetIDs(), theNode000, theNode001)
         isDone = pattern.MakeMesh(self.mesh, False, False)
-        if not isDone: print 'Pattern.MakeMesh :', pattern.GetErrorCode()
+        if not isDone: print('Pattern.MakeMesh :', pattern.GetErrorCode())
 
         # split quafrangle faces near triangular facets of volumes
         self.SplitQuadsNearTriangularFacets()
@@ -4644,12 +4960,12 @@ class Mesh:
         pattern = self.smeshpyD.GetPattern()
         isDone  = pattern.LoadFromFile(pattern_prism)
         if not isDone:
-            print 'Pattern.LoadFromFile :', pattern.GetErrorCode()
+            print('Pattern.LoadFromFile :', pattern.GetErrorCode())
             return isDone
 
         pattern.ApplyToHexahedrons(self.mesh, theObject.GetIDs(), theNode000, theNode001)
         isDone = pattern.MakeMesh(self.mesh, False, False)
-        if not isDone: print 'Pattern.MakeMesh :', pattern.GetErrorCode()
+        if not isDone: print('Pattern.MakeMesh :', pattern.GetErrorCode())
 
         # Split quafrangle faces near triangular facets of volumes
         self.SplitQuadsNearTriangularFacets()
@@ -4783,7 +5099,7 @@ class Mesh:
                 self.editor.ConvertToQuadratic(theForce3d)
         error = self.editor.GetLastError()
         if error and error.comment:
-            print error.comment
+            print(error.comment)
         return error
 
     def ConvertFromQuadratic(self, theSubMesh=None):
@@ -4870,7 +5186,7 @@ class Mesh:
                 groups: list of :class:`sub-meshes, groups or filters <SMESH.SMESH_IDSource>` of elements to make boundary around
 
         Returns:
-                tuple( long, mesh, groups )
+                tuple( long, mesh, group )
                        - long - number of added boundary elements
                        - mesh - the :class:`Mesh` where elements were added to
                        - group - the :class:`group <SMESH.SMESH_Group>` of boundary elements or None
@@ -5047,7 +5363,8 @@ class Mesh:
                                          NbOfSteps, Tolerance, MakeGroups, TotalAngle)
 
     def ExtrusionSweepObjects(self, nodes, edges, faces, StepVector, NbOfSteps, MakeGroups=False,
-                              scaleFactors=[], linearVariation=False, basePoint=[] ):
+                              scaleFactors=[], linearVariation=False, basePoint=[],
+                              angles=[], anglesVariation=False):
         """
         Generate new elements by extrusion of the given elements and nodes
 
@@ -5061,15 +5378,19 @@ class Mesh:
             NbOfSteps: the number of steps
             MakeGroups: forces the generation of new groups from existing ones
             scaleFactors: optional scale factors to apply during extrusion
-            linearVariation: if *True*, scaleFactors are spread over all *scaleFactors*,
-                else scaleFactors[i] is applied to nodes at the i-th extrusion step
-            basePoint: optional scaling center; if not provided, a gravity center of
+            linearVariation: if *True*, *scaleFactors* are spread over all *NbOfSteps*,
+                else *scaleFactors* [i] is applied to nodes at the i-th extrusion step
+            basePoint: optional scaling and rotation center; if not provided, a gravity center of
                 nodes and elements being extruded is used as the scaling center.
                 It can be either
 
                         - a list of tree components of the point or
                         - a node ID or
                         - a GEOM point
+            angles: list of angles in radians. Nodes at each extrusion step are rotated 
+                around *basePoint*, additionally to previous steps.
+            anglesVariation: forces the computation of rotation angles as linear
+                variation of the given *angles* along path steps
         Returns:
             the list of created :class:`groups <SMESH.SMESH_GroupBase>` if *MakeGroups* == True, empty list otherwise
 
@@ -5088,19 +5409,23 @@ class Mesh:
         if isinstance( basePoint, int):
             xyz = self.GetNodeXYZ( basePoint )
             if not xyz:
-                raise RuntimeError, "Invalid node ID: %s" % basePoint
+                raise RuntimeError("Invalid node ID: %s" % basePoint)
             basePoint = xyz
         if isinstance( basePoint, geomBuilder.GEOM._objref_GEOM_Object ):
             basePoint = self.geompyD.PointCoordinates( basePoint )
 
         NbOfSteps,Parameters,hasVars = ParseParameters(NbOfSteps)
-        Parameters = StepVector.PS.parameters + var_separator + Parameters
+        scaleFactors,scaleParameters,hasVars = ParseParameters(scaleFactors)
+        angles,angleParameters,hasVars = ParseAngles(angles)
+        Parameters = StepVector.PS.parameters + var_separator + \
+                     Parameters + var_separator + \
+                     scaleParameters + var_separator + angleParameters
         self.mesh.SetParameters(Parameters)
 
         return self.editor.ExtrusionSweepObjects( nodes, edges, faces,
-                                                  StepVector, NbOfSteps,
+                                                  StepVector, NbOfSteps, MakeGroups,
                                                   scaleFactors, linearVariation, basePoint,
-                                                  MakeGroups)
+                                                  angles, anglesVariation )
 
 
     def ExtrusionSweep(self, IDsOfElements, StepVector, NbOfSteps, MakeGroups=False, IsNodes = False):
@@ -5160,7 +5485,7 @@ class Mesh:
             Elements = [ Elements.GetMesh() ]
         if isinstance( Elements, list ):
             if not Elements:
-                raise RuntimeError, "Elements empty!"
+                raise RuntimeError("Elements empty!")
             if isinstance( Elements[0], int ):
                 Elements = self.GetIDSource( Elements, SMESH.ALL )
                 unRegister.set( Elements )
@@ -5262,9 +5587,10 @@ class Mesh:
         return self.editor.AdvancedExtrusion(IDsOfElements, StepVector, NbOfSteps,
                                              ExtrFlags, SewTolerance, MakeGroups)
 
-    def ExtrusionAlongPathObjects(self, Nodes, Edges, Faces, PathMesh, PathShape=None,
+    def ExtrusionAlongPathObjects(self, Nodes, Edges, Faces, PathObject, PathShape=None,
                                   NodeStart=1, HasAngles=False, Angles=[], LinearVariation=False,
-                                  HasRefPoint=False, RefPoint=[0,0,0], MakeGroups=False):
+                                  HasRefPoint=False, RefPoint=[0,0,0], MakeGroups=False,
+                                  ScaleFactors=[], ScalesVariation=False):
         """
         Generate new elements by extrusion of the given elements and nodes along the path.
         The path of extrusion must be a meshed edge.
@@ -5273,20 +5599,22 @@ class Mesh:
             Nodes: nodes to extrude: a list including ids, :class:`a mesh, sub-meshes, groups or filters <SMESH.SMESH_IDSource>`
             Edges: edges to extrude: a list including ids, :class:`a mesh, sub-meshes, groups or filters <SMESH.SMESH_IDSource>`
             Faces: faces to extrude: a list including ids, :class:`a mesh, sub-meshes, groups or filters <SMESH.SMESH_IDSource>`
-            PathMesh: 1D mesh or 1D sub-mesh, along which proceeds the extrusion
-            PathShape: shape (edge) defines the sub-mesh of PathMesh if PathMesh
-                contains not only path segments, else it can be None
+            PathObject: :class:`mesh, sub-mesh, group or filter <SMESH.SMESH_IDSource>` containing edges along which proceeds the extrusion
+            PathShape: optional shape (edge or wire) which defines the sub-mesh of the mesh defined by *PathObject* if the mesh contains not only path segments, else it can be None
             NodeStart: the first or the last node on the path. Defines the direction of extrusion
-            HasAngles: allows the shape to be rotated around the path
-                to get the resulting mesh in a helical fashion
-            Angles: list of angles
+            HasAngles: not used obsolete
+            Angles: list of angles in radians. Nodes at each extrusion step are rotated 
+                around *basePoint*, additionally to previous steps.
             LinearVariation: forces the computation of rotation angles as linear
                 variation of the given Angles along path steps
             HasRefPoint: allows using the reference point
-            RefPoint: the reference point around which the shape is rotated (the mass center of the
-                shape by default). The User can specify any point as the Reference Point. 
+            RefPoint: optional scaling and rotation center (mass center of the extruded
+                elements by default). The User can specify any point as the Reference Point. 
                 *RefPoint* can be either GEOM Vertex, [x,y,z] or :class:`SMESH.PointStruct`
             MakeGroups: forces the generation of new groups from existing ones
+            ScaleFactors: optional scale factors to apply during extrusion
+            ScalesVariation: if *True*, *scaleFactors* are spread over all *NbOfSteps*,
+                else *scaleFactors* [i] is applied to nodes at the i-th extrusion step
 
         Returns:
             list of created :class:`groups <SMESH.SMESH_GroupBase>` and 
@@ -5304,15 +5632,18 @@ class Mesh:
         if isinstance( RefPoint, list ):
             if not RefPoint: RefPoint = [0,0,0]
             RefPoint = SMESH.PointStruct( *RefPoint )
-        if isinstance( PathMesh, Mesh ):
-            PathMesh = PathMesh.GetMesh()
+        if isinstance( PathObject, Mesh ):
+            PathObject = PathObject.GetMesh()
         Angles,AnglesParameters,hasVars = ParseAngles(Angles)
-        Parameters = AnglesParameters + var_separator + RefPoint.parameters
+        ScaleFactors,ScalesParameters,hasVars = ParseParameters(ScaleFactors)
+        Parameters = AnglesParameters + var_separator + \
+                     RefPoint.parameters + var_separator + ScalesParameters 
         self.mesh.SetParameters(Parameters)
         return self.editor.ExtrusionAlongPathObjects(Nodes, Edges, Faces,
-                                                     PathMesh, PathShape, NodeStart,
+                                                     PathObject, PathShape, NodeStart,
                                                      HasAngles, Angles, LinearVariation,
-                                                     HasRefPoint, RefPoint, MakeGroups)
+                                                     HasRefPoint, RefPoint, MakeGroups,
+                                                     ScaleFactors, ScalesVariation)
 
     def ExtrusionAlongPathX(self, Base, Path, NodeStart,
                             HasAngles=False, Angles=[], LinearVariation=False,
@@ -5326,9 +5657,9 @@ class Mesh:
             Base: :class:`mesh, sub-mesh, group, filter <SMESH.SMESH_IDSource>`, or list of ids of elements for extrusion
             Path: 1D mesh or 1D sub-mesh, along which proceeds the extrusion
             NodeStart: the start node from Path. Defines the direction of extrusion
-            HasAngles: allows the shape to be rotated around the path
-                to get the resulting mesh in a helical fashion
-            Angles: list of angles in radians
+            HasAngles: not used obsolete
+            Angles: list of angles in radians. Nodes at each extrusion step are rotated 
+                around *basePoint*, additionally to previous steps.
             LinearVariation: forces the computation of rotation angles as linear
                 variation of the given Angles along path steps
             HasRefPoint: allows using the reference point
@@ -5369,9 +5700,9 @@ class Mesh:
             PathMesh: mesh containing a 1D sub-mesh on the edge, along which proceeds the extrusion
             PathShape: shape (edge) defines the sub-mesh for the path
             NodeStart: the first or the last node on the edge. Defines the direction of extrusion
-            HasAngles: allows the shape to be rotated around the path
-                to get the resulting mesh in a helical fashion
-            Angles: list of angles in radians
+            HasAngles: not used obsolete
+            Angles: list of angles in radians. Nodes at each extrusion step are rotated 
+                around *basePoint*, additionally to previous steps.
             HasRefPoint: allows using the reference point
             RefPoint: the reference point around which the shape is rotated (the mass center of the shape by default).
                 The User can specify any point as the Reference Point.
@@ -5387,6 +5718,8 @@ class Mesh:
         Example: :ref:`tui_extrusion_along_path`
         """
 
+        if not IDsOfElements:
+            IDsOfElements = [ self.GetMesh() ]
         n,e,f = [],IDsOfElements,IDsOfElements
         gr,er = self.ExtrusionAlongPathObjects(n,e,f, PathMesh, PathShape,
                                                NodeStart, HasAngles, Angles,
@@ -5408,9 +5741,9 @@ class Mesh:
             PathMesh: mesh containing a 1D sub-mesh on the edge, along which the extrusion proceeds
             PathShape: shape (edge) defines the sub-mesh for the path
             NodeStart: the first or the last node on the edge. Defines the direction of extrusion
-            HasAngles: allows the shape to be rotated around the path
-                to get the resulting mesh in a helical fashion
-            Angles: list of angles
+            HasAngles: not used obsolete
+            Angles: list of angles in radians. Nodes at each extrusion step are rotated 
+                around *basePoint*, additionally to previous steps.
             HasRefPoint: allows using the reference point
             RefPoint: the reference point around which the shape is rotated (the mass center of the shape by default).
                 The User can specify any point as the Reference Point.
@@ -5446,9 +5779,9 @@ class Mesh:
             PathMesh: mesh containing a 1D sub-mesh on the edge, along which the extrusion proceeds
             PathShape: shape (edge) defines the sub-mesh for the path
             NodeStart: the first or the last node on the edge. Defines the direction of extrusion
-            HasAngles: allows the shape to be rotated around the path
-                to get the resulting mesh in a helical fashion
-            Angles: list of angles
+            HasAngles: not used obsolete
+            Angles: list of angles in radians. Nodes at each extrusion step are rotated 
+                around *basePoint*, additionally to previous steps.
             HasRefPoint: allows using the reference point
             RefPoint:  the reference point around which the shape is rotated (the mass center of the shape by default).
                 The User can specify any point as the Reference Point.
@@ -5484,9 +5817,9 @@ class Mesh:
             PathMesh: mesh containing a 1D sub-mesh on the edge, along which the extrusion proceeds
             PathShape: shape (edge) defines the sub-mesh for the path
             NodeStart: the first or the last node on the edge. Defines the direction of extrusion
-            HasAngles: allows the shape to be rotated around the path
-                to get the resulting mesh in a helical fashion
-            Angles: list of angles
+            HasAngles: not used obsolete
+            Angles: list of angles in radians. Nodes at each extrusion step are rotated 
+                around *basePoint*, additionally to previous steps.
             HasRefPoint: allows using the reference point
             RefPoint: the reference point around which the shape is rotated (the mass center of the shape by default).
                 The User can specify any point as the Reference Point.
@@ -5516,7 +5849,7 @@ class Mesh:
         Parameters:
             IDsOfElements: list of elements ids
             Mirror: is :class:`SMESH.AxisStruct` or geom object (point, line, plane)
-            theMirrorType: smeshBuilder.POINT, smeshBuilder.AXIS or smeshBuilder.PLANE.
+            theMirrorType: smesh.POINT, smesh.AXIS or smesh.PLANE.
                 If the *Mirror* is a geom object this parameter is unnecessary
             Copy: allows to copy element (Copy is 1) or to replace with its mirroring (Copy is 0)
             MakeGroups: forces the generation of new groups from existing ones (if Copy)
@@ -5544,7 +5877,7 @@ class Mesh:
         Parameters:
             IDsOfElements: the list of elements ids
             Mirror: is :class:`SMESH.AxisStruct` or geom object (point, line, plane)
-            theMirrorType: smeshBuilder.POINT, smeshBuilder.AXIS or smeshBuilder.PLANE.
+            theMirrorType: smesh.POINT, smesh.AXIS or smesh.PLANE.
                 If the *Mirror* is a geom object this parameter is unnecessary
             MakeGroups: to generate new groups from existing ones
             NewMeshName: a name of the new mesh to create
@@ -5571,7 +5904,7 @@ class Mesh:
         Parameters:
             theObject: :class:`mesh, sub-mesh, group or filter <SMESH.SMESH_IDSource>`
             Mirror: :class:`SMESH.AxisStruct` or geom object (point, line, plane)
-            theMirrorType: smeshBuilder.POINT, smeshBuilder.AXIS or smeshBuilder.PLANE.
+            theMirrorType: smesh.POINT, smesh.AXIS or smesh.PLANE.
                 If the *Mirror* is a geom object this parameter is unnecessary
             Copy: allows copying the element (Copy==True) or replacing it with its mirror (Copy==False)
             MakeGroups: forces the generation of new groups from existing ones (if Copy)
@@ -5599,7 +5932,7 @@ class Mesh:
         Parameters:
             theObject: :class:`mesh, sub-mesh, group or filter <SMESH.SMESH_IDSource>`
             Mirror: :class:`SMESH.AxisStruct` or geom object (point, line, plane)
-            theMirrorType: smeshBuilder.POINT, smeshBuilder.AXIS or smeshBuilder.PLANE.
+            theMirrorType: smesh.POINT, smesh.AXIS or smesh.PLANE.
                 If the *Mirror* is a geom object this parameter is unnecessary
             MakeGroups: forces the generation of new groups from existing ones
             NewMeshName: the name of the new mesh to create
@@ -5746,9 +6079,9 @@ class Mesh:
         if ( isinstance( thePoint, list )):
             thePoint = PointStruct( thePoint[0], thePoint[1], thePoint[2] )
         if ( isinstance( theScaleFact, float )):
-             theScaleFact = [theScaleFact]
+            theScaleFact = [theScaleFact]
         if ( isinstance( theScaleFact, int )):
-             theScaleFact = [ float(theScaleFact)]
+            theScaleFact = [ float(theScaleFact)]
 
         self.mesh.SetParameters(thePoint.parameters)
 
@@ -5780,9 +6113,9 @@ class Mesh:
         if ( isinstance( thePoint, list )):
             thePoint = PointStruct( thePoint[0], thePoint[1], thePoint[2] )
         if ( isinstance( theScaleFact, float )):
-             theScaleFact = [theScaleFact]
+            theScaleFact = [theScaleFact]
         if ( isinstance( theScaleFact, int )):
-             theScaleFact = [ float(theScaleFact)]
+            theScaleFact = [ float(theScaleFact)]
 
         self.mesh.SetParameters(thePoint.parameters)
         mesh = self.editor.ScaleMakeMesh(theObject, thePoint, theScaleFact,
@@ -5942,11 +6275,11 @@ class Mesh:
     def FindCoincidentNodesOnPart (self, SubMeshOrGroup, Tolerance,
                                    exceptNodes=[], SeparateCornerAndMediumNodes=False):
         """
-        Find groups of ajacent nodes within Tolerance.
+        Find groups of adjacent nodes within Tolerance.
 
         Parameters:
             Tolerance: the value of tolerance
-            SubMeshOrGroup: :class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>`
+            SubMeshOrGroup: list of :class:`sub-meshes, groups or filters <SMESH.SMESH_IDSource>` or of node IDs
             exceptNodes: list of either SubMeshes, Groups or node IDs to exclude from search
             SeparateCornerAndMediumNodes: if *True*, in quadratic mesh puts
                 corner and medium nodes in separate groups thus preventing
@@ -5957,13 +6290,23 @@ class Mesh:
         """
 
         unRegister = genObjUnRegister()
-        if (isinstance( SubMeshOrGroup, Mesh )):
-            SubMeshOrGroup = SubMeshOrGroup.GetMesh()
+        if not isinstance( SubMeshOrGroup, list ):
+            SubMeshOrGroup = [ SubMeshOrGroup ]
+        for i,obj in enumerate( SubMeshOrGroup ):
+            if isinstance( obj, Mesh ):
+                SubMeshOrGroup = [ obj.GetMesh() ]
+                break
+            if isinstance( obj, int ):
+                SubMeshOrGroup = [ self.GetIDSource( SubMeshOrGroup, SMESH.NODE )]
+                unRegister.set( SubMeshOrGroup )
+                break
+
         if not isinstance( exceptNodes, list ):
             exceptNodes = [ exceptNodes ]
         if exceptNodes and isinstance( exceptNodes[0], int ):
             exceptNodes = [ self.GetIDSource( exceptNodes, SMESH.NODE )]
             unRegister.set( exceptNodes )
+
         return self.editor.FindCoincidentNodesOnPartBut(SubMeshOrGroup, Tolerance,
                                                         exceptNodes, SeparateCornerAndMediumNodes)
 
@@ -5974,44 +6317,72 @@ class Mesh:
         Parameters:
             GroupsOfNodes: a list of groups of nodes IDs for merging.
                 E.g. [[1,12,13],[25,4]] means that nodes 12, 13 and 4 will be removed and replaced
-                in all elements and groups by nodes 1 and 25 correspondingly
+                in all elements and mesh groups by nodes 1 and 25 correspondingly
             NodesToKeep: nodes to keep in the mesh: a list of groups, sub-meshes or node IDs.
                 If *NodesToKeep* does not include a node to keep for some group to merge,
                 then the first node in the group is kept.
             AvoidMakingHoles: prevent merging nodes which cause removal of elements becoming
                 invalid
         """
-        # NodesToKeep are converted to SMESH.SMESH_IDSource in meshEditor.MergeNodes()
         self.editor.MergeNodes( GroupsOfNodes, NodesToKeep, AvoidMakingHoles )
 
-    def FindEqualElements (self, MeshOrSubMeshOrGroup=None):
+    def FindEqualElements (self, MeshOrSubMeshOrGroup=None, exceptElements=[]):
         """
         Find the elements built on the same nodes.
 
         Parameters:
-            MeshOrSubMeshOrGroup: :class:`mesh, sub-mesh, group or filter <SMESH.SMESH_IDSource>`
+            MeshOrSubMeshOrGroup: :class:`mesh, sub-meshes, groups or filters <SMESH.SMESH_IDSource>` or element IDs to check for equal elements
+            exceptElements: list of either SubMeshes, Groups or elements IDs to exclude from search
+
 
         Returns:
             the list of groups of equal elements IDs (e.g. [[1,12,13],[4,25]])
         """
 
-        if not MeshOrSubMeshOrGroup:
-            MeshOrSubMeshOrGroup=self.mesh
+        unRegister = genObjUnRegister()
+        if MeshOrSubMeshOrGroup is None:
+            MeshOrSubMeshOrGroup = [ self.mesh ]
         elif isinstance( MeshOrSubMeshOrGroup, Mesh ):
-            MeshOrSubMeshOrGroup = MeshOrSubMeshOrGroup.GetMesh()
-        return self.editor.FindEqualElements( MeshOrSubMeshOrGroup )
-
-    def MergeElements(self, GroupsOfElementsID):
+            MeshOrSubMeshOrGroup = [ MeshOrSubMeshOrGroup.GetMesh() ]
+        elif not isinstance( MeshOrSubMeshOrGroup, list ):
+            MeshOrSubMeshOrGroup = [ MeshOrSubMeshOrGroup ]
+        if isinstance( MeshOrSubMeshOrGroup[0], int ):
+            MeshOrSubMeshOrGroup = [ self.GetIDSource( MeshOrSubMeshOrGroup, SMESH.ALL )]
+            unRegister.set( MeshOrSubMeshOrGroup )
+        for item in MeshOrSubMeshOrGroup:
+            if isinstance( item, Mesh ):
+                MeshOrSubMeshOrGroup = [ item.GetMesh() ]
+
+        if not isinstance( exceptElements, list ):
+            exceptElements = [ exceptElements ]
+        if exceptElements and isinstance( exceptElements[0], int ):
+            exceptElements = [ self.GetIDSource( exceptElements, SMESH.ALL )]
+            unRegister.set( exceptElements )
+
+        return self.editor.FindEqualElements( MeshOrSubMeshOrGroup, exceptElements )
+
+    def MergeElements(self, GroupsOfElementsID, ElementsToKeep=[]):
         """
         Merge elements in each given group.
 
         Parameters:
             GroupsOfElementsID: a list of groups (lists) of elements IDs for merging
                 (e.g. [[1,12,13],[25,4]] means that elements 12, 13 and 4 will be removed and
-                replaced in all groups by elements 1 and 25)
+                replaced in all mesh groups by elements 1 and 25)
+            ElementsToKeep: elements to keep in the mesh: a list of groups, sub-meshes or node IDs.
+                If *ElementsToKeep* does not include an element to keep for some group to merge,
+                then the first element in the group is kept.
         """
 
-        self.editor.MergeElements(GroupsOfElementsID)
+        unRegister = genObjUnRegister()
+        if ElementsToKeep:
+            if not isinstance( ElementsToKeep, list ):
+                ElementsToKeep = [ ElementsToKeep ]
+            if isinstance( ElementsToKeep[0], int ):
+                ElementsToKeep = [ self.GetIDSource( ElementsToKeep, SMESH.ALL )]
+                unRegister.set( ElementsToKeep )
+
+        self.editor.MergeElements( GroupsOfElementsID, ElementsToKeep )
 
     def MergeEqualElements(self):
         """
@@ -6030,22 +6401,25 @@ class Mesh:
 
         return self.editor.FindFreeBorders( ClosedOnly )
 
-    def FillHole(self, holeNodes):
+    def FillHole(self, holeNodes, groupName=""):
         """
         Fill with 2D elements a hole defined by a SMESH.FreeBorder.
 
         Parameters:
-            FreeBorder: either a SMESH.FreeBorder or a list on node IDs. These nodes
+            holeNodes: either a SMESH.FreeBorder or a list on node IDs. These nodes
                 must describe all sequential nodes of the hole border. The first and the last
                 nodes must be the same. Use :meth:`FindFreeBorders` to get nodes of holes.
+            groupName (string): name of a group to add new faces
+        Returns:
+            a :class:`group <SMESH.SMESH_GroupBase>` containing the new faces; or :code:`None` if `groupName` == ""
         """
 
 
         if holeNodes and isinstance( holeNodes, list ) and isinstance( holeNodes[0], int ):
             holeNodes = SMESH.FreeBorder(nodeIDs=holeNodes)
         if not isinstance( holeNodes, SMESH.FreeBorder ):
-            raise TypeError, "holeNodes must be either SMESH.FreeBorder or list of integer and not %s" % holeNodes
-        self.editor.FillHole( holeNodes )
+            raise TypeError("holeNodes must be either SMESH.FreeBorder or list of integer and not %s" % holeNodes)
+        self.editor.FillHole( holeNodes, groupName )
 
     def FindCoincidentFreeBorders (self, tolerance=0.):
         """
@@ -6092,7 +6466,7 @@ class Mesh:
             coincidentGroups = []
             for nodeList in freeBorders:
                 if not nodeList or len( nodeList ) % 3:
-                    raise ValueError, "Wrong number of nodes in this group: %s" % nodeList
+                    raise ValueError("Wrong number of nodes in this group: %s" % nodeList)
                 group = []
                 while nodeList:
                     group.append  ( SMESH.FreeBorderPart( len(borders), 0, 1, 2 ))
@@ -6219,7 +6593,7 @@ class Mesh:
                 a :class:`Mesh`, elements of highest dimension are duplicated
             theGroupName: a name of group to contain the generated elements.
                 If a group with such a name already exists, the new elements
-                are added to the existng group, else a new group is created.
+                are added to the existing group, else a new group is created.
                 If *theGroupName* is empty, new elements are not added
                 in any group.
 
@@ -6449,6 +6823,7 @@ class Mesh:
         return self.editor.AffectedElemGroupsInRegion(theElems, theNodesNot, theShape)
 
     def DoubleNodesOnGroupBoundaries(self, theDomains, createJointElems, onAllBoundaries=False ):
+
         """
         Double nodes on shared faces between groups of volumes and create flat elements on demand.
         The list of groups must describe a partition of the mesh volumes.
@@ -6494,7 +6869,7 @@ class Mesh:
     def MakePolyLine(self, segments, groupName='', isPreview=False ):
         """    
         Create a polyline consisting of 1D mesh elements each lying on a 2D element of
-        the initial mesh. Positions of new nodes are found by cutting the mesh by the
+        the initial triangle mesh. Positions of new nodes are found by cutting the mesh by the
         plane passing through pairs of points specified by each :class:`SMESH.PolySegment` structure.
         If there are several paths connecting a pair of points, the shortest path is
         selected by the module. Position of the cutting plane is defined by the two
@@ -6504,12 +6879,12 @@ class Mesh:
         The vector goes from the middle point to the projection point. In case of planar
         mesh, the vector is normal to the mesh.
 
-        *segments* [i].vector returns the used vector which goes from the middle point to its projection.
+        In preview mode, *segments* [i].vector returns the used vector which goes from the middle point to its projection.
 
-        Parameters:        
+        Parameters:
             segments: list of :class:`SMESH.PolySegment` defining positions of cutting planes.
             groupName: optional name of a group where created mesh segments will be added.
-            
+
         """    
         editor = self.editor
         if isPreview:
@@ -6519,7 +6894,18 @@ class Mesh:
             segments[i].vector = seg.vector
         if isPreview:
             return editor.GetPreviewData()
-        return None        
+        return None
+
+    def MakeSlot(self, segmentGroup, width ):
+        """
+        Create a slot of given width around given 1D elements lying on a triangle mesh.
+        The slot is consrtucted by cutting faces by cylindrical surfaces made
+        around each segment. Segments are expected to be created by MakePolyLine().
+
+        Returns:
+               FaceEdge's located at the slot boundary
+        """
+        return self.editor.MakeSlot( segmentGroup, width )
 
     def GetFunctor(self, funcType ):
         """
@@ -6562,56 +6948,112 @@ class Mesh:
 
     def GetLength(self, elemId=None):
         """
-        Get length of 1D element or sum of lengths of all 1D mesh elements
+        Get length of given 1D elements or of all 1D mesh elements
 
         Parameters:
-            elemId: mesh element ID (if not defined - sum of length of all 1D elements will be calculated)
+            elemId: either a mesh element ID or a list of IDs or :class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>`. By default sum length of all 1D elements will be calculated.
 
         Returns:
-            element's length value if *elemId* is specified or sum of all 1D mesh elements' lengths otherwise
+            Sum of lengths of given elements
         """
 
         length = 0
         if elemId == None:
             length = self.smeshpyD.GetLength(self)
+        elif isinstance(elemId, SMESH._objref_SMESH_IDSource):
+            length = self.smeshpyD.GetLength(elemId)
+        elif elemId == []:
+            length = 0
+        elif isinstance(elemId, list) and isinstance(elemId[0], SMESH._objref_SMESH_IDSource):
+            for obj in elemId:
+                length += self.smeshpyD.GetLength(obj)
+        elif isinstance(elemId, list) and isinstance(elemId[0], int):
+            unRegister = genObjUnRegister()
+            obj = self.GetIDSource( elemId )
+            unRegister.set( obj )
+            length = self.smeshpyD.GetLength( obj )
         else:
             length = self.FunctorValue(SMESH.FT_Length, elemId)
         return length
 
     def GetArea(self, elemId=None):
         """
-        Get area of 2D element or sum of areas of all 2D mesh elements
-        elemId mesh element ID (if not defined - sum of areas of all 2D elements will be calculated)
+        Get area of given 2D elements or of all 2D mesh elements
+
+        Parameters:
+            elemId: either a mesh element ID or a list of IDs or :class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>`. By default sum area of all 2D elements will be calculated.
 
         Returns:
-            element's area value if *elemId* is specified or sum of all 2D mesh elements' areas otherwise
+            Area of given element's if *elemId* is specified or sum of all 2D mesh elements' areas otherwise
         """
 
         area = 0
         if elemId == None:
             area = self.smeshpyD.GetArea(self)
+        elif isinstance(elemId, SMESH._objref_SMESH_IDSource):
+            area = self.smeshpyD.GetArea(elemId)
+        elif elemId == []:
+            area = 0
+        elif isinstance(elemId, list) and isinstance(elemId[0], SMESH._objref_SMESH_IDSource):
+            for obj in elemId:
+                area += self.smeshpyD.GetArea(obj)
+        elif isinstance(elemId, list) and isinstance(elemId[0], int):
+            unRegister = genObjUnRegister()
+            obj = self.GetIDSource( elemId )
+            unRegister.set( obj )
+            area = self.smeshpyD.GetArea( obj )
         else:
             area = self.FunctorValue(SMESH.FT_Area, elemId)
         return area
 
     def GetVolume(self, elemId=None):
         """
-        Get volume of 3D element or sum of volumes of all 3D mesh elements
+        Get volume of given 3D elements or of all 3D mesh elements
 
         Parameters:
-            elemId: mesh element ID (if not defined - sum of volumes of all 3D elements will be calculated)
+            elemId: either a mesh element ID or a list of IDs or :class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>`. By default sum volume of all 3D elements will be calculated.
 
         Returns:
-            element's volume value if *elemId* is specified or sum of all 3D mesh elements' volumes otherwise
+            Sum element's volume value if *elemId* is specified or sum of all 3D mesh elements' volumes otherwise
         """
 
         volume = 0
         if elemId == None:
-            volume = self.smeshpyD.GetVolume(self)
+            volume= self.smeshpyD.GetVolume(self)
+        elif isinstance(elemId, SMESH._objref_SMESH_IDSource):
+            volume= self.smeshpyD.GetVolume(elemId)
+        elif elemId == []:
+            volume = 0
+        elif isinstance(elemId, list) and isinstance(elemId[0], SMESH._objref_SMESH_IDSource):
+            for obj in elemId:
+                volume+= self.smeshpyD.GetVolume(obj)
+        elif isinstance(elemId, list) and isinstance(elemId[0], int):
+            unRegister = genObjUnRegister()
+            obj = self.GetIDSource( elemId )
+            unRegister.set( obj )
+            volume= self.smeshpyD.GetVolume( obj )
         else:
             volume = self.FunctorValue(SMESH.FT_Volume3D, elemId)
         return volume
 
+    def GetAngle(self, node1, node2, node3 ):
+        """
+        Computes a radian measure of an angle defined by 3 nodes: <(node1,node2,node3)
+
+        Parameters:            
+                node1,node2,node3: IDs of the three nodes
+
+        Returns:        
+            Angle in radians [0,PI]. -1 if failure case.
+        """
+        p1 = self.GetNodeXYZ( node1 )
+        p2 = self.GetNodeXYZ( node2 )
+        p3 = self.GetNodeXYZ( node3 )
+        if p1 and p2 and p3:
+            return self.smeshpyD.GetAngle( p1,p2,p3 )
+        return -1.
+
+
     def GetMaxElementLength(self, elemId):
         """
         Get maximum element length.
@@ -6738,28 +7180,49 @@ class meshProxy(SMESH._objref_SMESH_Mesh):
     Private class used to compensate change of CORBA API of SMESH_Mesh for backward compatibility
     with old dump scripts which call SMESH_Mesh directly and not via smeshBuilder.Mesh
     """
-    def __init__(self):
-        SMESH._objref_SMESH_Mesh.__init__(self)
+    def __init__(self,*args):
+        SMESH._objref_SMESH_Mesh.__init__(self,*args)
     def __deepcopy__(self, memo=None):
-        new = self.__class__()
+        new = self.__class__(self)
         return new
     def CreateDimGroup(self,*args): # 2 args added: nbCommonNodes, underlyingOnly
         if len( args ) == 3:
             args += SMESH.ALL_NODES, True
-        return SMESH._objref_SMESH_Mesh.CreateDimGroup( self, *args )
+        return SMESH._objref_SMESH_Mesh.CreateDimGroup(self, *args)
+    def ExportToMEDX(self, *args): # function removed
+        print("WARNING: ExportToMEDX() is deprecated, use ExportMED() instead")
+        #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]]
+        SMESH._objref_SMESH_Mesh.ExportMED(self, *args)
+    def ExportToMED(self, *args): # function removed
+        print("WARNING: ExportToMED() is deprecated, use ExportMED() instead")
+        #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]]
+        args2 = list(args)
+        while len(args2) < 5:  # !!!! nb of parameters for ExportToMED IDL's method
+            args2.append(True)
+        SMESH._objref_SMESH_Mesh.ExportMED(self, *args2)
+    def ExportPartToMED(self, *args): # 'version' parameter removed
+        #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]]
+        SMESH._objref_SMESH_Mesh.ExportPartToMED(self, *args)
+    def ExportMED(self, *args): # signature of method changed
+        #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]]
+        args2 = list(args)
+        while len(args2) < 5:  # !!!! nb of parameters for ExportToMED IDL's method
+            args2.append(True)
+        SMESH._objref_SMESH_Mesh.ExportMED(self, *args2)
     pass
 omniORB.registerObjref(SMESH._objref_SMESH_Mesh._NP_RepositoryId, meshProxy)
 
 
 class submeshProxy(SMESH._objref_SMESH_subMesh):
+
     """
     Private class wrapping SMESH.SMESH_SubMesh in order to add Compute()
     """
-    def __init__(self):
-        SMESH._objref_SMESH_subMesh.__init__(self)
+    def __init__(self,*args):
+        SMESH._objref_SMESH_subMesh.__init__(self,*args)
         self.mesh = None
     def __deepcopy__(self, memo=None):
-        new = self.__class__()
+        new = self.__class__(self)
         return new
 
     def Compute(self,refresh=False):
@@ -6781,11 +7244,8 @@ class submeshProxy(SMESH._objref_SMESH_subMesh):
 
         ok = self.mesh.Compute( self.GetSubShape(),refresh=[] )
 
-        if salome.sg.hasDesktop() and self.mesh.GetStudyId() >= 0:
-            smeshgui = salome.ImportComponentGUI("SMESH")
-            smeshgui.Init(self.mesh.GetStudyId())
-            smeshgui.SetMeshIcon( salome.ObjectToID( self ), ok, (self.GetNumberOfElements()==0) )
-            if refresh: salome.sg.updateObjBrowser(True)
+        if salome.sg.hasDesktop():
+            if refresh: salome.sg.updateObjBrowser()
             pass
 
         return ok
@@ -6799,8 +7259,8 @@ class meshEditor(SMESH._objref_SMESH_MeshEditor):
     compatibility with old dump scripts which call SMESH_MeshEditor directly and not via
     smeshBuilder.Mesh
     """
-    def __init__(self):
-        SMESH._objref_SMESH_MeshEditor.__init__(self)
+    def __init__(self,*args):
+        SMESH._objref_SMESH_MeshEditor.__init__( self, *args)
         self.mesh = None
     def __getattr__(self, name ): # method called if an attribute not found
         if not self.mesh:         # look for name() method in Mesh class
@@ -6809,10 +7269,10 @@ class meshEditor(SMESH._objref_SMESH_MeshEditor):
             return getattr( self.mesh, name )
         if name == "ExtrusionAlongPathObjX":
             return getattr( self.mesh, "ExtrusionAlongPathX" ) # other method name
-        print "meshEditor: attribute '%s' NOT FOUND" % name
+        print("meshEditor: attribute '%s' NOT FOUND" % name)
         return None
     def __deepcopy__(self, memo=None):
-        new = self.__class__()
+        new = self.__class__(self)
         return new
     def FindCoincidentNodes(self,*args): # a 2nd arg added (SeparateCornerAndMediumNodes)
         if len( args ) == 1: args += False,
@@ -6885,13 +7345,13 @@ class algoCreator:
         """
         Store a python class of algorithm
         """
-        if type( algoClass ).__name__ == 'classobj' and \
+        if inspect.isclass(algoClass) and \
            hasattr( algoClass, "algoType"):
             self.algoTypeToClass[ algoClass.algoType ] = algoClass
             if not self.defaultAlgoType and \
                hasattr( algoClass, "isDefault") and algoClass.isDefault:
                 self.defaultAlgoType = algoClass.algoType
-            #print "Add",algoClass.algoType, "dflt",self.defaultAlgoType
+            #print("Add",algoClass.algoType, "dflt",self.defaultAlgoType)
 
     def copy(self, mesh):
         """
@@ -6939,10 +7399,10 @@ class algoCreator:
             algoType = self.defaultAlgoType
         if not algoType and self.algoTypeToClass:
             algoType = sorted( self.algoTypeToClass.keys() )[0]
-        if self.algoTypeToClass.has_key( algoType ):
-            #print "Create algo",algoType
+        if algoType in self.algoTypeToClass:
+            #print("Create algo",algoType)
             return self.algoTypeToClass[ algoType ]( self.mesh, shape )
-        raise RuntimeError, "No class found for algo type %s" % algoType
+        raise RuntimeError( "No class found for algo type %s" % algoType)
         return None
 
 class hypMethodWrapper:
@@ -6953,7 +7413,7 @@ class hypMethodWrapper:
     def __init__(self, hyp, method):
         self.hyp    = hyp
         self.method = method
-        #print "REBIND:", method.__name__
+        #print("REBIND:", method.__name__)
         return
 
     def __call__(self,*args):
@@ -6964,7 +7424,7 @@ class hypMethodWrapper:
         if not args:
             return self.method( self.hyp, *args ) # hypothesis method with no args
 
-        #print "MethWrapper.__call__",self.method.__name__, args
+        #print("MethWrapper.__call__", self.method.__name__, args)
         try:
             parsed = ParseParameters(*args)     # replace variables with their values
             self.hyp.SetVarParameter( parsed[-2], self.method.__name__ )
@@ -6972,11 +7432,11 @@ class hypMethodWrapper:
         except omniORB.CORBA.BAD_PARAM: # raised by hypothesis method call
             # maybe there is a replaced string arg which is not variable
             result = self.method( self.hyp, *args )
-        except ValueError, detail: # raised by ParseParameters()
+        except ValueError as detail: # raised by ParseParameters()
             try:
                 result = self.method( self.hyp, *args )
             except omniORB.CORBA.BAD_PARAM:
-                raise ValueError, detail # wrong variable name
+                raise ValueError(detail) # wrong variable name
 
         return result
     pass
@@ -7009,25 +7469,25 @@ for pluginName in os.environ[ "SMESH_MeshersList" ].split( ":" ):
     Bind methods creating mesher plug-ins to the Mesh class
     """
 
-    # print "pluginName: ", pluginName
+    # print("pluginName: ", pluginName)
     pluginBuilderName = pluginName + "Builder"
     try:
         exec( "from salome.%s.%s import *" % (pluginName, pluginBuilderName))
-    except Exception, e:
+    except Exception as e:
         from salome_utils import verbose
-        if verbose(): print "Exception while loading %s: %s" % ( pluginBuilderName, e )
+        if verbose(): print("Exception while loading %s: %s" % ( pluginBuilderName, e ))
         continue
     exec( "from salome.%s import %s" % (pluginName, pluginBuilderName))
     plugin = eval( pluginBuilderName )
-    # print "  plugin:" , str(plugin)
+    # print("  plugin:" , str(plugin))
 
     # add methods creating algorithms to Mesh
     for k in dir( plugin ):
         if k[0] == '_': continue
         algo = getattr( plugin, k )
-        # print "             algo:", str(algo)
-        if type( algo ).__name__ == 'classobj' and hasattr( algo, "meshMethod" ):
-            # print "                     meshMethod:" , str(algo.meshMethod)
+        #print("             algo:", str(algo))
+        if inspect.isclass(algo) and hasattr(algo, "meshMethod"):
+            #print("                     meshMethod:" , str(algo.meshMethod))
             if not hasattr( Mesh, algo.meshMethod ):
                 setattr( Mesh, algo.meshMethod, algoCreator( algo.meshMethod ))
                 pass