Salome HOME
22611: EDF 8409 SMESH: Bad dump of CutListOfGroups
[modules/smesh.git] / src / SMESH_I / SMESH_Mesh_i.cxx
index b47ae9b19e261cd1c7ae03d6f169e51d68bbb774..311e1377de03680480ba070b33923581a35ba940 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -6,7 +6,7 @@
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 // License as published by the Free Software Foundation; either
-// version 2.1 of the License.
+// version 2.1 of the License, or (at your option) any later version.
 //
 // This library is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -26,6 +26,7 @@
 #include "SMESH_Mesh_i.hxx"
 
 #include "DriverMED_R_SMESHDS_Mesh.h"
+#include "DriverMED_W_Field.h"
 #include "DriverMED_W_SMESHDS_Mesh.h"
 #include "MED_Factory.hxx"
 #include "SMDS_EdgePosition.hxx"
 #include "SMESHDS_Group.hxx"
 #include "SMESHDS_GroupOnGeom.hxx"
 #include "SMESH_Controls.hxx"
+#include "SMESH_File.hxx"
 #include "SMESH_Filter_i.hxx"
 #include "SMESH_Gen_i.hxx"
 #include "SMESH_Group.hxx"
 #include "SMESH_Group_i.hxx"
+#include "SMESH_Mesh.hxx"
 #include "SMESH_MeshAlgos.hxx"
 #include "SMESH_MeshEditor.hxx"
 #include "SMESH_MeshEditor_i.hxx"
 #include "SMESH_PythonDump.hxx"
 #include "SMESH_subMesh_i.hxx"
 
-#include <OpUtil.hxx>
 #include <SALOMEDS_Attributes_wrap.hxx>
 #include <SALOMEDS_wrap.hxx>
-#include <SALOME_NamingService.hxx>
 #include <Utils_ExceptHandlers.hxx>
-#include <Utils_SINGLETON.hxx>
 #include <utilities.h>
 
 #include <GEOMImpl_Types.hxx>
 
 // OCCT Includes
 #include <BRep_Builder.hxx>
-#include <OSD_Directory.hxx>
-#include <OSD_File.hxx>
-#include <OSD_Path.hxx>
-#include <OSD_Protection.hxx>
-#include <Standard_OutOfMemory.hxx>
-#include <TColStd_MapIteratorOfMapOfInteger.hxx>
+#include <Standard_ErrorHandler.hxx>
 #include <TColStd_MapOfInteger.hxx>
-#include <TColStd_SequenceOfInteger.hxx>
-#include <TCollection_AsciiString.hxx>
 #include <TopExp.hxx>
 #include <TopExp_Explorer.hxx>
 #include <TopTools_MapIteratorOfMapOfShape.hxx>
 #include <TopTools_MapOfShape.hxx>
 #include <TopoDS_Compound.hxx>
 
-#include "SMESH_TryCatch.hxx" // include after OCCT headers!
-
 // STL Includes
 #include <algorithm>
-#include <string>
 #include <iostream>
 #include <sstream>
 
-#include <sys/stat.h>
+// to pass CORBA exception through SMESH_TRY
+#define SMY_OWN_CATCH catch( SALOME::SALOME_Exception& se ) { throw se; }
+
+#include "SMESH_TryCatch.hxx" // include after OCCT headers!
 
 #ifdef _DEBUG_
 static int MYDEBUG = 0;
@@ -121,6 +114,7 @@ SMESH_Mesh_i::SMESH_Mesh_i( PortableServer::POA_ptr thePOA,
   _editor        = NULL;
   _previewEditor = NULL;
   _preMeshInfo   = NULL;
+  _mainShapeTick = 0;
 }
 
 //=============================================================================
@@ -194,6 +188,8 @@ void SMESH_Mesh_i::SetShape( GEOM::GEOM_Object_ptr theShapeObject )
   // to track changes of GEOM groups
   SMESH::SMESH_Mesh_var mesh = _this();
   addGeomGroupData( theShapeObject, mesh );
+  if ( !CORBA::is_nil( theShapeObject ))
+    _mainShapeTick = theShapeObject->GetTick();
 }
 
 //================================================================================
@@ -276,7 +272,7 @@ void SMESH_Mesh_i::Clear() throw (SALOME::SALOME_Exception)
 
   try {
     _impl->Clear();
-    CheckGeomGroupModif(); // issue 20145
+    //CheckGeomGroupModif(); // issue 20145
   }
   catch(SALOME_Exception & S_ex) {
     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
@@ -397,14 +393,7 @@ SMESH_Mesh_i::ImportMEDFile( const char* theFileName, const char* theMeshName )
   _medFileInfo->major    = major;
   _medFileInfo->minor    = minor;
   _medFileInfo->release  = release;
-#ifdef WIN32
-  struct _stati64 d;
-  if ( ::_stati64( theFileName, &d ) != -1 )
-#else
-  struct stat64 d;
-  if ( ::stat64( theFileName, &d ) != -1 )
-#endif
-    _medFileInfo->fileSize = d.st_size;
+  _medFileInfo->fileSize = SMESH_File( theFileName ).size();
 
   return ConvertDriverMEDReadStatus(status);
 }
