Salome HOME
0020511: EDF 1101 SMESH : Add CGNS to Mesh Format Supported
authoreap <eap@opencascade.com>
Wed, 10 Aug 2011 10:10:26 +0000 (10:10 +0000)
committereap <eap@opencascade.com>
Wed, 10 Aug 2011 10:10:26 +0000 (10:10 +0000)
doc/salome/gui/SMESH/input/importing_exporting_meshes.doc
doc/salome/gui/SMESH/input/index.doc
src/DriverCGNS/DriverCGNS_Read.cxx [new file with mode: 0644]
src/DriverCGNS/DriverCGNS_Read.hxx [new file with mode: 0644]
src/DriverCGNS/DriverCGNS_Write.cxx [new file with mode: 0644]
src/DriverCGNS/DriverCGNS_Write.hxx [new file with mode: 0644]
src/DriverCGNS/Makefile.am [new file with mode: 0644]
src/DriverCGNS/SMESH_DriverCGNS.hxx [new file with mode: 0755]

index cdedf8d33b6dbe276ad194beb0116365e7cce74b..52ff261e3369b7ab05245de380fa92049d434aa9 100644 (file)
@@ -3,15 +3,15 @@
 \page importing_exporting_meshes_page Importing and exporting meshes
 
 \n In MESH there is a functionality allowing importation/exportation
-of meshes from/to \b MED, \b UNV (I-DEAS 10), \b DAT (Nastran) and STL
-format files. You can also export a group as a whole mesh.
+of meshes from/to \b MED, \b UNV (I-DEAS 10), \b DAT (Nastran), \b STL
+and \b CGNS format files. You can also export a group as a whole mesh.
 
 
 <em>To import a mesh:</em>
 
 <ol>
 <li>From the \b File menu choose the \b Import item, from its sub-menu
-select the corresponding format (MED, UNV and DAT) of the file containing
+select the corresponding format (MED, UNV, DAT, STL and CGNS) of the file containing
 your mesh.</li>
 <li>In the standard <b>Search File</b> dialog box find the file for
 importation. It is possible to select multiple files to be imported all at once. </li>
@@ -26,8 +26,8 @@ importation. It is possible to select multiple files to be imported all at once.
 <ol>
 <li>Select the object you wish to export.</li>
 <li>From the \b File menu choose the \b Export item, from its sub-menu
-select the format (MED, UNV, DAT and STL) of the file which will contain your
-exported mesh.</li>
+select the format (MED, UNV, DAT, STL and CGNS) of the file which will
+contain your exported mesh.</li>
 <li>In the standard <b>Search File</b> select a location for the
 exported file and enter its name.</li>
 <li>Click the \b OK button.</li>
index 2522b5bcb59cc3b287b405b0672006867c894bb2..776dbeafe9f70ea38c34ff95413978b3e2eed3fe 100644 (file)
@@ -6,7 +6,7 @@
 
 \n \b MESH module of SALOME is destined for:
 <ul>
-<li>\ref importing_exporting_meshes_page "import and export of meshes in MED format";</li>
+<li>\ref importing_exporting_meshes_page "import and export of meshes in different formats";</li>
 <li>\subpage about_meshes_page "meshing geometrical models"
 previously created or imported by the Geometry component; </li>
 <li>\subpage viewing_meshes_overview_page "viewing created meshes" in