@@ -1504,7 +1493,7 @@ SMESH_Mesh_i::CutListOfGroups(const SMESH::ListOfGroups& theMainGroups,
     if ( aType == SMESH::ALL )
       aType = aGrp->GetType();
     else if ( aType != aGrp->GetType() )
-      THROW_SALOME_CORBA_EXCEPTION("UnionListOfGroups(): different group types",
+      THROW_SALOME_CORBA_EXCEPTION("CutListOfGroups(): different group types",
                                    SALOME::BAD_PARAM);
     if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aGrp ))
       if ( SMESHDS_GroupBase* grpDS = grp_i->GetGroupDS() )
@@ -1522,7 +1511,7 @@ SMESH_Mesh_i::CutListOfGroups(const SMESH::ListOfGroups& theMainGroups,
     if ( CORBA::is_nil( aGrp ) )
       continue;
     if ( aType != aGrp->GetType() )
-      THROW_SALOME_CORBA_EXCEPTION("UnionListOfGroups(): different group types",
+      THROW_SALOME_CORBA_EXCEPTION("CutListOfGroups(): different group types",
                                    SALOME::BAD_PARAM);
     if ( SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( aGrp ))
       if ( SMESHDS_GroupBase* grpDS = grp_i->GetGroupDS() )
@@ -1558,7 +1547,7 @@ SMESH_Mesh_i::CutListOfGroups(const SMESH::ListOfGroups& theMainGroups,
 
   // Update Python script
   pyDump << aResGrp << " = " << SMESH::SMESH_Mesh_var( _this() )
-         << ".CutListOfGroups( " << theMainGroups
+         << ".CutListOfGroups( " << theMainGroups << ", "
          << theToolGroups << ", '" << theName << "' )";
 
   SMESH_CATCH( SMESH::throwCorbaException );
@@ -1703,6 +1692,9 @@ void SMESH_Mesh_i::addGeomGroupData(GEOM::GEOM_Object_ptr theGeomObj,
     groupData._indices.insert( ids[i] );
   // SMESH object
   groupData._smeshObject = CORBA::Object::_duplicate( theSmeshObj );
+  // shape index in SMESHDS
+  // TopoDS_Shape shape = _gen_i->GeomObjectToShape( theGeomObj );
+  // groupData._dsID = shape.IsNull() ? 0 : _impl->GetSubMesh( shape )->GetId();
 }
 
 //================================================================================
@@ -1776,22 +1768,176 @@ TopoDS_Shape SMESH_Mesh_i::newGroupShape( TGeomGroupData & groupData)
 
 namespace
 {
-  //=============================================================================
+  //-----------------------------------------------------------------------------
   /*!
    * \brief Storage of shape and index used in CheckGeomGroupModif()
    */
-  //=============================================================================
   struct TIndexedShape
   {
     int          _index;
     TopoDS_Shape _shape;
     TIndexedShape( int i, const TopoDS_Shape& s ):_index(i), _shape(s) {}
   };
+  //-----------------------------------------------------------------------------
+  /*!
+   * \brief Data to re-create a group on geometry
+   */
+  struct TGroupOnGeomData
+  {
+    int                 _oldID;
+    int                 _shapeID;
+    SMDSAbs_ElementType _type;
+    std::string         _name;
+    Quantity_Color      _color;
+  };
 }
+
+//=============================================================================
+/*!
+ * \brief Update data if geometry changes
+ *
+ * Issue 0022501
+ */
+//=============================================================================
+
+void SMESH_Mesh_i::CheckGeomModif()
+{
+  if ( !_impl->HasShapeToMesh() ) return;
+
+  SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
+  if ( study->_is_nil() ) return;
+
+  GEOM::GEOM_Object_var mainGO = _gen_i->ShapeToGeomObject( _impl->GetShapeToMesh() );
+  if ( mainGO->_is_nil() ) return;
+
+  if ( mainGO->GetType() == GEOM_GROUP ||
+       mainGO->GetTick() == _mainShapeTick )
+  {
+    CheckGeomGroupModif();
+    return;
+  }
+
+  GEOM_Client* geomClient = _gen_i->GetShapeReader();
+  if ( !geomClient ) return;
+  GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine();
+  if ( geomGen->_is_nil() ) return;
+
+  CORBA::String_var ior = geomGen->GetStringFromIOR( mainGO );
+  geomClient->RemoveShapeFromBuffer( ior.in() );
+
+  // Update data taking into account that
+  // all sub-shapes change but IDs of sub-shapes remain (except for geom groups)
+
+  _impl->Clear();
+  TopoDS_Shape newShape = _gen_i->GeomObjectToShape( mainGO );
+  if ( newShape.IsNull() )
+    return;
+
+  _mainShapeTick = mainGO->GetTick();
+
+  SMESHDS_Mesh * meshDS = _impl->GetMeshDS();
+
+  // store data of groups on geometry
+  vector< TGroupOnGeomData > groupsData;
+  const set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
+  groupsData.reserve( groups.size() );
+  set<SMESHDS_GroupBase*>::const_iterator g = groups.begin();
+  for ( ; g != groups.end(); ++g )
+    if ( const SMESHDS_GroupOnGeom* group = dynamic_cast< SMESHDS_GroupOnGeom* >( *g ))
+    {
+      TGroupOnGeomData data;
+      data._oldID   = group->GetID();
+      data._shapeID = meshDS->ShapeToIndex( group->GetShape() );
+      data._type    = group->GetType();
+      data._name    = group->GetStoreName();
+      data._color   = group->GetColor();
+      groupsData.push_back( data );
+    }
+  // store assigned hypotheses
+  vector< pair< int, THypList > > ids2Hyps;
+  const ShapeToHypothesis & hyps = meshDS->GetHypotheses();
+  for ( ShapeToHypothesis::Iterator s2hyps( hyps ); s2hyps.More(); s2hyps.Next() )
+  {
+    const TopoDS_Shape& s = s2hyps.Key();
+    const THypList&  hyps = s2hyps.ChangeValue();
+    ids2Hyps.push_back( make_pair( meshDS->ShapeToIndex( s ), hyps ));
+  }
+
+  // change shape to mesh
+  int oldNbSubShapes = meshDS->MaxShapeIndex();
+  _impl->ShapeToMesh( TopoDS_Shape() );
+  _impl->ShapeToMesh( newShape );
+
+  // re-add shapes of geom groups
+  list<TGeomGroupData>::iterator data = _geomGroupData.begin();
+  for ( ; data != _geomGroupData.end(); ++data )
+  {
+    TopoDS_Shape newShape = newGroupShape( *data );
+    if ( !newShape.IsNull() )
+    {
+      if ( meshDS->ShapeToIndex( newShape ) > 0 ) // a group reduced to one sub-shape
+      {
+        TopoDS_Compound compound;
+        BRep_Builder().MakeCompound( compound );
+        BRep_Builder().Add( compound, newShape );
+        newShape = compound;
+      }
+      _impl->GetSubMesh( newShape );
+    }
+  }
+  if ( oldNbSubShapes != meshDS->MaxShapeIndex() )
+    THROW_SALOME_CORBA_EXCEPTION( "SMESH_Mesh_i::CheckGeomModif() bug",
+                                  SALOME::INTERNAL_ERROR );
+
+  // re-assign hypotheses
+  for ( size_t i = 0; i < ids2Hyps.size(); ++i )
+  {
+    const TopoDS_Shape& s = meshDS->IndexToShape( ids2Hyps[i].first );
+    const THypList&  hyps = ids2Hyps[i].second;
+    THypList::const_iterator h = hyps.begin();
+    for ( ; h != hyps.end(); ++h )
+      _impl->AddHypothesis( s, (*h)->GetID() );
+  }
+
+  // restore groups
+  for ( size_t i = 0; i < groupsData.size(); ++i )
+  {
+    const TGroupOnGeomData& data = groupsData[i];
+
+    map<int, SMESH::SMESH_GroupBase_ptr>::iterator i2g = _mapGroups.find( data._oldID );
+    if ( i2g == _mapGroups.end() ) continue;
+
+    SMESH_GroupBase_i* gr_i = SMESH::DownCast<SMESH_GroupBase_i*>( i2g->second );
+    if ( !gr_i ) continue;
+
+    int id;
+    SMESH_Group* g = _impl->AddGroup( data._type, data._name.c_str(), id,
+                                      meshDS->IndexToShape( data._shapeID ));
+    if ( !g )
+    {
+      _mapGroups.erase( i2g );
+    }
+    else
+    {
+      g->GetGroupDS()->SetColor( data._color );
+      gr_i->changeLocalId( id );
+      _mapGroups[ id ] = i2g->second;
+      if ( data._oldID != id )
+        _mapGroups.erase( i2g );
+    }
+  }
+
+  // update _mapSubMesh
+  map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
+  for ( ; i_sm != _mapSubMesh.end(); ++i_sm )
+    i_sm->second = _impl->GetSubMesh( meshDS->IndexToShape( i_sm->first ));
+
+}
+
 //=============================================================================
 /*!
  * \brief Update objects depending on changed geom groups
- * 
+ *
  * NPAL16168: geometrical group edition from a submesh don't modifiy mesh computation
  * issue 0020210: Update of a smesh group after modification of the associated geom group
  */
@@ -2609,44 +2755,36 @@ CORBA::Boolean SMESH_Mesh_i::HasDuplicatedGroupNamesMED()
 
 void SMESH_Mesh_i::PrepareForWriting (const char* file, bool overwrite)
 {
-  TCollection_AsciiString aFullName ((char*)file);
-  OSD_Path aPath (aFullName);
-  OSD_File aFile (aPath);
-  if (aFile.Exists()) {
+  SMESH_File aFile( file );
+  SMESH_Comment msg;
+  if (aFile.exists()) {
     // existing filesystem node
-    if (aFile.KindOfFile() == OSD_FILE) {
-      if (aFile.IsWriteable()) {
-        if (overwrite) {
-          aFile.Reset();
-          aFile.Remove();
-        }
-        if (aFile.Failed()) {
-          TCollection_AsciiString msg ("File ");
-          msg += aFullName + " cannot be replaced.";
-          THROW_SALOME_CORBA_EXCEPTION(msg.ToCString(), SALOME::BAD_PARAM);
+    if ( !aFile.isDirectory() ) {
+      if ( aFile.openForWriting() ) {
+        if ( overwrite && ! aFile.remove()) {
+          msg << "Can't replace " << aFile.getName();
         }
       } else {
-        TCollection_AsciiString msg ("File ");
-        msg += aFullName + " cannot be overwritten.";
-        THROW_SALOME_CORBA_EXCEPTION(msg.ToCString(), SALOME::BAD_PARAM);
+        msg << "Can't write into " << aFile.getName();
       }
     } else {
-      TCollection_AsciiString msg ("Location ");
-      msg += aFullName + " is not a file.";
-      THROW_SALOME_CORBA_EXCEPTION(msg.ToCString(), SALOME::BAD_PARAM);
+      msg << "Location " << aFile.getName() << " is not a file";
     }
-  } else {
+  }
+  else {
     // nonexisting file; check if it can be created
-    aFile.Reset();
-    aFile.Build(OSD_WriteOnly, OSD_Protection());
-    if (aFile.Failed()) {
-      TCollection_AsciiString msg ("You cannot create the file ");
-      msg += aFullName + ". Check the directory existance and access rights.";
-      THROW_SALOME_CORBA_EXCEPTION(msg.ToCString(), SALOME::BAD_PARAM);
-    } else {
-      aFile.Close();
-      aFile.Remove();
+    if ( !aFile.openForWriting() ) {
+      msg << "You cannot create the file "
+          << aFile.getName()
+          << ". Check the directory existance and access rights";
     }
+    aFile.remove();
+  }
+
+  if ( !msg.empty() )
+  {
+    msg << ".";
+    THROW_SALOME_CORBA_EXCEPTION(msg.c_str(), SALOME::BAD_PARAM);
   }
 }
 
@@ -2716,13 +2854,13 @@ void SMESH_Mesh_i::ExportToMEDX (const char*        file,
     _preMeshInfo->FullLoadFromFile();
 
   string aMeshName = prepareMeshNameAndGroups(file, overwrite);
+  _impl->ExportMED( file, aMeshName.c_str(), auto_groups, theVersion, 0, autoDimension );
+
   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportToMEDX( r'"
                 << file << "', " << auto_groups << ", "
                 << theVersion << ", " << overwrite << ", "
                 << autoDimension << " )";
 
-  _impl->ExportMED( file, aMeshName.c_str(), auto_groups, theVersion, 0, autoDimension );
-
   SMESH_CATCH( SMESH::throwCorbaException );
 }
 
@@ -2850,20 +2988,65 @@ void SMESH_Mesh_i::ExportSTL (const char *file, const bool isascii)
  */
 //================================================================================
 
-void SMESH_Mesh_i::ExportPartToMED(::SMESH::SMESH_IDSource_ptr meshPart,
-                                   const char*                 file,
-                                   CORBA::Boolean              auto_groups,
-                                   ::SMESH::MED_VERSION        version,
-                                   ::CORBA::Boolean            overwrite,
-                                   ::CORBA::Boolean            autoDimension)
+void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
+                                   const char*               file,
+                                   CORBA::Boolean            auto_groups,
+                                   SMESH::MED_VERSION        version,
+                                   CORBA::Boolean            overwrite,
+                                   CORBA::Boolean            autoDimension,
+                                   const GEOM::ListOfFields& fields,
+                                   const char*               geomAssocFields)
   throw (SALOME::SALOME_Exception)
 {
-  Unexpect aCatch(SALOME_SalomeException);
-  TPythonDump pyDump;
+  SMESH_TRY;
+  if ( _preMeshInfo )
+    _preMeshInfo->FullLoadFromFile();
+
+  // check fields
+  bool have0dField = false;
+  if ( fields.length() > 0 )
+  {
+    GEOM::GEOM_Object_var shapeToMesh = GetShapeToMesh();
+    if ( shapeToMesh->_is_nil() )
+      THROW_SALOME_CORBA_EXCEPTION( "No shape to mesh", SALOME::INTERNAL_ERROR );
+
+    for ( size_t i = 0; i < fields.length(); ++i )
+    {
+      if ( fields[i]->GetDataType() == GEOM::FDT_String )
+        THROW_SALOME_CORBA_EXCEPTION
+          ( "Export of string fields is not supported", SALOME::BAD_PARAM);
+      GEOM::GEOM_Object_var fieldShape = fields[i]->GetShape();
+      if ( fieldShape->_is_nil() )
+        THROW_SALOME_CORBA_EXCEPTION( "Null shape under a field", SALOME::INTERNAL_ERROR );
+      if ( !fieldShape->IsSame( shapeToMesh ) )
+        THROW_SALOME_CORBA_EXCEPTION
+          ( "Field defined not on shape", SALOME::BAD_PARAM);
+      if ( fields[i]->GetDimension() == 0 )
+        have0dField = true;
+    }
+    if ( geomAssocFields )
+      for ( int i = 0; geomAssocFields[i]; ++i )
+        switch ( geomAssocFields[i] ) {
+        case 'v':case 'e':case 'f':case 's': break;
+        case 'V':case 'E':case 'F':case 'S': break;
+        default: THROW_SALOME_CORBA_EXCEPTION
+            ( "geomAssocFields can include only [vefs] characters", SALOME::BAD_PARAM);
+        }
+  }
+
+  SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
 
-  if ( SMESH_Mesh_i * mesh = SMESH::DownCast< SMESH_Mesh_i* >( meshPart ))
+  // write mesh
+
+  string aMeshName = "Mesh";
+  SMESHUtils::Deleter< SMESH_MeshPartDS > tmpDSDeleter(0);
+  if ( CORBA::is_nil( meshPart ) ||
+       SMESH::DownCast< SMESH_Mesh_i* >( meshPart ))
   {
-    mesh->ExportToMEDX( file, auto_groups, version, autoDimension );
+    aMeshName = prepareMeshNameAndGroups(file, overwrite);
+    _impl->ExportMED( file, aMeshName.c_str(), auto_groups,
+                      version, 0, autoDimension, /*addODOnVertices=*/have0dField);
+    meshDS = _impl->GetMeshDS();
   }
   else
   {
@@ -2872,7 +3055,6 @@ void SMESH_Mesh_i::ExportPartToMED(::SMESH::SMESH_IDSource_ptr meshPart,
 
     PrepareForWriting(file, overwrite);
 
-    string aMeshName = "Mesh";
     SALOMEDS::Study_var aStudy = _gen_i->GetCurrentStudy();
     if ( !aStudy->_is_nil() ) {
       SALOMEDS::SObject_wrap SO = _gen_i->ObjectToSObject( aStudy, meshPart );
@@ -2881,13 +3063,287 @@ void SMESH_Mesh_i::ExportPartToMED(::SMESH::SMESH_IDSource_ptr meshPart,
         aMeshName = name;
       }
     }
-    SMESH_MeshPartDS partDS( meshPart );
-    _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version, &partDS, autoDimension );
+    SMESH_MeshPartDS* partDS = new SMESH_MeshPartDS( meshPart );
+    _impl->ExportMED( file, aMeshName.c_str(), auto_groups,
+                      version, partDS, autoDimension, /*addODOnVertices=*/have0dField);
+    meshDS = tmpDSDeleter._obj = partDS;
+  }
+
+  // write fields
+
+  if ( _impl->HasShapeToMesh() )
+  {
+    DriverMED_W_Field fieldWriter;
+    fieldWriter.SetFile( file );
+    fieldWriter.SetMeshName( aMeshName );
+    fieldWriter.AddODOnVertices( have0dField );
+
+    exportMEDFields( fieldWriter, meshDS, fields, geomAssocFields );
   }
-  pyDump << SMESH::SMESH_Mesh_var(_this()) << ".ExportPartToMED( "
-         << meshPart << ", r'" << file << "', "
-         << auto_groups << ", " << version << ", " << overwrite << ", "
-         << autoDimension << " )";
+
+  // dump
+  GEOM::ListOfGBO_var goList = new GEOM::ListOfGBO;
+  goList->length( fields.length() );
+  for ( size_t i = 0; i < fields.length(); ++i )
+  {
+    GEOM::GEOM_BaseObject_var gbo = GEOM::GEOM_BaseObject::_narrow( fields[i] );
+    goList[i] = gbo;
+  }
+  TPythonDump() << _this() << ".ExportPartToMED( "
+                << meshPart << ", r'" << file << "', "
+                << auto_groups << ", " << version << ", " << overwrite << ", "
+                << autoDimension << ", " << goList
+                << ", '" << ( geomAssocFields ? geomAssocFields : "" ) << "'" << " )";
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+}
+
+//================================================================================
+/*!
+ * Write GEOM fields to MED file
+ */
+//================================================================================
+
+void SMESH_Mesh_i::exportMEDFields( DriverMED_W_Field&        fieldWriter,
+                                    SMESHDS_Mesh*             meshDS,
+                                    const GEOM::ListOfFields& fields,
+                                    const char*               geomAssocFields)
+{
+#define METH "SMESH_Mesh_i::exportMEDFields() "
+
+  if (( fields.length() < 1 ) &&
+      ( !geomAssocFields || !geomAssocFields[0] ))
+    return;
+
+  std::vector< double > dblVals( meshDS->MaxShapeIndex()+1 );
+  std::vector< int >    intVals( meshDS->MaxShapeIndex()+1 );
+  std::vector< int >    subIdsByDim[ 4 ];
+  const double noneDblValue = 0.;
+  const double noneIntValue = 0;
+
+  for ( size_t iF = 0; iF < fields.length(); ++iF )
+  {
+    // set field data
+
+    int dim = fields[ iF ]->GetDimension();
+    SMDSAbs_ElementType elemType;
+    TopAbs_ShapeEnum    shapeType;
+    switch ( dim ) {
+    case 0: elemType = SMDSAbs_0DElement; shapeType = TopAbs_VERTEX; break;
+    case 1: elemType = SMDSAbs_Edge;      shapeType = TopAbs_EDGE;   break;
+    case 2: elemType = SMDSAbs_Face;      shapeType = TopAbs_FACE;   break;
+    case 3: elemType = SMDSAbs_Volume;    shapeType = TopAbs_SOLID;  break;
+    default:
+      continue; // skip fields on whole shape
+    }
+    GEOM::field_data_type dataType = fields[ iF ]->GetDataType();
+    if ( dataType == GEOM::FDT_String )
+      continue;
+    GEOM::ListOfLong_var stepIDs = fields[ iF ]->GetSteps();
+    if ( stepIDs->length() < 1 )
+      continue;
+    GEOM::string_array_var comps = fields[ iF ]->GetComponents();
+    if ( comps->length() < 1 )
+      continue;
+    CORBA::String_var       name = fields[ iF ]->GetName();
+
+    if ( !fieldWriter.Set( meshDS,
+                           name.in(),
+                           elemType,
+                           comps->length(),
+                           /*isIntData=*/false ))//( dataType == GEOM::FDT_Int )))
+      continue;
+
+    for ( size_t iC = 0; iC < comps->length(); ++iC )
+      fieldWriter.SetCompName( iC, comps[ iC ].in() );
+
+    // find sub-shape IDs
+
+    std::vector< int >& subIds = subIdsByDim[ dim ];
+    if ( subIds.empty() )
+      for ( int id = 1; id <= meshDS->MaxShapeIndex(); ++id )
+        if ( meshDS->IndexToShape( id ).ShapeType() == shapeType )
+          subIds.push_back( id );
+
+    // write steps
+
+    SMDS_ElemIteratorPtr elemIt = fieldWriter.GetOrderedElems();
+    if ( !elemIt )
+      continue;
+
+    for ( size_t iS = 0; iS < stepIDs->length(); ++iS )
+    {
+      GEOM::GEOM_FieldStep_var step = fields[ iF ]->GetStep( stepIDs[ iS ]);
+      if ( step->_is_nil() )
+        continue;
+
+      CORBA::Long stamp = step->GetStamp();
+      CORBA::Long id    = step->GetID();
+      fieldWriter.SetDtIt( int( stamp ), int( id ));
+
+      // fill dblVals or intVals
+      switch ( dataType )
+      {
+      case GEOM::FDT_Double:
+      {
+        GEOM::GEOM_DoubleFieldStep_var dblStep = GEOM::GEOM_DoubleFieldStep::_narrow( step );
+        if ( dblStep->_is_nil() ) continue;
+        GEOM::ListOfDouble_var vv = dblStep->GetValues();
+        if ( vv->length() != subIds.size() )
+          THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
+        for ( size_t i = 0; i < vv->length(); ++i )
+          dblVals[ subIds[ i ]] = vv[ i ];
+        break;
+      }
+      case GEOM::FDT_Int:
+      {
+        GEOM::GEOM_IntFieldStep_var intStep = GEOM::GEOM_IntFieldStep::_narrow( step );
+        if ( intStep->_is_nil() ) continue;
+        GEOM::ListOfLong_var vv = intStep->GetValues();
+        if ( vv->length() != subIds.size() )
+          THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
+        for ( size_t i = 0; i < vv->length(); ++i )
+          intVals[ subIds[ i ]] = (int) vv[ i ];
+        break;
+      }
+      case GEOM::FDT_Bool:
+      {
+        GEOM::GEOM_BoolFieldStep_var boolStep = GEOM::GEOM_BoolFieldStep::_narrow( step );
+        if ( boolStep->_is_nil() ) continue;
+        GEOM::short_array_var vv = boolStep->GetValues();
+        if ( vv->length() != subIds.size() )
+          THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
+        for ( size_t i = 0; i < vv->length(); ++i )
+          intVals[ subIds[ i ]] = (int) vv[ i ];
+        break;
+      }
+      default: continue;
+      }
+
+      // pass values to fieldWriter
+      elemIt = fieldWriter.GetOrderedElems();
+      if ( dataType == GEOM::FDT_Double )
+        while ( elemIt->more() )
+        {
+          const SMDS_MeshElement* e = elemIt->next();
+          const int shapeID = e->getshapeId();
+          if ( shapeID < 1 || shapeID >= dblVals.size() )
+            fieldWriter.AddValue( noneDblValue );
+          else
+            fieldWriter.AddValue( dblVals[ shapeID ]);
+        }
+      else
+        while ( elemIt->more() )
+        {
+          const SMDS_MeshElement* e = elemIt->next();
+          const int shapeID = e->getshapeId();
+          if ( shapeID < 1 || shapeID >= intVals.size() )
+            fieldWriter.AddValue( (double) noneIntValue );
+          else
+            fieldWriter.AddValue( (double) intVals[ shapeID ]);
+        }
+
+      // write a step
+      fieldWriter.Perform();
+      SMESH_ComputeErrorPtr res = fieldWriter.GetError();
+      if ( res && res->IsKO() )
+      {
+        if ( res->myComment.empty() )
+        { THROW_SALOME_CORBA_EXCEPTION( METH "Fatal error", SALOME::INTERNAL_ERROR ); }
+        else
+        { THROW_SALOME_CORBA_EXCEPTION( res->myComment.c_str(), SALOME::INTERNAL_ERROR ); }
+      }
+
+    } // loop on steps
+  } // loop on fields
+
+  if ( !geomAssocFields || !geomAssocFields[0] )
+    return;
+
+  // write geomAssocFields
+
+  std::vector< int > shapeDim( TopAbs_SHAPE + 1 );
+  shapeDim[ TopAbs_COMPOUND  ] = 3;
+  shapeDim[ TopAbs_COMPSOLID ] = 3;
+  shapeDim[ TopAbs_SOLID     ] = 3;
+  shapeDim[ TopAbs_SHELL     ] = 2;
+  shapeDim[ TopAbs_FACE      ] = 2;
+  shapeDim[ TopAbs_WIRE      ] = 1;
+  shapeDim[ TopAbs_EDGE      ] = 1;
+  shapeDim[ TopAbs_VERTEX    ] = 0;
+  shapeDim[ TopAbs_SHAPE     ] = 3;
+
+  for ( int iF = 0; geomAssocFields[ iF ]; ++iF )
+  {
+    std::vector< std::string > compNames;
+    switch ( geomAssocFields[ iF ]) {
+    case 'v': case 'V':
+      fieldWriter.Set( meshDS, "_vertices_", SMDSAbs_Node, /*nbComps=*/2, /*isInt=*/false );
+      compNames.push_back( "dim" );
+      break;
+    case 'e': case 'E':
+      fieldWriter.Set( meshDS, "_edges_", SMDSAbs_Edge, /*nbComps=*/1, /*isInt=*/false );
+      break;
+    case 'f': case 'F':
+      fieldWriter.Set( meshDS, "_faces_", SMDSAbs_Face, /*nbComps=*/1, /*isInt=*/false );
+      break;
+    case 's': case 'S':
+      fieldWriter.Set( meshDS, "_solids_", SMDSAbs_Volume, /*nbComps=*/1, /*isInt=*/false );
+      break;
+    default: continue;
+    }
+    compNames.push_back( "id" );
+    for ( size_t iC = 0; iC < compNames.size(); ++iC )
+      fieldWriter.SetCompName( iC, compNames[ iC ].c_str() );
+
+    fieldWriter.SetDtIt( -1, -1 );
+
+    SMDS_ElemIteratorPtr elemIt = fieldWriter.GetOrderedElems();
+    if ( !elemIt )
+      continue;
+
+    if ( compNames.size() == 2 ) // _vertices_
+      while ( elemIt->more() )
+      {
+        const SMDS_MeshElement* e = elemIt->next();
+        const int shapeID = e->getshapeId();
+        if ( shapeID < 1 )
+        {
+          fieldWriter.AddValue( (double) -1 );
+          fieldWriter.AddValue( (double) -1 );
+        }
+        else
+        {
+          const TopoDS_Shape& S = meshDS->IndexToShape( shapeID );
+          fieldWriter.AddValue( (double) ( S.IsNull() ? -1 : shapeDim[ S.ShapeType() ]));
+          fieldWriter.AddValue( (double) shapeID );
+        }
+      }
+    else
+      while ( elemIt->more() )
+      {
+        const SMDS_MeshElement* e = elemIt->next();
+        const int shapeID = e->getshapeId();
+        if ( shapeID < 1 )
+          fieldWriter.AddValue( (double) -1 );
+        else
+          fieldWriter.AddValue( (double) shapeID );
+      }
+
+    // write a step
+    fieldWriter.Perform();
+    SMESH_ComputeErrorPtr res = fieldWriter.GetError();
+    if ( res && res->IsKO() )
+    {
+      if ( res->myComment.empty() )
+      { THROW_SALOME_CORBA_EXCEPTION( METH "Fatal error", SALOME::INTERNAL_ERROR ); }
+      else
+      { THROW_SALOME_CORBA_EXCEPTION( res->myComment.c_str(), SALOME::INTERNAL_ERROR ); }
+    }
+
+  } // loop on geomAssocFields
+
+#undef METH
 }
 
 //================================================================================
@@ -3682,17 +4138,11 @@ SMESH::long_array* SMESH_Mesh_i::GetNodeInverseElements(const CORBA::Long id)
 
   // find inverse elements
   SMDS_ElemIteratorPtr eIt = aNode->GetInverseElementIterator();
-  TColStd_SequenceOfInteger IDs;
-  while(eIt->more()) {
+  aResult->length( aNode->NbInverseElements() );  
+  for( int i = 0; eIt->more(); ++i )
+  {
     const SMDS_MeshElement* elem = eIt->next();
-    IDs.Append(elem->GetID());
-  }
-  if(IDs.Length()>0) {
-    aResult->length(IDs.Length());
-    int i = 1;
-    for(; i<=IDs.Length(); i++) {
-      aResult[i-1] = IDs.Value(i);
-    }
+    aResult[ i ] = elem->GetID();
   }
   return aResult._retn();
 }
@@ -4048,7 +4498,8 @@ SMESH::long_array* SMESH_Mesh_i::GetElemFaceNodes(CORBA::Long  elemId,
 //purpose  : Returns three components of normal of given mesh face.
 //=======================================================================
 
-SMESH::double_array* SMESH_Mesh_i::GetFaceNormal(CORBA::Long  elemId)
+SMESH::double_array* SMESH_Mesh_i::GetFaceNormal(CORBA::Long    elemId,
+                                                 CORBA::Boolean normalized)
 {
   if ( _preMeshInfo )
     _preMeshInfo->FullLoadFromFile();
@@ -4058,7 +4509,7 @@ SMESH::double_array* SMESH_Mesh_i::GetFaceNormal(CORBA::Long  elemId)
   if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
   {
     gp_XYZ normal;
-    if ( SMESH_MeshAlgos::FaceNormal( mesh->FindElement(elemId), normal, /*normalized=*/true ))
+    if ( SMESH_MeshAlgos::FaceNormal( mesh->FindElement(elemId), normal, normalized ))
     {
       aResult->length( 3 );
       aResult[ 0 ] = normal.X();
@@ -5099,8 +5550,37 @@ void findCommonSubMesh (list<const SMESH_subMesh*>& theSubMeshList,
   //theCommon.insert( theSubMesh );
 }
 
+//-----------------------------------------------------------------------------
+bool isSubMeshInList ( int smID, const TListOfListOfInt& smLists )
+{
+  TListOfListOfInt::const_iterator listsIt = smLists.begin();
+  for ( ; listsIt != smLists.end(); ++listsIt )
+  {
+    const TListOfInt& smIDs = *listsIt;
+    if ( std::find( smIDs.begin(), smIDs.end(), smID ) != smIDs.end() )
+      return true;
+  }
+  return false;
+}
+
 } // namespace
 
+//=============================================================================
+/*!
+ * \brief Return \c true if a meshing order not yet set for a concurrent sub-mesh
+ */
+//=============================================================================
+
+CORBA::Boolean SMESH_Mesh_i::IsUnorderedSubMesh(CORBA::Long submeshID)
+{
+  TListOfListOfInt anOrder = GetImpl().GetMeshOrder(); // already defined order
+  if ( isSubMeshInList( submeshID, anOrder ))
+    return false;
+
+  TListOfListOfInt allConurrent = findConcurrentSubMeshes();
+  return isSubMeshInList( submeshID, allConurrent );
+}
+
 //=============================================================================
 /*!
  * \brief Return submesh objects list in meshing order
@@ -5114,14 +5594,37 @@ SMESH::submesh_array_array* SMESH_Mesh_i::GetMeshOrder()
   SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
   if ( !aMeshDS )
     return aResult._retn();
-  
-  ::SMESH_Mesh& mesh = GetImpl();
-  TListOfListOfInt anOrder = mesh.GetMeshOrder(); // is there already defined order?
-  if ( !anOrder.size() ) {
 
+  TListOfListOfInt      anOrder = GetImpl().GetMeshOrder(); // already defined order
+  TListOfListOfInt allConurrent = findConcurrentSubMeshes();
+  anOrder.splice( anOrder.end(), allConurrent );
+
+  int listIndx = 0;
+  TListOfListOfInt::iterator listIt = anOrder.begin();
+  for(; listIt != anOrder.end(); listIt++, listIndx++ )
+    unionLists( *listIt,  anOrder, listIndx + 1 );
+
+  // convert submesh ids into interface instances
+  //  and dump command into python
+  convertMeshOrder( anOrder, aResult, false );
+
+  return aResult._retn();
+}
+
+//=============================================================================
+/*!
+ * \brief Finds concurrent sub-meshes
+ */
+//=============================================================================
+
+TListOfListOfInt SMESH_Mesh_i::findConcurrentSubMeshes()
+{
+  TListOfListOfInt anOrder;
+  ::SMESH_Mesh& mesh = GetImpl();
+  {
     // collect submeshes and detect concurrent algorithms and hypothesises
     TDimHypList dimHypListArr[4]; // dimHyp list for each shape dimension
-    
+
     map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
     for ( ; i_sm != _mapSubMesh.end(); i_sm++ ) {
       ::SMESH_subMesh* sm = (*i_sm).second;
@@ -5193,11 +5696,8 @@ SMESH::submesh_array_array* SMESH_Mesh_i::GetMeshOrder()
     for(; listIt != anOrder.end(); listIt++, listIndx++ )
       unionLists( *listIt,  anOrder, listIndx + 1 );
   }
-  // convert submesh ids into interface instances
-  //  and dump command into python
-  convertMeshOrder( anOrder, aResult, false );
 
-  return aResult._retn();
+  return anOrder;
 }
 
 //=============================================================================
@@ -5223,6 +5723,8 @@ SMESH::submesh_array_array* SMESH_Mesh_i::GetMeshOrder()
   {
     const SMESH::submesh_array& aSMArray = theSubMeshArray[i];
     TListOfInt subMeshIds;
+    if ( i > 0 )
+      aPythonDump << ", ";
     aPythonDump << "[ ";
     // Collect subMeshes which should be clear
     //  do it list-by-list, because modification of submesh order
@@ -5286,7 +5788,8 @@ void SMESH_Mesh_i::convertMeshOrder (const TListOfListOfInt&     theIdsOrder,
     SMESH::submesh_array_var aResSubSet = new SMESH::submesh_array();
     aResSubSet->length(aSubOrder.size());
     TListOfInt::const_iterator subIt = aSubOrder.begin();
-    for( int j = 0; subIt != aSubOrder.end(); subIt++ ) {
+    int j;
+    for( j = 0; subIt != aSubOrder.end(); subIt++ ) {
       if ( _mapSubMeshIor.find(*subIt) == _mapSubMeshIor.end() )
         continue;
       SMESH::SMESH_subMesh_var subMesh =
@@ -5300,7 +5803,8 @@ void SMESH_Mesh_i::convertMeshOrder (const TListOfListOfInt&     theIdsOrder,
     }
     if ( theIsDump )
       aPythonDump << " ]";
-    theResOrder[ listIndx++ ] = aResSubSet;
+    if ( j > 1 )
+      theResOrder[ listIndx++ ] = aResSubSet;
   }
   // correct number of lists
   theResOrder.length( listIndx );