diff --git a/src/DriverCGNS/DriverCGNS_Read.cxx b/src/DriverCGNS/DriverCGNS_Read.cxx
new file mode 100644 (file)
index 0000000..f051d55
--- /dev/null
@@ -0,0 +1,1184 @@
+// Copyright (C) 2007-2011  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
+//
+// 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.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+// File      : DriverCGNS_Read.cxx
+// Created   : Thu Jun 30 10:33:31 2011
+// Author    : Edward AGAPOV (eap)
+
+#include "DriverCGNS_Read.hxx"
+
+#include "SMDS_MeshNode.hxx"
+#include "SMESHDS_Group.hxx"
+#include "SMESHDS_Mesh.hxx"
+#include "SMESH_Comment.hxx"
+
+#include <gp_XYZ.hxx>
+
+#include <cgnslib.h>
+
+#include <map>
+
+#if CGNS_VERSION < 3100
+# define cgsize_t int
+#endif
+
+#define NB_ZONE_SIZE_VAL 9
+#define CGNS_NAME_SIZE 33
+#define CGNS_STRUCT_RANGE_SZ 6
+
+using namespace std;
+
+namespace
+{
+  //================================================================================
+  /*!
+   * \brief Data of a zone
+   */
+  struct TZoneData
+  {
+    int                    _id;
+    int                    _nodeIdShift; // nb nodes in previously read zones
+    int                    _elemIdShift; // nb faces in previously read zones
+    int                    _nbNodes, _nbElems;
+    int                    _meshDim;
+    int                    _sizeX, _sizeY, _sizeZ, _nbCells; // structured
+    cgsize_t               _sizes[NB_ZONE_SIZE_VAL];
+    CGNS_ENUMT(ZoneType_t) _type;
+    map< int, int >        _nodeReplacementMap;/* key:   id of node to replace (in this zone),
+                                                  value: id of node to replace by (in another zone)
+                                                  id values include _nodeIdShift of the zones */
+    void SetSizeAndDim( cgsize_t* sizes, int meshDim )
+    {
+      _meshDim = meshDim;
+      memcpy( _sizes, sizes, NB_ZONE_SIZE_VAL*sizeof(cgsize_t));
+      _sizeX = _sizes[0];
+      _sizeY = _meshDim > 1 ? _sizes[1] : 0;
+      _sizeZ = _meshDim > 2 ? _sizes[2] : 0;
+      _nbCells = (_sizeX - 1) * ( _meshDim > 1 ? _sizeY : 1 ) * ( _meshDim > 2 ? _sizeZ : 1 );
+    }
+    bool IsStructured() const { return ( _type == CGNS_ENUMV( Structured )); }
+    int IndexSize() const { return IsStructured() ? _meshDim : 1; }
+    string ReadZonesConnection(int file, int base, const map< string, TZoneData >& zonesByName);
+    void ReplaceNodes( int* ids, int nbIds, int idShift = 0 ) const;
+
+    // Methods for a structured zone
+
+    int NodeID( int i, int j, int k = 1 ) const
+    {
+      return _nodeIdShift + (k-1)*_sizeX*_sizeY + (j-1)*_sizeX + i;
+    }
+    int NodeID( const gp_XYZ& ijk ) const
+    {
+      return NodeID( int(ijk.X()), int(ijk.Y()), int(ijk.Z()));
+    }
+    void CellNodes( int i, int j, int k, cgsize_t* ids ) const
+    {
+      ids[0] = NodeID( i  , j  , k  );
+      ids[1] = NodeID( i  , j+1, k  );
+      ids[2] = NodeID( i+1, j+1, k  );
+      ids[3] = NodeID( i+1, j  , k  );
+      ids[4] = NodeID( i  , j  , k+1);
+      ids[5] = NodeID( i  , j+1, k+1);
+      ids[6] = NodeID( i+1, j+1, k+1);
+      ids[7] = NodeID( i+1, j  , k+1);
+    }
+    void CellNodes( int i, int j, cgsize_t* ids ) const
+    {
+      ids[0] = NodeID( i  , j   );
+      ids[1] = NodeID( i  , j+1 );
+      ids[2] = NodeID( i+1, j+1 );
+      ids[3] = NodeID( i+1, j   );
+    }
+    void IFaceNodes( int i, int j, int k, cgsize_t* ids ) const // face perpendiculaire to X (3D)
+    {
+      ids[0] = NodeID( i, j, k );
+      ids[1] = ids[0] + _sizeX*( i==_sizeX ? 1 : _sizeY );
+      ids[2] = ids[0] + _sizeX*( _sizeY + 1 );
+      ids[3] = ids[0] + _sizeX*( i==_sizeX ? _sizeY : 1 );
+    }
+    void JFaceNodes( int i, int j, int k, cgsize_t* ids ) const
+    {
+      ids[0] = NodeID( i, j, k );
+      ids[1] = ids[0] + ( j==_sizeY ? _sizeX*_sizeY : 1);
+      ids[2] = ids[0] + _sizeX*_sizeY + 1;
+      ids[3] = ids[0] + ( j==_sizeY ? 1 : _sizeX*_sizeY);
+    }
+    void KFaceNodes( int i, int j, int k, cgsize_t* ids ) const
+    {
+      ids[0] = NodeID( i, j, k );
+      ids[1] = ids[0] + ( k==_sizeZ ? 1 : _sizeX);
+      ids[2] = ids[0] + _sizeX + 1;
+      ids[3] = ids[0] + ( k==_sizeZ ? _sizeX : 1);
+    }
+    void IEdgeNodes( int i, int j, int k, cgsize_t* ids ) const // edge perpendiculaire to X (2D)
+    {
+      ids[0] = NodeID( i, j, 0 );
+      ids[1] = ids[0] + _sizeX;
+    }
+    void JEdgeNodes( int i, int j, int k, cgsize_t* ids ) const
+    {
+      ids[0] = NodeID( i, j, 0 );
+      ids[1] = ids[0] + 1;
+    }
+#define gpXYZ2IJK(METHOD)                                     \
+    void METHOD( const gp_XYZ& ijk, cgsize_t* ids ) const {        \
+      METHOD( int(ijk.X()), int(ijk.Y()), int(ijk.Z()), ids); \
+    }
+    gpXYZ2IJK( IFaceNodes )
+    gpXYZ2IJK( JFaceNodes )
+    gpXYZ2IJK( KFaceNodes )
+    gpXYZ2IJK( IEdgeNodes )
+    gpXYZ2IJK( JEdgeNodes )
+  };
+
+  //================================================================================
+  /*!
+   * \brief Iterator over nodes of the structired grid using FORTRAN multidimensional
+   * array ordering.
+   */
+  class TPointRangeIterator
+  {
+    int _beg[3], _end[3], _cur[3], _dir[3], _dim;
+    bool _more;
+  public:
+    TPointRangeIterator( const cgsize_t* range, int dim ):_dim(dim)
+    {
+      _more = false;
+      for ( int i = 0; i < dim; ++i )
+      {
+        _beg[i] = range[i];
+        _end[i] = range[i+dim];
+        _dir[i] = _end[i] < _beg[i] ? -1 : 1;
+        _end[i] += _dir[i];
+        _cur[i] = _beg[i];
+        if ( _end[i] - _beg[i] )
+          _more = true;
+      }
+//       for ( int i = dim; i < 3; ++i )
+//         _cur[i] = _beg[i] = _end[i] = _dir[i] = 0;
+    }
+    bool More() const
+    {
+      return _more;
+    }
+    gp_XYZ Next()
+    {
+      gp_XYZ res( _cur[0], _cur[1], _cur[2] );
+      for ( int i = 0; i < _dim; ++i )
+      {
+        _cur[i] += _dir[i];
+        if ( _cur[i]*_dir[i] < _end[i]*_dir[i] )
+          break;
+        if ( i+1 < _dim )
+          _cur[i] = _beg[i];
+        else
+          _more = false;
+      }
+      return res;
+    }
+    size_t Size()  const
+    {
+      size_t size = 1;
+      for ( int i = 0; i < _dim; ++i )
+        size *= _dir[i]*(_end[i]-_beg[i]);
+      return size;
+    }
+    gp_XYZ Begin() const { return gp_XYZ( _beg[0], _beg[1], _beg[2] ); }
+    //gp_XYZ End() const { return gp_XYZ( _end[0]-1, _end[1]-1, _end[2]-1 ); }
+  };
+
+  //================================================================================
+  /*!
+   * \brief Reads zone interface connectivity
+   *  \param file - file to read
+   *  \param base - base to read
+   *  \param zone - zone to replace nodes in
+   *  \param zonesByName - TZoneData by name
+   *  \retval string - warning message
+   *
+   * see // http://www.grc.nasa.gov/WWW/cgns/CGNS_docs_current/sids/cnct.html
+   */
+  //================================================================================
+
+  string TZoneData::ReadZonesConnection( int                             file,
+                                         int                             base,
+                                         const map< string, TZoneData >& zonesByName)
+  {
+    string error;
+
+    char connectName[ CGNS_NAME_SIZE ], donorName [ CGNS_NAME_SIZE ];
+
+    // ----------------------------
+    // read zone 1 to 1 interfaces
+    // ----------------------------
+    if ( IsStructured() )
+    {
+      int nb1to1 = 0;
+      if ( cg_n1to1 ( file, base, _id, &nb1to1) == CG_OK )
+      {
+        cgsize_t range[CGNS_STRUCT_RANGE_SZ], donorRange[CGNS_STRUCT_RANGE_SZ];
+        int transform[3] = {0,0,0};
+
+        for ( int I = 1; I <= nb1to1; ++I )
+        {
+          if ( cg_1to1_read(file, base, _id, I, connectName,
+                            donorName, range, donorRange, transform) == CG_OK )
+          {
+            map< string, TZoneData>::const_iterator n_z = zonesByName.find( donorName );
+            if ( n_z == zonesByName.end() )
+              continue; // donor zone not yet read
+            const TZoneData& zone2 = n_z->second;
+
+            // set up matrix to transform ijk of the zone to ijk of the zone2
+            gp_Mat T;
+            for ( int i = 0; i < _meshDim; ++i )
+              if ( transform[i] )
+              {
+                int row = Abs(transform[i]);
+                int col = i+1;
+                int val = transform[i] > 0 ? +1 : -1;
+                T( row, col ) = val;
+              }
+
+            // fill nodeReplacementMap
+            TPointRangeIterator rangeIt1( range, _meshDim );
+            TPointRangeIterator rangeIt2( donorRange, _meshDim );
+            gp_XYZ begin1 = rangeIt1.Begin(), begin2 = rangeIt2.Begin(), index1, index2;
+            if ( &zone2 == this )
+            {
+              // not to read twice the same interface with self
+              TPointRangeIterator rangeIt1bis( range, _meshDim );
+              if ( rangeIt1bis.More() )
+              {
+                index1 = rangeIt1bis.Next();
+                index2 = T * ( index1 - begin1 ) + begin2;
+                int node1 = NodeID( index1 );
+                int node2 = zone2.NodeID( index2 );
+                if ( _nodeReplacementMap.count( node2 ) &&
+                     _nodeReplacementMap[ node2 ] == node1 )
+                  continue; // this interface already read
+              }
+            }
+            while ( rangeIt1.More() )
+            {
+              index1 = rangeIt1.Next();
+              index2 = T * ( index1 - begin1 ) + begin2;
+              int node1 = NodeID( index1 );
+              int node2 = zone2.NodeID( index2 );
+              _nodeReplacementMap.insert( make_pair( node1, node2 ));
+            }
+          }
+          else
+          {
+            error = cg_get_error();
+          }
+        }
+      }
+      else
+      {
+        error = cg_get_error();
+      }
+    }
+
+    // ---------------------------------
+    // read general zone connectivities
+    // ---------------------------------
+    int nbConn = 0;
+    if ( cg_nconns( file, base, _id, &nbConn) == CG_OK )
+    {
+      cgsize_t nb, donorNb;
+      CGNS_ENUMT(GridLocation_t) location;
+      CGNS_ENUMT(GridConnectivityType_t) connectType;
+      CGNS_ENUMT(PointSetType_t) ptype, donorPtype;
+      CGNS_ENUMT(ZoneType_t) donorZonetype;
+      CGNS_ENUMT(DataType_t) donorDatatype;
+
+      for ( int I = 1; I <= nbConn; ++I )
+      {
+        if ( cg_conn_info(file, base, _id, I, connectName, &location, &connectType,
+                          &ptype, &nb, donorName, &donorZonetype, &donorPtype,
+                          &donorDatatype, &donorNb ) == CG_OK )
+        {
+          if ( location != CGNS_ENUMV( Vertex ))
+            continue; // we do not support cell-to-cell connectivity
+          if ( ptype != CGNS_ENUMV( PointList ) &&
+               ptype != CGNS_ENUMV( PointRange ))
+            continue;
+          if ( donorPtype != CGNS_ENUMV( PointList ) &&
+               donorPtype != CGNS_ENUMV( PointRange ))
+            continue;
+          
+          map< string, TZoneData>::const_iterator n_z = zonesByName.find( donorName );
+          if ( n_z == zonesByName.end() )
+            continue; // donor zone not yet read
+          const TZoneData& zone2 = n_z->second;
+
+          vector< int > ids( nb * IndexSize() );
+          vector< int > donorIds( donorNb * zone2.IndexSize() );
+          if (cg_conn_read ( file, base, _id, I,
+                             &ids[0], CGNS_ENUMV(Integer), &donorIds[0]) == CG_OK )
+          {
+            for ( int isThisZone = 0; isThisZone < 2; ++isThisZone )
+            {
+              const TZoneData&           zone = isThisZone ? *this : zone2;
+              CGNS_ENUMT(PointSetType_t) type = isThisZone ? ptype : donorPtype;
+              vector< int >&           points = isThisZone ? ids : donorIds;
+              if ( type == CGNS_ENUMV( PointRange ))
+              {
+                TPointRangeIterator rangeIt( &points[0], zone._meshDim );
+                points.clear();
+                while ( rangeIt.More() )
+                  points.push_back ( NodeID( rangeIt.Next() ));
+              }
+              else if ( zone.IsStructured() )
+              {
+                vector< int > resIDs; resIDs.reserve( points.size() / IndexSize() );
+                for ( size_t i = 0; i < points.size(); i += IndexSize() )
+                  resIDs.push_back( zone.NodeID( points[i+0], points[i+1], points[i+2] ));
+                resIDs.swap( points );
+              }
+              else if ( zone._nodeIdShift > 0 )
+              {
+                for ( size_t i = 0; i < points.size(); ++i )
+                  points[i] += zone._nodeIdShift;
+              }
+            }
+            for ( size_t i = 0; i < ids.size() && i < donorIds.size(); ++i )
+              _nodeReplacementMap.insert( make_pair( ids[i], donorIds[i] ));
+          }
+          else
+          {
+            error = cg_get_error();
+          }
+        }
+        else
+        {
+          error = cg_get_error();
+        }
+      }
+    }
+    else
+    {
+      error = cg_get_error();
+    }
+    return error;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Replaces node ids according to nodeReplacementMap to take into account
+   *        connection of zones
+   */
+  //================================================================================
+
+  void TZoneData::ReplaceNodes( cgsize_t* ids, int nbIds, int idShift/* = 0*/ ) const
+  {
+    if ( !_nodeReplacementMap.empty() )
+    {
+      map< int, int >::const_iterator it, end = _nodeReplacementMap.end();
+      for ( size_t i = 0; i < nbIds; ++i )
+        if (( it = _nodeReplacementMap.find( ids[i] + idShift)) != end )
+          ids[i] = it->second;
+        else
+          ids[i] += idShift;
+    }
+    else if ( idShift )
+    {
+      for ( size_t i = 0; i < nbIds; ++i )
+        ids[i] += idShift;
+    }
+  }
+  //================================================================================
+  /*!
+   * \brief functions adding an element of a particular type
+   */
+  SMDS_MeshElement* add_0D(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
+  {
+    return mesh->Add0DElementWithID( ids[0], ID );
+  }
+  SMDS_MeshElement* add_BAR_2(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
+  {
+    return mesh->AddEdgeWithID( ids[0], ids[1], ID );
+  }
+  SMDS_MeshElement* add_BAR_3(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
+  {
+    return mesh->AddEdgeWithID( ids[0], ids[1], ids[2], ID );
+  }
+  SMDS_MeshElement* add_TRI_3(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
+  {
+    return mesh->AddFaceWithID( ids[0], ids[2], ids[1], ID );
+  }
+  SMDS_MeshElement* add_TRI_6(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
+  {
+    return mesh->AddFaceWithID( ids[0], ids[2], ids[1], ids[5], ids[4], ids[3], ID );
+  }
+  SMDS_MeshElement* add_QUAD_4(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
+  {
+    return mesh->AddFaceWithID( ids[0], ids[3], ids[2], ids[1], ID );
+  }
+  SMDS_MeshElement* add_QUAD_8(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
+  {
+    return mesh->AddFaceWithID( ids[0],ids[3],ids[2],ids[1],ids[7],ids[6],ids[5],ids[4], ID );
+  }
+  SMDS_MeshElement* add_TETRA_4(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
+  {
+    return mesh->AddVolumeWithID( ids[0], ids[2], ids[1], ids[3], ID );
+  }
+  SMDS_MeshElement* add_TETRA_10(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
+  {
+    return mesh->AddVolumeWithID( ids[0],ids[2],ids[1],ids[3],ids[6],
+                                  ids[5],ids[4],ids[7],ids[9],ids[8], ID );
+  }
+  SMDS_MeshElement* add_PYRA_5(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
+  {
+    return mesh->AddVolumeWithID( ids[0],ids[3],ids[2],ids[1],ids[4],ID );
+  }
+  SMDS_MeshElement* add_PYRA_13(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
+  {
+    return mesh->AddVolumeWithID( ids[0],ids[3],ids[2],ids[1],ids[4],ids[8],ids[7],
+                                  ids[6],ids[5],ids[9],ids[12],ids[11],ids[10], ID );
+  }
+  SMDS_MeshElement* add_PENTA_6(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
+  {
+    return mesh->AddVolumeWithID( ids[0],ids[2],ids[1],ids[3],ids[5],ids[4], ID );
+  }
+  SMDS_MeshElement* add_PENTA_15(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
+  {
+    return mesh->AddVolumeWithID( ids[0],ids[2],ids[1],ids[3],ids[5],ids[4],ids[8],ids[7],
+                                  ids[6],ids[9],ids[11],ids[10],ids[14],ids[13],ids[12], ID );
+  }
+  SMDS_MeshElement* add_HEXA_8(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
+  {
+    return mesh->AddVolumeWithID( ids[0],ids[3],ids[2],ids[1],ids[4],ids[7],ids[6],ids[5], ID );
+  }
+  SMDS_MeshElement* add_HEXA_20(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
+  {
+    return mesh->AddVolumeWithID( ids[0],ids[3],ids[2],ids[1],ids[4],ids[7],ids[6],
+                                  ids[5],ids[11],ids[10],ids[9],ids[8],ids[12],ids[15],
+                                  ids[14],ids[13],ids[19],ids[18],ids[17],ids[16], ID );
+  }
+  SMDS_MeshElement* add_NGON(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
+  {
+    vector<int> idVec( ids[0] );
+    for ( int i = 0; i < ids[0]; ++i )
+      idVec[ i ] = (int) ids[ i + 1];
+    return mesh->AddPolygonalFaceWithID( idVec, ID );
+  }
+
+  typedef SMDS_MeshElement* (* PAddElemFun) (cgsize_t* ids, SMESHDS_Mesh* mesh, int ID);
+  
+  //================================================================================
+  /*!
+   * \brief Return an array of functions each adding an element of a particular type
+   */
+  //================================================================================
+
+  PAddElemFun* getAddElemFunTable()
+  {
+    static vector< PAddElemFun > funVec;
+    if ( funVec.empty() )
+    {
+      funVec.resize( NofValidElementTypes, (PAddElemFun)0 );
+      funVec[ CGNS_ENUMV( NODE     )] = add_0D      ;
+      funVec[ CGNS_ENUMV( BAR_2    )] = add_BAR_2   ;
+      funVec[ CGNS_ENUMV( BAR_3    )] = add_BAR_3   ;
+      funVec[ CGNS_ENUMV( TRI_3    )] = add_TRI_3   ;
+      funVec[ CGNS_ENUMV( TRI_6    )] = add_TRI_6   ;
+      funVec[ CGNS_ENUMV( QUAD_4   )] = add_QUAD_4  ;
+      funVec[ CGNS_ENUMV( QUAD_8   )] = add_QUAD_8  ;
+      funVec[ CGNS_ENUMV( QUAD_9   )] = add_QUAD_8  ;
+      funVec[ CGNS_ENUMV( TETRA_4  )] = add_TETRA_4 ;
+      funVec[ CGNS_ENUMV( TETRA_10 )] = add_TETRA_10;
+      funVec[ CGNS_ENUMV( PYRA_5   )] = add_PYRA_5  ;
+      funVec[ CGNS_ENUMV( PYRA_13  )] = add_PYRA_13 ;
+      funVec[ CGNS_ENUMV( PYRA_14  )] = add_PYRA_13 ;
+      funVec[ CGNS_ENUMV( PENTA_6  )] = add_PENTA_6 ;
+      funVec[ CGNS_ENUMV( PENTA_15 )] = add_PENTA_15;
+      funVec[ CGNS_ENUMV( PENTA_18 )] = add_PENTA_15;
+      funVec[ CGNS_ENUMV( HEXA_8   )] = add_HEXA_8  ;
+      funVec[ CGNS_ENUMV( HEXA_20  )] = add_HEXA_20 ;
+      funVec[ CGNS_ENUMV( HEXA_27  )] = add_HEXA_20 ;
+      funVec[ CGNS_ENUMV( NGON_n   )] = add_NGON    ;
+    }
+    return &funVec[0];
+  }
+
+  //================================================================================
+  /*!
+   * \brief Finds an existing boundary element
+   */
+  //================================================================================
+
+  const SMDS_MeshElement* findElement(const cgsize_t*     nodeIDs,
+                                      const int           nbNodes,
+                                      const SMESHDS_Mesh* mesh)
+  {
+    const SMDS_MeshNode* nn[4]; // look for quad4 or seg2
+    if (( nn[0] = mesh->FindNode( nodeIDs[0] )))
+    {
+      SMDSAbs_ElementType eType = nbNodes==4 ? SMDSAbs_Face : SMDSAbs_Edge;
+      SMDS_ElemIteratorPtr eIt = nn[0]->GetInverseElementIterator( eType );
+      if ( eIt->more() )
+        for ( int i = 1; i < nbNodes; ++i )
+          nn[i] = mesh->FindNode( nodeIDs[i] );
+      while ( eIt->more() )
+      {
+        const SMDS_MeshElement* e = eIt->next();
+        if ( e->NbNodes() == nbNodes )
+        {
+          bool elemOK = true;
+          for ( int i = 1; i < nbNodes && elemOK; ++i )
+            elemOK = ( e->GetNodeIndex( nn[i] ) >= 0 );
+          if ( elemOK )
+            return e;
+        }
+      } 
+    }
+    return 0;
+  }
+
+} // namespace
+
+//================================================================================
+/*!
+ * \brief Perform reading a myMeshId-th mesh
+ */
+//================================================================================
+
+Driver_Mesh::Status DriverCGNS_Read::Perform()
+{
+  myErrorMessages.clear();
+
+  Status aResult;
+  if (( aResult = open() ) != DRS_OK )
+    return aResult;
+
+  // read nb of meshes (CGNSBase_t)
+  if ( myMeshId < 0 || myMeshId >= GetNbMeshes(aResult))
+    return addMessage( SMESH_Comment("Invalid mesh index :") << myMeshId );
+
+  // read a name and a dimension of the mesh
+  const int cgnsBase = myMeshId + 1;
+  char meshName[CGNS_NAME_SIZE];
+  int meshDim, spaceDim;
+  if ( cg_base_read( _fn, cgnsBase, meshName, &meshDim, &spaceDim) != CG_OK )
+    return addMessage( cg_get_error() );
+
+  if ( spaceDim < 1 || spaceDim > 3 )
+    return addMessage( SMESH_Comment("Invalid space dimension: ") << spaceDim
+                       << " in mesh '" << meshName << "'");
+
+  myMeshName = meshName;
+
+  // read nb of domains (Zone_t) in the mesh
+  int nbZones = 0;
+  if ( cg_nzones (_fn, cgnsBase, &nbZones) != CG_OK )
+    return addMessage( cg_get_error() );
+
+  if ( nbZones < 1 )
+    return addMessage( SMESH_Comment("Empty mesh: '") << meshName << "'");
+
+  // read the domains (zones)
+  // ------------------------
+  map< string, TZoneData > zonesByName;
+  char name[CGNS_NAME_SIZE];
+  cgsize_t sizes[NB_ZONE_SIZE_VAL];
+  memset(sizes, 0, NB_ZONE_SIZE_VAL * sizeof(cgsize_t));
+
+  const SMDS_MeshInfo& meshInfo = myMesh->GetMeshInfo();
+  int groupID = myMesh->GetGroups().size();
+
+  for ( int iZone = 1; iZone <= nbZones; ++iZone )
+  {
+    // size and name of a zone
+    if ( cg_zone_read( _fn, cgnsBase, iZone, name, sizes) != CG_OK) {
+      addMessage( cg_get_error() );
+      continue;
+    }
+    TZoneData& zone = zonesByName[ name ];
+    zone._id          = iZone;
+    zone._nodeIdShift = meshInfo.NbNodes();
+    zone._elemIdShift = meshInfo.NbElements();
+    zone.SetSizeAndDim( sizes, meshDim );
+
+    // mesh type of the zone
+    if ( cg_zone_type ( _fn, cgnsBase, iZone, &zone._type) != CG_OK) {
+      addMessage( cg_get_error() );
+      continue;
+    }
+
+    switch ( zone._type )
+    {
+    case CGNS_ENUMV( Unstructured ):
+    case CGNS_ENUMV( Structured ):
+      break;
+    case CGNS_ENUMV( ZoneTypeNull ):
+      addMessage( "Meshes with ZoneTypeNull are not supported");
+      continue;
+    case CGNS_ENUMV( ZoneTypeUserDefined ):
+      addMessage( "Meshes with ZoneTypeUserDefined are not supported");
+      continue;
+    default:
+      addMessage( "Unknown ZoneType_t");
+      continue;
+    }
+
+    // -----------
+    // Read nodes
+    // -----------
+
+    if ( cg_ncoords( _fn, cgnsBase, iZone, &spaceDim) != CG_OK ) {
+      addMessage( cg_get_error() );
+      continue;
+    }
+    if ( spaceDim < 1 ) {
+      addMessage( SMESH_Comment("No coordinates defined in zone ")
+                  << iZone << " of Mesh " << myMeshId );
+      continue;
+    }
+    // read coordinates
+
+    int rmin[3] = {1,1,1}; // range of nodes to read
+    int rmax[3] = {1,1,1};
+    int nbNodes = rmax[0] = zone._sizes[0];
+    if ( zone.IsStructured())
+      for ( int i = 1; i < meshDim; ++i )
+        nbNodes *= rmax[i] = zone._sizes[i];
+
+    vector<double> coords[3];
+    for ( int c = 1; c <= spaceDim; ++c)
+    {
+      coords[c-1].resize( nbNodes );
+
+      CGNS_ENUMV( DataType_t ) type;
+      if ( cg_coord_info( _fn, cgnsBase, iZone, c, &type, name) != CG_OK ||
+           cg_coord_read( _fn, cgnsBase, iZone, name, CGNS_ENUMV(RealDouble),
+                          rmin, rmax, (void*)&(coords[c-1][0])) != CG_OK)
+      {
+        addMessage( cg_get_error() );
+        coords[c-1].clear();
+        break;
+      }
+    }
+    if ( coords[ spaceDim-1 ].empty() )
+      continue; // there was an error while reading coordinates 
+
+    // fill coords with zero if spaceDim < 3
+    for ( int c = 2; c <= 3; ++c)
+      if ( coords[ c-1 ].empty() )
+        coords[ c-1 ].resize( nbNodes, 0.0 );
+
+    // create nodes
+    try {
+      for ( int i = 0; i < nbNodes; ++i )
+        myMesh->AddNodeWithID( coords[0][i], coords[1][i], coords[2][i], i+1+zone._nodeIdShift );
+    }
+    catch ( std::exception& exc ) // expect std::bad_alloc
+    {
+      addMessage( exc.what() );
+      break;
+    }
+
+    // Read connectivity between zones. Nodes of the zone interface will be
+    // replaced withing the zones read later
+    string err = zone.ReadZonesConnection( _fn, cgnsBase, zonesByName );
+    if ( !err.empty() )
+      addMessage( err );
+
+    // --------------
+    // Read elements
+    // --------------
+    if ( zone.IsStructured())
+    {
+      int nbI = zone._sizeX - 1, nbJ = zone._sizeY - 1, nbK = zone._sizeZ - 1;
+      cgsize_t nID[8];
+      if ( meshDim > 2 && nbK > 0 )
+      {
+        for ( int k = 1; k <= nbK; ++k )
+          for ( int j = 1; j <= nbJ; ++j )
+            for ( int i = 1; i <= nbI; ++i )
+            {
+              zone.CellNodes( i, j, k, nID );
+              zone.ReplaceNodes( nID, 8 );
+              myMesh->AddVolumeWithID(nID[0],nID[1],nID[2],nID[3],nID[4],nID[5],nID[6],nID[7],
+                                      meshInfo.NbElements()+1);
+            }
+      }
+      else if ( meshDim > 1 && nbJ > 0 )
+      {
+        for ( int j = 1; j <= nbJ; ++j )
+          for ( int i = 1; i <= nbI; ++i )
+          {
+            zone.CellNodes( i, j, nID );
+            zone.ReplaceNodes( nID, 4 );
+            myMesh->AddFaceWithID(nID[0],nID[1],nID[2],nID[3], meshInfo.NbElements()+1);
+          }
+      }
+      else if ( meshDim > 0 && nbI > 0 )
+      {
+        nID[0] = zone.NodeID( 1, 0, 0 );
+        for ( int i = 1; i <= nbI; ++i, ++nID[0] )
+        {
+          nID[1] = nID[0]+1;
+          zone.ReplaceNodes( nID, 2 );
+          myMesh->AddEdgeWithID(nID[0],nID[1], meshInfo.NbElements()+1);
+        }
+      }
+    }
+    else
+    {
+      // elements can be stored in different sections each dedicated to one element type
+      int nbSections = 0;
+      if ( cg_nsections( _fn, cgnsBase, iZone, &nbSections) != CG_OK)
+      {
+        addMessage( cg_get_error() );
+        continue;
+      }
+      PAddElemFun* addElemFuns = getAddElemFunTable(), curAddElemFun = 0;
+      int nbNotSuppElem = 0; // nb elements of not supported types
+      bool polyhedError = false; // error at polyhedron creation
+
+      // read element data
+
+      CGNS_ENUMT( ElementType_t ) elemType;
+      cgsize_t start, end; // range of ids of elements of a zone
+      int nbBnd, parent_flag, eDataSize = 0;
+      for ( int iSec = 1; iSec <= nbSections; ++iSec )
+      {
+        if ( cg_section_read( _fn, cgnsBase, iZone, iSec, name, &elemType,
+                              &start, &end, &nbBnd, &parent_flag) != CG_OK ||
+             cg_ElementDataSize( _fn, cgnsBase, iZone, iSec, &eDataSize ) != CG_OK )
+        {
+          addMessage( cg_get_error() );
+          continue;
+        }
+        vector< cgsize_t > elemData( eDataSize );
+        if ( cg_elements_read( _fn, cgnsBase, iZone, iSec, &elemData[0], NULL ) != CG_OK )
+        {
+          addMessage( cg_get_error() );
+          continue;
+        }
+        // store elements
+
+        int pos = 0, cgnsNbNodes = 0, elemID = start + zone._elemIdShift;
+        cg_npe( elemType, &cgnsNbNodes ); // get nb nodes by element type
+        curAddElemFun = addElemFuns[ elemType ];
+        SMDS_MeshElement* newElem = 0;
+        const SMDS_MeshElement* face;
+
+        while ( pos < eDataSize )
+        {
+          CGNS_ENUMT( ElementType_t ) currentType = elemType;
+          if ( currentType == CGNS_ENUMV( MIXED )) {
+            //ElementConnectivity = Etype1, Node11, Node21, ... NodeN1,
+            //                      Etype2, Node12, Node22, ... NodeN2,
+            //                      ...
+            //                      EtypeM, Node1M, Node2M, ... NodeNM
+            currentType = (CGNS_ENUMT(ElementType_t)) elemData[ pos++ ];
+            cg_npe( currentType, &cgnsNbNodes );
+            curAddElemFun = addElemFuns[ currentType ];
+          }
+          if ( cgnsNbNodes < 1 ) // poly elements
+          {
+            if ( currentType == CGNS_ENUMV( NFACE_n )) // polyhedron
+            {
+              //ElementConnectivity = Nfaces1, Face11, Face21, ... FaceN1,
+              //                      Nfaces2, Face12, Face22, ... FaceN2,
+              //                      ...
+              //                      NfacesM, Face1M, Face2M, ... FaceNM
+              const int nbFaces = elemData[ pos++ ];
+              vector<int> quantities( nbFaces );
+              vector<const SMDS_MeshNode*> nodes, faceNodes;
+              nodes.reserve( nbFaces * 4 );
+              for ( int iF = 0; iF < nbFaces; ++iF )
+              {
+                const int faceID = Abs( elemData[ pos++ ]) + zone._elemIdShift; 
+                if (( face = myMesh->FindElement( faceID )) && face->GetType() == SMDSAbs_Face )
+                {
+                  const bool reverse = ( elemData[ pos-1 ] < 0 );
+                  const int    iQuad = face->IsQuadratic() ? 1 : 0;
+                  SMDS_ElemIteratorPtr nIter = face->interlacedNodesElemIterator();
+                  faceNodes.assign( SMDS_MeshElement::iterator( nIter ),
+                                    SMDS_MeshElement::iterator());
+                  if ( iQuad && reverse )
+                    nodes.push_back( faceNodes[0] );
+                  if ( reverse )
+                    nodes.insert( nodes.end(), faceNodes.rbegin(), faceNodes.rend() - iQuad );
+                  else
+                    nodes.insert( nodes.end(), faceNodes.begin(), faceNodes.end() );
+
+                  quantities[ iF ] = face->NbNodes();
+                }
+                else {
+                  polyhedError = true;
+                  break;
+                }
+              }
+              if ( quantities.back() )
+              {
+                myMesh->AddPolyhedralVolumeWithID( nodes, quantities, elemID );
+              }
+            }
+            else if ( currentType == CGNS_ENUMV( NGON_n )) // polygon
+            {
+              // ElementConnectivity = Nnodes1, Node11, Node21, ... NodeN1,
+              //                       Nnodes2, Node12, Node22, ... NodeN2,
+              //                       ...
+              //                       NnodesM, Node1M, Node2M, ... NodeNM
+              cgnsNbNodes = elemData[ pos ];
+              zone.ReplaceNodes( &elemData[pos+1], cgnsNbNodes, zone._nodeIdShift );
+              newElem = add_NGON( &elemData[pos  ], myMesh, elemID );
+              pos += cgnsNbNodes + 1;
+              cgnsNbNodes = 0; // as mark of poly elements
+            }
+          }
+          else // standard elements
+          {
+            zone.ReplaceNodes( &elemData[pos], cgnsNbNodes, zone._nodeIdShift );
+            newElem = curAddElemFun( &elemData[pos], myMesh, elemID );
+            pos += cgnsNbNodes;
+            nbNotSuppElem += int( newElem && newElem->NbNodes() != cgnsNbNodes );
+          }
+          elemID++;
+
+        } // loop on elemData
+      } // loop on cgns sections
+
+      if ( nbNotSuppElem > 0 )
+        addMessage( SMESH_Comment(nbNotSuppElem) << " elements of not supported types"
+                    << " have beem converted to close types");
+      if ( polyhedError )
+        addMessage( "Some polyhedral elements have been skipped due to internal(?) errors" );
+
+    } // reading unstructured elements
+
+    zone._nbNodes = meshInfo.NbNodes() - zone._nodeIdShift;
+    zone._nbElems = meshInfo.NbElements() - zone._elemIdShift;
+
+    // -------------------------------------------
+    // Read Boundary Conditions into SMESH groups
+    // -------------------------------------------
+    int nbBC = 0;
+    if ( cg_nbocos( _fn, cgnsBase, iZone, &nbBC) == CG_OK )
+    {
+      CGNS_ENUMT( BCType_t ) bcType;
+      CGNS_ENUMT( PointSetType_t ) psType;
+      CGNS_ENUMT( DataType_t ) normDataType;
+      cgsize_t nbPnt, normFlag;
+      int normIndex[3], nbDS;
+      for ( int iBC = 1; iBC <= nbBC; ++iBC )
+      {
+        if ( cg_boco_info( _fn, cgnsBase, iZone, iBC, name, &bcType, &psType,
+                           &nbPnt, normIndex, &normFlag, &normDataType, &nbDS ) != CG_OK )
+        {
+          addMessage( cg_get_error() );
+          continue;
+        }
+        vector< cgsize_t > ids( nbPnt * zone.IndexSize() );
+        CGNS_ENUMT( GridLocation_t ) location;
+        if ( cg_boco_read( _fn, cgnsBase, iZone, iBC, &ids[0], NULL ) != CG_OK ||
+             cg_boco_gridlocation_read( _fn, cgnsBase, iZone, iBC, &location) != CG_OK )
+        {
+          addMessage( cg_get_error() );
+          continue;
+        }
+        SMDSAbs_ElementType elemType = SMDSAbs_All;
+        switch ( location ) {
+        case CGNS_ENUMV( Vertex      ): elemType = SMDSAbs_Node; break;
+        case CGNS_ENUMV( FaceCenter  ): elemType = SMDSAbs_Face; break;
+        case CGNS_ENUMV( IFaceCenter ): elemType = SMDSAbs_Face; break;
+        case CGNS_ENUMV( JFaceCenter ): elemType = SMDSAbs_Face; break;
+        case CGNS_ENUMV( KFaceCenter ): elemType = SMDSAbs_Face; break;
+        case CGNS_ENUMV( EdgeCenter  ): elemType = SMDSAbs_Edge; break;
+        default:;
+        }
+        SMESHDS_Group* group = new SMESHDS_Group ( groupID++, myMesh, elemType );
+        myMesh->AddGroup( group );
+        SMESH_Comment groupName( name ); groupName << " " << cg_BCTypeName( bcType );
+        group->SetStoreName( groupName.c_str() );
+        SMDS_MeshGroup& groupDS = group->SMDSGroup();
+
+        if ( elemType == SMDSAbs_Node )
+        {
+          if ( zone.IsStructured() )
+          {
+            vector< cgsize_t > nodeIds;
+            if ( psType == CGNS_ENUMV( PointRange ))
+            {
+              // nodes are given as (ijkMin, ijkMax)
+              TPointRangeIterator idIt( & ids[0], meshDim );
+              nodeIds.reserve( idIt.Size() );
+              while ( idIt.More() )
+                nodeIds.push_back( zone.NodeID( idIt.Next() ));
+            }
+            else
+            {
+              // nodes are given as (ijk1, ijk2, ..., ijkN)
+              nodeIds.reserve( ids.size() / meshDim );
+              for ( size_t i = 0; i < ids.size(); i += meshDim )
+                nodeIds.push_back( zone.NodeID( ids[i], ids[i+1], ids[i+2] ));
+            }
+            ids.swap( nodeIds );
+          }
+          else if ( zone._nodeIdShift )
+          {
+            for ( size_t i = 0; i < ids.size(); ++i )
+              ids[i] += zone._nodeIdShift;
+          }
+          zone.ReplaceNodes( &ids[0], ids.size() );
+
+          for ( size_t i = 0; i < ids.size(); ++i )
+            if ( const SMDS_MeshNode* n = myMesh->FindNode( ids[i] ))
+              groupDS.Add( n );
+        }
+        else // BC applied to elements
+        {
+          if ( zone.IsStructured() )
+          {
+            int axis = 0; // axis perpendiculaire to which boundary elements are oriented
+            if ( ids.size() >= meshDim * 2 )
+            {
+              for ( ; axis < meshDim; ++axis )
+                if ( ids[axis] - ids[axis+meshDim] == 0 )
+                  break;
+            }
+            else
+            {
+              for ( ; axis < meshDim; ++axis )
+                if ( normIndex[axis] != 0 )
+                  break;
+            }
+            if ( axis == meshDim )
+            {
+              addMessage( SMESH_Comment("Invalid NormalIndex in BC ") << name );
+              continue;
+            }
+            const int nbElemNodesByDim[] = { 1, 2, 4, 8 };
+            const int nbElemNodes = nbElemNodesByDim[ meshDim ];
+
+            if ( psType == CGNS_ENUMV( PointRange ) ||
+                 psType == CGNS_ENUMV( ElementRange ))
+            {
+              // elements are given as (ijkMin, ijkMax)
+              typedef void (TZoneData::*PGetNodesFun)( const gp_XYZ& ijk, cgsize_t* ids ) const;
+              PGetNodesFun getNodesFun = 0;
+              if ( elemType == SMDSAbs_Face  && meshDim == 3 )
+                switch ( axis ) {
+                case 0: getNodesFun = & TZoneData::IFaceNodes;
+                case 1: getNodesFun = & TZoneData::JFaceNodes;
+                case 2: getNodesFun = & TZoneData::KFaceNodes;
+                }
+              else if ( elemType == SMDSAbs_Edge && meshDim == 2 )
+                switch ( axis ) {
+                case 0: getNodesFun = & TZoneData::IEdgeNodes;
+                case 1: getNodesFun = & TZoneData::JEdgeNodes;
+                }
+              if ( !getNodesFun )
+              {
+                addMessage( SMESH_Comment("Unsupported BC location in BC ") << name
+                            << " " << cg_GridLocationName( location )
+                            << " in " << meshDim << " mesh");
+                continue;
+              }
+              TPointRangeIterator rangeIt( & ids[0], meshDim );
+              vector< cgsize_t > elemNodeIds( rangeIt.Size() * nbElemNodes );
+              for ( int i = 0; rangeIt.More(); i+= nbElemNodes )
+                (zone.*getNodesFun)( rangeIt.Next(), &elemNodeIds[i] );
+
+              ids.swap( elemNodeIds );
+            }
+            else
+            {
+              // elements are given as (ijk1, ijk2, ..., ijkN)
+              typedef void (TZoneData::*PGetNodesFun)( int i, int j, int k, cgsize_t* ids ) const;
+              PGetNodesFun getNodesFun = 0;
+              if ( elemType == SMDSAbs_Face )
+                switch ( axis ) {
+                case 0: getNodesFun = & TZoneData::IFaceNodes;
+                case 1: getNodesFun = & TZoneData::JFaceNodes;
+                case 2: getNodesFun = & TZoneData::KFaceNodes;
+                }
+              else if ( elemType == SMDSAbs_Edge && meshDim == 2 )
+                switch ( axis ) {
+                case 0: getNodesFun = & TZoneData::IEdgeNodes;
+                case 1: getNodesFun = & TZoneData::JEdgeNodes;
+                }
+              if ( !getNodesFun )
+              {
+                addMessage( SMESH_Comment("Unsupported BC location in BC ") << name
+                            << " " << cg_GridLocationName( location )
+                            << " in " << meshDim << " mesh");
+                continue;
+              }
+              vector< cgsize_t > elemNodeIds( ids.size()/meshDim * nbElemNodes );
+              for ( size_t i = 0, j = 0; i < ids.size(); i += meshDim, j += nbElemNodes )
+                (zone.*getNodesFun)( ids[i], ids[i+1], ids[i+2], &elemNodeIds[j] );
+
+              ids.swap( elemNodeIds );
+            }
+            zone.ReplaceNodes( &ids[0], ids.size() );
+
+            PAddElemFun addElemFun = 0;
+            switch ( meshDim ) {
+            case 1: addElemFun = & add_BAR_2;
+            case 2: addElemFun = & add_QUAD_4;
+            case 3: addElemFun = & add_HEXA_8;
+            }
+            int elemID = meshInfo.NbElements();
+            const SMDS_MeshElement* elem = 0;
+            for ( size_t i = 0; i < ids.size(); i += nbElemNodes )
+            {
+              if ( iZone == 1 || !( elem = findElement( &ids[i], nbElemNodes, myMesh )))
+                elem = addElemFun( &ids[i], myMesh, ++elemID );
+              groupDS.Add( elem );
+            }
+          }
+          else // unstructured zone
+          {
+            if ( zone._elemIdShift )
+              for ( size_t i = 0; i < ids.size(); ++i )
+                ids[i] += zone._elemIdShift;
+
+            if ( psType == CGNS_ENUMV( PointRange ) && ids.size() == 2 )
+            {
+              for ( size_t i = ids[0]; i <= ids[1]; ++i )
+                if ( const SMDS_MeshElement* e = myMesh->FindElement( i ))
+                  groupDS.Add( e );
+            }
+            else
+            {
+              for ( size_t i = 0; i < ids.size(); ++i )
+                if ( const SMDS_MeshElement* e = myMesh->FindElement( ids[i] ))
+                  groupDS.Add( e );
+            }
+          }
+        } // end "BC applied to elements"
+
+        // to have group type according to a real elem type
+        group->SetType( groupDS.GetType() );
+
+      } // loop on BCs of the zone
+    }
+    else
+    {
+      addMessage( cg_get_error() );
+    }
+  } // loop on the zones of a mesh
+
+
+  // ------------------------------------------------------------------------
+  // Make groups for multiple zones and remove free nodes at zone interfaces
+  // ------------------------------------------------------------------------
+  map< string, TZoneData >::iterator nameZoneIt = zonesByName.begin();
+  for ( ; nameZoneIt != zonesByName.end(); ++nameZoneIt )
+  {
+    TZoneData& zone = nameZoneIt->second;
+    if ( zone._nbElems == 0 ) continue;
+    if ( zone._nbElems == meshInfo.NbElements() ) break; // there is only one non-empty zone
+
+    // make a group
+    SMDSAbs_ElementType elemType = myMesh->GetElementType( zone._elemIdShift + 1,
+                                                           /*iselem=*/true );
+    SMESHDS_Group* group = new SMESHDS_Group ( groupID++, myMesh, elemType );
+    myMesh->AddGroup( group );
+    group->SetStoreName( nameZoneIt->first.c_str() );
+    SMDS_MeshGroup& groupDS = group->SMDSGroup();
+
+    for ( int i = 1; i <= zone._nbElems; ++i )
+      if ( const SMDS_MeshElement* e = myMesh->FindElement( i + zone._elemIdShift ))
+        groupDS.Add( e );
+
+    // remove free nodes
+    map< int, int >::iterator nnRmKeepIt = zone._nodeReplacementMap.begin();
+    for ( ; nnRmKeepIt != zone._nodeReplacementMap.end(); ++nnRmKeepIt )
+      if ( const SMDS_MeshNode* n = myMesh->FindNode( nnRmKeepIt->first ))
+        if ( n->NbInverseElements() == 0 )
+          myMesh->RemoveFreeNode( n, (SMESHDS_SubMesh *)0, /*fromGroups=*/false );
+  }
+
+  aResult = myErrorMessages.empty() ? DRS_OK : DRS_WARN_SKIP_ELEM;
+
+  return aResult;
+}
+
+//================================================================================
+/*!
+ * \brief Constructor
+ */
+//================================================================================
+
+DriverCGNS_Read::DriverCGNS_Read()
+{
+  _fn = -1;
+}
+//================================================================================
+/*!
+ * \brief Close the cgns file at destruction
+ */
+//================================================================================
+
+DriverCGNS_Read::~DriverCGNS_Read()
+{
+  if ( _fn > 0 )
+    cg_close( _fn );
+}
+
+//================================================================================
+/*!
+ * \brief Opens myFile
+ */
+//================================================================================
+
+Driver_Mesh::Status DriverCGNS_Read::open()
+{
+  if ( _fn < 0 )
+  {
+    
+#ifdef CG_MODE_READ
+    int res = cg_open(myFile.c_str(), CG_MODE_READ, &_fn);
+#else
+    int res = cg_open(myFile.c_str(), MODE_READ, &_fn);
+#endif
+    if ( res != CG_OK)
+    {
+      addMessage( cg_get_error(), /*fatal = */true );
+    }
+  }
+  return _fn >= 0 ? DRS_OK : DRS_FAIL;
+}
+
+//================================================================================
+/*!
+ * \brief Reads nb of meshes in myFile
+ */
+//================================================================================
+
+int DriverCGNS_Read::GetNbMeshes(Status& theStatus)
+{
+  if (( theStatus = open()) != DRS_OK )
+    return 0;
+
+  int nbases = 0;
+  if(cg_nbases( _fn, &nbases) != CG_OK)
+    theStatus = addMessage( cg_get_error(), /*fatal = */true );
+
+  return nbases;
+}
diff --git a/src/DriverCGNS/DriverCGNS_Read.hxx b/src/DriverCGNS/DriverCGNS_Read.hxx
new file mode 100644 (file)
index 0000000..718ba11
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright (C) 2007-2011  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
+//
+// 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.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+// File      : DriverCGNS_Read.hxx
+// Created   : Thu Jun 30 10:25:09 2011
+// Author    : Edward AGAPOV (eap)
+
+#ifndef __DriverCGNS_Read_HXX__
+#define __DriverCGNS_Read_HXX__
+
+#include "SMESH_DriverCGNS.hxx"
+
+#include "Driver_SMESHDS_Mesh.h"
+
+#include <vector>
+#include <string>
+
+/*!
+ * \brief Driver reading a mesh from the CGNS file. The mesh to read is selected by 
+ *  an index (counted form 0) set via SetMeshId()
+ */
+class MESHDriverCGNS_EXPORT DriverCGNS_Read : public Driver_SMESHDS_Mesh
+{
+public:
+
+  DriverCGNS_Read();
+  ~DriverCGNS_Read();
+
+  virtual Status Perform();
+
+  int GetNbMeshes(Status& theStatus);
+
+
+private:
+
+  Status open();
+
+  int _fn; //!< file index
+};
+
+#endif
diff --git a/src/DriverCGNS/DriverCGNS_Write.cxx b/src/DriverCGNS/DriverCGNS_Write.cxx
new file mode 100644 (file)
index 0000000..0c9a209
--- /dev/null
@@ -0,0 +1,570 @@
+// Copyright (C) 2007-2011  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
+//
+// 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.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+// File      : DriverCGNS_Write.cxx
+// Created   : Fri Aug  5 17:43:54 2011
+// Author    : Edward AGAPOV (eap)
+
+#include "DriverCGNS_Write.hxx"
+
+#include "SMDS_MeshNode.hxx"
+#include "SMDS_VolumeTool.hxx"
+#include "SMESHDS_GroupBase.hxx"
+#include "SMESHDS_Mesh.hxx"
+#include "SMESH_Comment.hxx"
+
+#include <limits>
+#include <cgnslib.h>
+
+#if CGNS_VERSION < 3100
+# define cgsize_t int
+#endif
+
+using namespace std;
+
+namespace
+{
+  //================================================================================
+  /*!
+   * \brief Return interlace and type of CGNS element for the given SMDSAbs_EntityType
+   */
+  //================================================================================
+
+  const int* getInterlaceAndType( const SMDSAbs_EntityType      smType,
+                                  CGNS_ENUMT( ElementType_t ) & cgType )
+  {
+    static vector< const int* >                 interlaces;
+    static vector< CGNS_ENUMT( ElementType_t )> cgTypes; 
+    if ( interlaces.empty() )
+    {
+      interlaces.resize( SMDSEntity_Last, 0 );
+      cgTypes.resize( SMDSEntity_Last, CGNS_ENUMV( ElementTypeNull ));
+      {
+        static int ids[] = {0};
+        interlaces[SMDSEntity_0D] = ids;
+        cgTypes   [SMDSEntity_0D] = CGNS_ENUMV( NODE );
+      }
+      {
+        static int ids[] = { 0, 1 };
+        interlaces[SMDSEntity_Edge] = ids;
+        cgTypes   [SMDSEntity_Edge] = CGNS_ENUMV( BAR_2 );
+      }
+      {
+        static int ids[] = { 0, 1, 2 };
+        interlaces[SMDSEntity_Quad_Edge] = ids;
+        cgTypes   [SMDSEntity_Quad_Edge] = CGNS_ENUMV( BAR_3 );
+      }
+      {
+        static int ids[] = { 0, 2, 1 };
+        interlaces[SMDSEntity_Triangle] = ids;
+        cgTypes   [SMDSEntity_Triangle] = CGNS_ENUMV( TRI_3 );
+      }
+      {
+        static int ids[] = { 0, 2, 1, 5, 4, 3 };
+        interlaces[SMDSEntity_Quad_Triangle] = ids;
+        cgTypes   [SMDSEntity_Quad_Triangle] = CGNS_ENUMV( TRI_6 );
+      }
+      {
+        static int ids[] = { 0, 3, 2, 1 };
+        interlaces[SMDSEntity_Quadrangle] = ids;
+        cgTypes   [SMDSEntity_Quadrangle] = CGNS_ENUMV( QUAD_4 );
+      }
+      {
+        static int ids[] = { 0,3,2,1,7,6,5,4 };
+        interlaces[SMDSEntity_Quad_Quadrangle] = ids;
+        cgTypes   [SMDSEntity_Quad_Quadrangle] = CGNS_ENUMV( QUAD_8 );
+      }
+      {
+        static int ids[] = { 0, 2, 1, 3 };
+        interlaces[SMDSEntity_Tetra] = ids;
+        cgTypes   [SMDSEntity_Tetra] = CGNS_ENUMV( TETRA_4 );
+      }
+      {
+        static int ids[] = { 0,2,1,3,6,5,4,7,9,8 };
+        interlaces[SMDSEntity_Quad_Tetra] = ids;
+        cgTypes   [SMDSEntity_Quad_Tetra] = CGNS_ENUMV( TETRA_10 );
+      }
+      {
+        static int ids[] = { 0,3,2,1,4 };
+        interlaces[SMDSEntity_Pyramid] = ids;
+        cgTypes   [SMDSEntity_Pyramid] = CGNS_ENUMV( PYRA_5 );
+      }
+      {
+        static int ids[] = { 0,3,2,1,4,8,7,6,5,9,12,11,10 };
+        interlaces[SMDSEntity_Quad_Pyramid] = ids;
+        cgTypes   [SMDSEntity_Quad_Pyramid] = CGNS_ENUMV( PYRA_13 );
+      }
+      {
+        static int ids[] = { 0,2,1,3,5,4 };
+        interlaces[SMDSEntity_Penta] = ids;
+        cgTypes   [SMDSEntity_Penta] = CGNS_ENUMV( PENTA_6 );
+      }
+      {
+        static int ids[] = { 0,2,1,3,5,4,8,7,6,9,11,10,14,13,12 };
+        interlaces[SMDSEntity_Quad_Penta] = ids;
+        cgTypes   [SMDSEntity_Quad_Penta] = CGNS_ENUMV( PENTA_15 );
+      }
+      {
+        static int ids[] = { 0,3,2,1,4,7,6,5 };
+        interlaces[SMDSEntity_Hexa] = ids;
+        cgTypes   [SMDSEntity_Hexa] = CGNS_ENUMV( HEXA_8 );
+      }
+      {
+        static int ids[] = { 0,3,2,1,4,7,6,5,11,10,9,8,12,15,14,13,19,18,17,16 };
+        interlaces[SMDSEntity_Quad_Hexa] = ids;
+        cgTypes   [SMDSEntity_Quad_Hexa] = CGNS_ENUMV( HEXA_20 );
+      }
+      {
+        cgTypes[SMDSEntity_Polygon]   = CGNS_ENUMV( NGON_n );
+        cgTypes[SMDSEntity_Polyhedra] = CGNS_ENUMV( NFACE_n );
+      }
+    }
+    cgType  = cgTypes[ smType ];
+    return interlaces[ smType ];
+  }
+
+  //================================================================================
+  /*!
+   * \brief Cut off type of boundary condition from the group name
+   */
+  //================================================================================
+
+  CGNS_ENUMT( BCType_t ) getBCType( string& groupName )
+  {
+    CGNS_ENUMT( BCType_t ) bcType = CGNS_ENUMV( BCGeneral ); // default type
+
+    // boundary condition type starts from "BC"
+    size_t bcBeg = groupName.find("BC");
+    if ( bcBeg != string::npos )
+    {
+      for ( int t = 0; t < NofValidBCTypes; ++t )
+      {
+        CGNS_ENUMT( BCType_t ) type = CGNS_ENUMT( BCType_t)( t );
+        string typeName = cg_BCTypeName( type );
+        if ( typeName == &groupName[0] + bcBeg )
+        {
+          bcType = type;
+          while ( bcBeg > 0 && isspace( bcBeg-1 ))
+            --bcBeg;
+          if ( bcBeg == 0 )
+            groupName = "Group";
+          else
+            groupName = groupName.substr( 0, bcBeg-1 );
+        }
+      }
+    }
+    return bcType;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Sortable face of a polyhedron
+   */
+  struct TPolyhedFace
+  {
+    int _id; // id of NGON_n
+    vector< int > _nodes; // lowest node IDs used for sorting
+
+    TPolyhedFace( const SMDS_MeshNode** nodes, const int nbNodes, int ID):_id(ID)
+    {
+      set< int > ids;
+      for ( int i = 0; i < nbNodes; ++i )
+        ids.insert( nodes[i]->GetID() );
+
+      _nodes.resize( 3 ); // std::min( nbNodes, 4 )); hope 3 nodes is enough
+      set< int >::iterator idIt = ids.begin();
+      for ( size_t j = 0; j < _nodes.size(); ++j, ++idIt )
+        _nodes[j] = *idIt;
+    }
+    bool operator< (const TPolyhedFace& o ) const
+    {
+      return _nodes < o._nodes;
+    }
+  };
+  //================================================================================
+  /*!
+   * \brief Return CGNS id of an element
+   */
+  //================================================================================
+
+  cgsize_t cgnsID( const SMDS_MeshElement*                         elem,
+                   const map< const SMDS_MeshElement*, cgsize_t >& elem2cgID )
+  {
+    map< const SMDS_MeshElement*, cgsize_t >::const_iterator e2id = elem2cgID.find( elem );
+    return ( e2id == elem2cgID.end() ? elem->GetID() : e2id->second );
+  }
+
+} // namespace
+
+//================================================================================
+/*!
+ * \brief Write the mesh into the CGNS file
+ */
+//================================================================================
+
+Driver_Mesh::Status DriverCGNS_Write::Perform()
+{
+  myErrorMessages.clear();
+
+  if ( !myMesh || myMesh->GetMeshInfo().NbElements() < 1 )
+    return addMessage( !myMesh ? "NULL mesh" : "Empty mesh (no elements)", /*fatal = */true );
+
+  // open the file
+  if ( cg_open(myFile.c_str(), CG_MODE_MODIFY, &_fn) != CG_OK &&
+       cg_open(myFile.c_str(), CG_MODE_WRITE,  &_fn) != CG_OK )
+    return addMessage( cg_get_error(), /*fatal = */true );
+
+  // create a Base
+  // --------------
+
+  const int spaceDim = 3;
+  int meshDim = 1;
+  if ( myMesh->NbFaces() > 0 ) meshDim = 2;
+  if ( myMesh->NbVolumes() > 0 ) meshDim = 3;
+
+  if ( myMeshName.empty() )
+  {
+    int nbases = 0;
+    if ( cg_nbases( _fn, &nbases) == CG_OK)
+      myMeshName = ( SMESH_Comment("Base_") << nbases+1 );
+    else
+      myMeshName = "Base_0";
+  }
+  int iBase;
+  if ( cg_base_write( _fn, myMeshName.c_str(), meshDim, spaceDim, &iBase))
+    return addMessage( cg_get_error(), /*fatal = */true );
+
+  // create a Zone
+  // --------------
+
+  int nbCells = myMesh->NbEdges();
+  if ( meshDim == 3 )
+    nbCells = myMesh->NbVolumes();
+  else if ( meshDim == 2 )
+    nbCells = myMesh->NbFaces();
+
+  cgsize_t size[9] = { myMesh->NbNodes(), nbCells, /*NBoundVertex=*/0, 0,0,0,0,0,0 };
+  int iZone;
+  if ( cg_zone_write( _fn, iBase, "SMESH_Mesh", size,
+                      CGNS_ENUMV( Unstructured ), &iZone) != CG_OK )
+    return addMessage( cg_get_error(), /*fatal = */true );
+
+  // Map to store only elements whose an SMDS ID differs from a CGNS one
+  typedef map< const SMDS_MeshElement*, cgsize_t > TElem2cgIDMap;
+  vector< TElem2cgIDMap > elem2cgIDByEntity( SMDSEntity_Last );
+  TElem2cgIDMap::iterator elem2cgIDIter;
+
+  TElem2cgIDMap & n2cgID = elem2cgIDByEntity[ SMDSEntity_Node ];
+
+  // Write nodes
+  // ------------
+  {
+    vector< double > coords( myMesh->NbNodes() );
+    int iC;
+    // X
+    SMDS_NodeIteratorPtr nIt = myMesh->nodesIterator( /*idInceasingOrder=*/true );
+    for ( int i = 0; nIt->more(); ++i ) coords[i] = nIt->next()->X();
+    if ( cg_coord_write( _fn, iBase, iZone, CGNS_ENUMV(RealDouble),
+                          "CoordinateX", &coords[0], &iC) != CG_OK )
+      return addMessage( cg_get_error(), /*fatal = */true );
+    // Y
+    nIt = myMesh->nodesIterator( /*idInceasingOrder=*/true );
+    for ( int i = 0; nIt->more(); ++i ) coords[i] = nIt->next()->Y();
+    if ( cg_coord_write( _fn, iBase, iZone, CGNS_ENUMV(RealDouble),
+                          "CoordinateY", &coords[0], &iC) != CG_OK )
+      return addMessage( cg_get_error(), /*fatal = */true );
+    // Z
+    nIt = myMesh->nodesIterator( /*idInceasingOrder=*/true );
+    for ( int i = 0; nIt->more(); ++i ) coords[i] = nIt->next()->Z();
+    if ( cg_coord_write( _fn, iBase, iZone, CGNS_ENUMV(RealDouble),
+                          "CoordinateZ", &coords[0], &iC) != CG_OK )
+      return addMessage( cg_get_error(), /*fatal = */true );
+
+    // store CGNS ids of nodes
+    nIt = myMesh->nodesIterator( /*idInceasingOrder=*/true );
+    for ( int i = 0; nIt->more(); ++i )
+    {
+      const SMDS_MeshElement* n = nIt->next();
+      if ( n->GetID() != i+1 )
+        n2cgID.insert( n2cgID.end(), make_pair( n, i+1 ));
+    }
+  }
+  // Write elements
+  // ---------------
+  
+  cgsize_t cgID = 1, startID;
+
+  // write into a section all successive elements of one geom type
+  int iSec;
+  vector< cgsize_t > elemData;
+  SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator();
+  const SMDS_MeshElement* elem = elemIt->next();
+  while ( elem )
+  {
+    const SMDSAbs_EntityType elemType = elem->GetEntityType();
+    CGNS_ENUMT( ElementType_t ) cgType;
+    const int* interlace = getInterlaceAndType( elemType, cgType );
+
+    TElem2cgIDMap & elem2cgID = elem2cgIDByEntity[ elemType ];
+
+    elemData.clear();
+    startID = cgID;
+
+    if ( interlace ) // STANDARD elements
+      do
+      {
+        for ( int i = 0, nb = elem->NbNodes(); i < nb; ++i )
+          elemData.push_back( cgnsID( elem->GetNode( interlace[i] ), n2cgID ));
+        if ( elem->GetID() != cgID )
+          elem2cgID.insert( elem2cgID.end(), make_pair( elem, cgID ));
+        ++cgID;
+        elem = elemIt->more() ? elemIt->next() : 0;
+      }
+      while ( elem && elem->GetEntityType() == elemType );
+
+    else if ( elemType == SMDSEntity_Polygon ) // POLYGONS
+      do
+      {
+        elemData.push_back( elem->NbNodes() );
+        for ( int i = 0, nb = elem->NbNodes(); i < nb; ++i )
+          elemData.push_back( cgnsID( elem->GetNode(i), n2cgID ));
+        if ( elem->GetID() != cgID )
+          elem2cgID.insert( elem2cgID.end(), make_pair( elem, cgID ));
+        ++cgID;
+        elem = elemIt->more() ? elemIt->next() : 0;
+      }
+      while ( elem && elem->GetEntityType() == elemType );
+
+    else if ( elemType == SMDSEntity_Polyhedra ) // POLYHEDRA
+    {
+      // to save polyhedrons after all
+      const SMDS_MeshInfo& meshInfo = myMesh->GetMeshInfo();
+      if ( meshInfo.NbPolyhedrons() == meshInfo.NbElements() - cgID + 1 )
+        break; // only polyhedrons remain
+      while ( elem && elem->GetEntityType() == elemType )
+        elem = elemIt->more() ? elemIt->next() : 0;
+      continue;
+    }
+
+    SMESH_Comment sectionName( cg_ElementTypeName( cgType ));
+    sectionName << " " << startID << " - " << cgID-1;
+
+    if ( cg_section_write(_fn, iBase, iZone, sectionName.c_str(), cgType, startID,
+                          cgID-1, /*nbndry=*/0, &elemData[0], &iSec) != CG_OK )
+      return addMessage( cg_get_error(), /*fatal = */true );
+  }
+  // Write polyhedral volumes
+  // -------------------------
+
+  if ( myMesh->GetMeshInfo().NbPolyhedrons() > 0 )
+  {
+    // the polyhedron (NFACE_n) is described as a set of signed face IDs,
+    // so first we are to write all polygones (NGON_n) bounding polyhedrons
+
+    vector< cgsize_t > faceData;
+    set< TPolyhedFace > faces;
+    set< TPolyhedFace >::iterator faceInSet;
+    vector<const SMDS_MeshNode *> faceNodesVec;
+    int nbPolygones = 0, faceID;
+
+    SMDS_VolumeTool vol;
+
+    elemData.clear();
+
+    int nbPolyhTreated = 0;
+
+    TElem2cgIDMap * elem2cgID = 0;
+    TElem2cgIDMap & n2cgID    = elem2cgIDByEntity[ SMDSEntity_Node ];
+
+    SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator();
+    while ( elemIt->more() )
+    {
+      elem = elemIt->next();
+      if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
+      {
+        ++nbPolyhTreated;
+        vol.Set( elem );
+        vol.SetExternalNormal();
+        const int nbFaces = vol.NbFaces();
+        elemData.push_back( nbFaces );
+        for ( int iF = 0; iF < nbFaces; ++iF )
+        {
+          const int nbNodes = vol.NbFaceNodes( iF );
+          const SMDS_MeshNode** faceNodes = vol.GetFaceNodes( iF );
+          faceNodesVec.assign( faceNodes, faceNodes + nbNodes );
+          if (( elem = myMesh->FindElement( faceNodesVec, SMDSAbs_Face, /*noMedium=*/false)))
+          {
+            // a face of the polyhedron is present in the mesh
+            faceID = cgnsID( elem, elem2cgIDByEntity[ elem->GetEntityType() ]);
+          }
+          else if ( vol.IsFreeFace( iF ))
+          {
+            // the face is not shared by volumes
+            faceID = cgID++;
+            ++nbPolygones;
+            faceData.push_back( nbNodes );
+            for ( int i = 0; i < nbNodes; ++i )
+              faceData.push_back( cgnsID( faceNodes[i], n2cgID ));
+          }
+          else
+          {
+            TPolyhedFace face( faceNodes, nbNodes, cgID );
+            faceInSet = faces.insert( faces.end(), face );
+            if ( faceInSet->_id == cgID ) // the face encounters for the 1st time
+            {
+              faceID = cgID++;
+              ++nbPolygones;
+              faceData.push_back( nbNodes );
+              for ( int i = 0; i < nbNodes; ++i )
+                faceData.push_back( cgnsID( faceNodes[i], n2cgID ));
+            }
+            else
+            {
+              // the face encounters for the 2nd time; we hope it won't encounter once more,
+              // for that we can erase it from the set of faces
+              faceID = -faceInSet->_id;
+              faces.erase( faceInSet );
+            }
+          }
+          elemData.push_back( faceID );
+        }
+      }
+    }
+
+    if ( nbPolygones > 0 )
+    {
+      if ( cg_section_write(_fn, iBase, iZone, "Faces of Polyhedrons",
+                             CGNS_ENUMV( NGON_n ), cgID - nbPolygones, cgID-1,
+                             /*nbndry=*/0, &faceData[0], &iSec) != CG_OK )
+        return addMessage( cg_get_error(), /*fatal = */true );
+    }
+    
+    if ( cg_section_write(_fn, iBase, iZone, "Polyhedrons", 
+                             CGNS_ENUMV( NFACE_n ), cgID, cgID+nbPolyhTreated-1,
+                           /*nbndry=*/0, &elemData[0], &iSec) != CG_OK )
+      return addMessage( cg_get_error(), /*fatal = */true );
+
+    if ( !myMesh->GetGroups().empty() )
+    {
+      // store CGNS ids of polyhedrons
+      elem2cgID = &elem2cgIDByEntity[ SMDSEntity_Polyhedra ];
+      elemIt = myMesh->elementsIterator();
+      while ( elemIt->more() )
+      {
+        elem = elemIt->next();
+        if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
+        {
+          if ( elem->GetID() != cgID )
+            elem2cgID->insert( elem2cgID->end(), make_pair( elem, cgID ));
+          ++cgID;
+        }
+      }
+    }
+  } // write polyhedral volumes
+
+
+  // Write groups as boundary conditions
+  // ------------------------------------
+
+  const set<SMESHDS_GroupBase*>& groups = myMesh->GetGroups();
+  set<SMESHDS_GroupBase*>::const_iterator grpIt = groups.begin();
+  set< string > groupNames; groupNames.insert(""); // to avoid duplicated and empty names
+  for ( ; grpIt != groups.end(); ++grpIt )
+  {
+    const SMESHDS_GroupBase* group = *grpIt;
+
+    // write BC location (default is Vertex)
+    CGNS_ENUMT( GridLocation_t ) location = CGNS_ENUMV( Vertex );
+    if ( group->GetType() != SMDSAbs_Node )
+    {
+      switch ( meshDim ) {
+      case 3:
+        switch ( group->GetType() ) {
+        case SMDSAbs_Volume: location = CGNS_ENUMV( FaceCenter ); break; // !!!
+        case SMDSAbs_Face:   location = CGNS_ENUMV( FaceCenter ); break; // OK
+        case SMDSAbs_Edge:   location = CGNS_ENUMV( EdgeCenter ); break; // OK
+        default:;
+        }
+        break;
+      case 2:
+        switch ( group->GetType() ) {
+        case SMDSAbs_Face: location = CGNS_ENUMV( FaceCenter ); break; // ???
+        case SMDSAbs_Edge: location = CGNS_ENUMV( EdgeCenter ); break; // OK
+        default:;
+        }
+        break;
+      case 1:
+        location = CGNS_ENUMV( EdgeCenter ); break; // ???
+        break;
+      }
+    }
+
+    // try to extract type of boundary condition from the group name
+    string name = group->GetStoreName();
+    CGNS_ENUMT( BCType_t ) bcType = getBCType( name );
+    while ( !groupNames.insert( name ).second )
+      name = (SMESH_Comment( "Group_") << groupNames.size());
+
+    // write IDs of elements
+    vector< cgsize_t > pnts;
+    pnts.reserve( group->Extent() );
+    SMDS_ElemIteratorPtr elemIt = group->GetElements();
+    while ( elemIt->more() )
+    {
+      const SMDS_MeshElement* elem = elemIt->next();
+      pnts.push_back( cgnsID( elem, elem2cgIDByEntity[ elem->GetEntityType() ]));
+    }
+    int iBC;
+    if ( cg_boco_write( _fn, iBase, iZone, name.c_str(), bcType,
+                        CGNS_ENUMV( PointList ), pnts.size(), &pnts[0], &iBC) != CG_OK )
+      return addMessage( cg_get_error(), /*fatal = */true);
+
+    // write BC location
+    if ( location != CGNS_ENUMV( Vertex ))
+    {
+      if ( cg_boco_gridlocation_write( _fn, iBase, iZone, iBC, location) != CG_OK )
+        return addMessage( cg_get_error(), /*fatal = */false);
+    }
+  }
+  return DRS_OK;
+}
+
+//================================================================================
+/*!
+ * \brief Constructor
+ */
+//================================================================================
+
+DriverCGNS_Write::DriverCGNS_Write(): _fn(0)
+{
+}
+
+//================================================================================
+/*!
+ * \brief Close the cgns file at destruction
+ */
+//================================================================================
+
+DriverCGNS_Write::~DriverCGNS_Write()
+{
+  if ( _fn > 0 )
+    cg_close( _fn );
+}
diff --git a/src/DriverCGNS/DriverCGNS_Write.hxx b/src/DriverCGNS/DriverCGNS_Write.hxx
new file mode 100644 (file)
index 0000000..fbe2435
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright (C) 2007-2011  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
+//
+// 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.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+// File      : DriverCGNS_Write.hxx
+// Created   : Thu Jun 30 10:25:09 2011
+// Author    : Edward AGAPOV (eap)
+
+#ifndef __DriverCGNS_Write_HXX__
+#define __DriverCGNS_Write_HXX__
+
+#include "SMESH_DriverCGNS.hxx"
+
+#include "Driver_SMESHDS_Mesh.h"
+
+#include <vector>
+#include <string>
+
+/*!
+ * \brief Driver writinging a mesh into the CGNS file.
+ */
+class MESHDriverCGNS_EXPORT DriverCGNS_Write : public Driver_SMESHDS_Mesh
+{
+public:
+
+  DriverCGNS_Write();
+  ~DriverCGNS_Write();
+
+  virtual Status Perform();
+
+private:
+
+  int _fn; //!< file index
+};
+
+#endif
diff --git a/src/DriverCGNS/Makefile.am b/src/DriverCGNS/Makefile.am
new file mode 100644 (file)
index 0000000..f7cdab3
--- /dev/null
@@ -0,0 +1,50 @@
+# Copyright (C) 2007-2011  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
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+include $(top_srcdir)/adm_local/unix/make_common_starter.am
+
+# header files 
+salomeinclude_HEADERS = \
+       DriverCGNS_Read.hxx \
+       DriverCGNS_Write.hxx \
+       SMESH_DriverCGNS.hxx
+
+# Libraries targets
+lib_LTLIBRARIES = libMeshDriverCGNS.la
+dist_libMeshDriverCGNS_la_SOURCES = \
+       DriverCGNS_Read.cxx \
+       DriverCGNS_Write.cxx
+
+# additionnal information to compil and link file
+libMeshDriverCGNS_la_CPPFLAGS = \
+       $(KERNEL_CXXFLAGS) \
+       $(CAS_CPPFLAGS) \
+       $(CGNS_INCLUDES) \
+        $(VTK_INCLUDES) \
+       $(BOOST_CPPFLAGS) \
+       -I$(srcdir)/../Driver \
+       -I$(srcdir)/../SMESHUtils \
+       -I$(srcdir)/../SMDS \
+       -I$(srcdir)/../SMESHDS
+
+libMeshDriverCGNS_la_LDFLAGS  = \
+       $(BOOST_LIBS) \
+       $(CGNS_LIBS) \
+       ../Driver/libMeshDriver.la
+       ../Driver/libSMESHUtils.la
diff --git a/src/DriverCGNS/SMESH_DriverCGNS.hxx b/src/DriverCGNS/SMESH_DriverCGNS.hxx
new file mode 100755 (executable)
index 0000000..5f69ca6
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright (C) 2007-2011  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
+//
+// 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.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+//  File   : SMESH_DriverCGNS.hxx
+//  Author : Alexander A. BORODIN
+//  Module : SMESH
+//
+#ifndef _SMESH_DriverCGNS_HXX_
+#define _SMESH_DriverCGNS_HXX_
+
+#ifdef WNT
+ #if defined MESHDriverCGNS_EXPORTS || defined MeshDriverCGNS_EXPORTS
+  #define MESHDriverCGNS_EXPORT __declspec( dllexport )
+ #else
+  #define MESHDriverCGNS_EXPORT __declspec( dllimport )
+ #endif
+#else
+ #define MESHDriverCGNS_EXPORT
+#endif
+
+#endif