Salome HOME
#18963 Minimize compiler warnings
[modules/smesh.git] / src / DriverCGNS / DriverCGNS_Read.cxx
1 // Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 // File      : DriverCGNS_Read.cxx
23 // Created   : Thu Jun 30 10:33:31 2011
24 // Author    : Edward AGAPOV (eap)
25 //#define _DEBUG_
26 #include <utilities.h>
27
28 #include "DriverCGNS_Read.hxx"
29
30 #include "SMDS_MeshNode.hxx"
31 #include "SMESHDS_Group.hxx"
32 #include "SMESHDS_Mesh.hxx"
33 #include "SMESH_Comment.hxx"
34 #include "SMESH_TypeDefs.hxx"
35
36 #include <gp_XYZ.hxx>
37
38 #include <cgnslib.h>
39
40 #include <map>
41
42
43 #if CGNS_VERSION < 3100
44 # define cgsize_t int
45 #endif
46
47 #define NB_ZONE_SIZE_VAL 9
48 #define CGNS_NAME_SIZE 33
49 #define CGNS_STRUCT_RANGE_SZ 6
50
51 using namespace std;
52
53 namespace
54 {
55   //================================================================================
56   /*!
57    * \brief Data of a zone
58    */
59   struct TZoneData
60   {
61     int                    _id;
62     int                    _nodeIdShift; // nb nodes in previously read zones
63     int                    _elemIdShift; // nb faces in previously read zones
64     int                    _nbNodes, _nbElems;
65     int                    _meshDim;
66     int                    _sizeX, _sizeY, _sizeZ, _nbCells; // structured
67     cgsize_t               _sizes[NB_ZONE_SIZE_VAL];
68     CGNS_ENUMT(ZoneType_t) _type;
69     map< int, int >        _nodeReplacementMap;/* key:   id of node to replace (in this zone),
70                                                   value: id of node to replace by (in another zone)
71                                                   id values include _nodeIdShift of the zones */
72     void SetSizeAndDim( cgsize_t* sizes, int meshDim )
73     {
74       _meshDim = meshDim;
75       memcpy( _sizes, sizes, NB_ZONE_SIZE_VAL*sizeof(cgsize_t));
76       _sizeX = _sizes[0];
77       _sizeY = _meshDim > 1 ? _sizes[1] : 0;
78       _sizeZ = _meshDim > 2 ? _sizes[2] : 0;
79       _nbCells = (_sizeX - 1) * ( _meshDim > 1 ? _sizeY : 1 ) * ( _meshDim > 2 ? _sizeZ : 1 );
80     }
81     bool IsStructured() const { return ( _type == CGNS_ENUMV( Structured )); }
82     int IndexSize() const { return IsStructured() ? _meshDim : 1; }
83     string ReadZonesConnection(int file, int base,
84                                const map< string, TZoneData >& zonesByName,
85                                SMESHDS_Mesh*                   mesh);
86     void ReplaceNodes( cgsize_t* ids, int nbIds, int idShift = 0 ) const;
87
88     // Methods for a structured zone
89
90     int NodeID( int i, int j, int k = 1 ) const
91     {
92       return _nodeIdShift + (k-1)*_sizeX*_sizeY + (j-1)*_sizeX + i;
93     }
94     int NodeID( const gp_XYZ& ijk ) const
95     {
96       return NodeID( int(ijk.X()), int(ijk.Y()), int(ijk.Z()));
97     }
98     void CellNodes( int i, int j, int k, cgsize_t* ids ) const
99     {
100       ids[0] = NodeID( i  , j  , k  );
101       ids[1] = NodeID( i  , j+1, k  );
102       ids[2] = NodeID( i+1, j+1, k  );
103       ids[3] = NodeID( i+1, j  , k  );
104       ids[4] = NodeID( i  , j  , k+1);
105       ids[5] = NodeID( i  , j+1, k+1);
106       ids[6] = NodeID( i+1, j+1, k+1);
107       ids[7] = NodeID( i+1, j  , k+1);
108     }
109     void CellNodes( int i, int j, cgsize_t* ids ) const
110     {
111       ids[0] = NodeID( i  , j   );
112       ids[1] = NodeID( i  , j+1 );
113       ids[2] = NodeID( i+1, j+1 );
114       ids[3] = NodeID( i+1, j   );
115     }
116     void IFaceNodes( int i, int j, int k, cgsize_t* ids ) const // face perpendiculaire to X (3D)
117     {
118       ids[0] = NodeID( i, j, k );
119       ids[1] = ids[0] + _sizeX*( i==_sizeX ? 1 : _sizeY );
120       ids[2] = ids[0] + _sizeX*( _sizeY + 1 );
121       ids[3] = ids[0] + _sizeX*( i==_sizeX ? _sizeY : 1 );
122     }
123     void JFaceNodes( int i, int j, int k, cgsize_t* ids ) const
124     {
125       ids[0] = NodeID( i, j, k );
126       ids[1] = ids[0] + ( j==_sizeY ? _sizeX*_sizeY : 1);
127       ids[2] = ids[0] + _sizeX*_sizeY + 1;
128       ids[3] = ids[0] + ( j==_sizeY ? 1 : _sizeX*_sizeY);
129     }
130     void KFaceNodes( int i, int j, int k, cgsize_t* ids ) const
131     {
132       ids[0] = NodeID( i, j, k );
133       ids[1] = ids[0] + ( k==_sizeZ ? 1 : _sizeX);
134       ids[2] = ids[0] + _sizeX + 1;
135       ids[3] = ids[0] + ( k==_sizeZ ? _sizeX : 1);
136     }
137     void IEdgeNodes( int i, int j, int /*k*/, cgsize_t* ids ) const // edge perpendiculaire to X (2D)
138     {
139       ids[0] = NodeID( i, j, 0 );
140       ids[1] = ids[0] + _sizeX;
141     }
142     void JEdgeNodes( int i, int j, int /*k*/, cgsize_t* ids ) const
143     {
144       ids[0] = NodeID( i, j, 0 );
145       ids[1] = ids[0] + 1;
146     }
147 #define gpXYZ2IJK(METHOD)                                     \
148     void METHOD( const gp_XYZ& ijk, cgsize_t* ids ) const {        \
149       METHOD( int(ijk.X()), int(ijk.Y()), int(ijk.Z()), ids); \
150     }
151     gpXYZ2IJK( IFaceNodes )
152     gpXYZ2IJK( JFaceNodes )
153     gpXYZ2IJK( KFaceNodes )
154     gpXYZ2IJK( IEdgeNodes )
155     gpXYZ2IJK( JEdgeNodes )
156   };
157
158   //================================================================================
159   /*!
160    * \brief Iterator over nodes of the structired grid using FORTRAN multidimensional
161    * array ordering.
162    */
163   class TPointRangeIterator
164   {
165     int _beg[3], _end[3], _cur[3], _dir[3], _dim;
166     bool _more;
167   public:
168     TPointRangeIterator( const cgsize_t* range, int dim ):_dim(dim)
169     {
170       _more = false;
171       for ( int i = 0; i < dim; ++i )
172       {
173         _beg[i] = range[i];
174         _end[i] = range[i+dim];
175         _dir[i] = _end[i] < _beg[i] ? -1 : 1;
176         _end[i] += _dir[i];
177         _cur[i] = _beg[i];
178         if ( _end[i] - _beg[i] )
179           _more = true;
180       }
181 //       for ( int i = dim; i < 3; ++i )
182 //         _cur[i] = _beg[i] = _end[i] = _dir[i] = 0;
183     }
184     bool More() const
185     {
186       return _more;
187     }
188     gp_XYZ Next()
189     {
190       gp_XYZ res( _cur[0], _cur[1], _cur[2] ); // todo: _cur can be used uninitialized
191       for ( int i = 0; i < _dim; ++i )
192       {
193         _cur[i] += _dir[i];
194         if ( _cur[i]*_dir[i] < _end[i]*_dir[i] )
195           break;
196         if ( i+1 < _dim )
197           _cur[i] = _beg[i];
198         else
199           _more = false;
200       }
201       return res;
202     }
203     size_t Size()  const
204     {
205       size_t size = 1;
206       for ( int i = 0; i < _dim; ++i )
207         size *= _dir[i]*(_end[i]-_beg[i]);
208       return size;
209     }
210     gp_XYZ Begin() const { return gp_XYZ( _beg[0], _beg[1], _beg[2] ); }  // todo: _beg can be used uninitialized
211     //gp_XYZ End() const { return gp_XYZ( _end[0]-1, _end[1]-1, _end[2]-1 ); }
212   };
213
214   //================================================================================
215   /*!
216    * \brief Checks if the two arrays of node IDs describe nodes with equal coordinates
217    */
218   //================================================================================
219
220   bool isEqualNodes( const int* nIds1, const int* nIds2, int nbNodes, SMESHDS_Mesh* mesh )
221   {
222     if ( nbNodes > 0 )
223     {
224       SMESH_TNodeXYZ nn1[2], nn2[2];
225       nn1[0] = mesh->FindNode( nIds1[0] );
226       nn2[0] = mesh->FindNode( nIds2[0] );
227       if ( !nn1[0]._node || !nn2[0]._node )
228         return false;
229       double dist1 = ( nn1[0] - nn2[0] ).Modulus();
230       double dist2 = 0, tol = 1e-7;
231       if ( nbNodes > 1 )
232       {
233         nn1[1] = mesh->FindNode( nIds1[1] );
234         nn2[1] = mesh->FindNode( nIds2[1] );
235         if ( !nn1[1]._node || !nn2[1]._node )
236           return false;
237         dist2 = ( nn1[1] - nn2[1] ).Modulus();
238         tol   = 1e-5 * ( nn1[0] - nn1[1] ).Modulus();
239       }
240       return ( dist1 < tol && dist2 < tol );
241     }
242     return false;
243   }
244
245   //================================================================================
246   /*!
247    * \brief Reads zone interface connectivity
248    *  \param file - file to read
249    *  \param base - base to read
250    *  \param zone - zone to replace nodes in
251    *  \param zonesByName - TZoneData by name
252    *  \retval string - warning message
253    *
254    * see // http://www.grc.nasa.gov/WWW/cgns/CGNS_docs_current/sids/cnct.html
255    */
256   //================================================================================
257
258   string TZoneData::ReadZonesConnection( int                             file,
259                                          int                             base,
260                                          const map< string, TZoneData >& zonesByName,
261                                          SMESHDS_Mesh*                   mesh)
262   {
263     string error;
264
265     char connectName[ CGNS_NAME_SIZE ], donorName [ CGNS_NAME_SIZE ];
266
267     // ----------------------------
268     // read zone 1 to 1 interfaces
269     // ----------------------------
270     if ( IsStructured() )
271     {
272       int nb1to1 = 0;
273       if ( cg_n1to1 ( file, base, _id, &nb1to1) == CG_OK )
274       {
275         cgsize_t range[CGNS_STRUCT_RANGE_SZ], donorRange[CGNS_STRUCT_RANGE_SZ];
276         int transform[3] = {0,0,0};
277
278         for ( int I = 1; I <= nb1to1; ++I )
279         {
280           if ( cg_1to1_read(file, base, _id, I, connectName,
281                             donorName, range, donorRange, transform) == CG_OK )
282           {
283             map< string, TZoneData>::const_iterator n_z = zonesByName.find( donorName );
284             if ( n_z == zonesByName.end() )
285               continue; // donor zone not yet read
286             const TZoneData& zone2 = n_z->second;
287
288             // set up matrix to transform ijk of the zone to ijk of the zone2
289             gp_Mat T;
290             for ( int i = 0; i < _meshDim; ++i )
291               if ( transform[i] )
292               {
293                 int row = Abs(transform[i]);
294                 int col = i+1;
295                 int val = transform[i] > 0 ? +1 : -1;
296                 T( row, col ) = val;
297               }
298
299             // fill nodeReplacementMap
300             TPointRangeIterator rangeIt1( range, _meshDim );  // todo: rangeIt1: _end[i], _dir[i], _beg[i], _cur[i] may be used uninitialized
301             TPointRangeIterator rangeIt2( donorRange, _meshDim );
302             gp_XYZ begin1 = rangeIt1.Begin(), begin2 = rangeIt2.Begin(), index1, index2;
303             if ( &zone2 == this )
304             {
305               // not to read twice the same interface with self
306               TPointRangeIterator rangeIt1bis( range, _meshDim );
307               if ( rangeIt1bis.More() )
308               {
309                 index1 = rangeIt1bis.Next();
310                 index2 = T * ( index1 - begin1 ) + begin2;
311                 int node1 = NodeID( index1 );
312                 int node2 = zone2.NodeID( index2 );
313                 if ( _nodeReplacementMap.count( node2 ) &&
314                      _nodeReplacementMap[ node2 ] == node1 )
315                   continue; // this interface already read
316               }
317             }
318             // check if range and donorRange describe the same nodes
319             {
320               int ids1[2], ids2[2], nbN = 0;
321               TPointRangeIterator rangeIt1bis( range, _meshDim );
322               index1 = rangeIt1bis.Next();
323               index2 = T * ( index1 - begin1 ) + begin2;
324               ids1[0] = NodeID( index1 );
325               ids2[0] = zone2.NodeID( index2 );
326               ++nbN;
327               if ( rangeIt1bis.More() )
328               {
329                 index1 = rangeIt1bis.Next();
330                 index2 = T * ( index1 - begin1 ) + begin2;
331                 ids1[1] = NodeID( index1 );
332                 ids2[1] = zone2.NodeID( index2 );
333                 ++nbN;
334               }
335               if ( !isEqualNodes( &ids1[0], &ids2[0], nbN, mesh ))
336                 continue;
337             }
338             while ( rangeIt1.More() )
339             {
340               index1 = rangeIt1.Next();
341               index2 = T * ( index1 - begin1 ) + begin2;
342               int node1 = NodeID( index1 );
343               int node2 = zone2.NodeID( index2 );
344               _nodeReplacementMap.insert( make_pair( node1, node2 ));
345             }
346           }
347           else
348           {
349             error = cg_get_error();
350           }
351         }
352       }
353       else
354       {
355         error = cg_get_error();
356       }
357     }
358
359     // ---------------------------------
360     // read general zone connectivities
361     // ---------------------------------
362     int nbConn = 0;
363     if ( cg_nconns( file, base, _id, &nbConn) == CG_OK )
364     {
365       cgsize_t nb, donorNb;
366       CGNS_ENUMT(GridLocation_t) location;
367       CGNS_ENUMT(GridConnectivityType_t) connectType;
368       CGNS_ENUMT(PointSetType_t) ptype, donorPtype;
369       CGNS_ENUMT(ZoneType_t) donorZonetype;
370       CGNS_ENUMT(DataType_t) donorDatatype;
371
372       for ( int I = 1; I <= nbConn; ++I )
373       {
374         if ( cg_conn_info(file, base, _id, I, connectName, &location, &connectType,
375                           &ptype, &nb, donorName, &donorZonetype, &donorPtype,
376                           &donorDatatype, &donorNb ) == CG_OK )
377         {
378           if ( location != CGNS_ENUMV( Vertex ))
379             continue; // we do not support cell-to-cell connectivity
380           if ( ptype != CGNS_ENUMV( PointList ) &&
381                ptype != CGNS_ENUMV( PointRange ))
382             continue;
383           if ( donorPtype != CGNS_ENUMV( PointList ) &&
384                donorPtype != CGNS_ENUMV( PointRange ))
385             continue;
386           
387           map< string, TZoneData>::const_iterator n_z = zonesByName.find( donorName );
388           if ( n_z == zonesByName.end() )
389             continue; // donor zone not yet read
390           const TZoneData& zone2 = n_z->second;
391
392           vector< cgsize_t > ids( nb * IndexSize() );
393           vector< cgsize_t > donorIds( donorNb * zone2.IndexSize() );
394           if (cg_conn_read ( file, base, _id, I,
395                              &ids[0], CGNS_ENUMV(Integer), &donorIds[0]) == CG_OK )
396           {
397             for ( int isThisZone = 0; isThisZone < 2; ++isThisZone )
398             {
399               const TZoneData&           zone = isThisZone ? *this : zone2;
400               CGNS_ENUMT(PointSetType_t) type = isThisZone ? ptype : donorPtype;
401               vector< cgsize_t >&      points = isThisZone ? ids : donorIds;
402               if ( type == CGNS_ENUMV( PointRange ))
403               {
404                 TPointRangeIterator rangeIt( &points[0], zone._meshDim );
405                 points.clear();
406                 while ( rangeIt.More() )
407                   points.push_back ( NodeID( rangeIt.Next() ));
408               }
409               else if ( zone.IsStructured() )
410               {
411                 vector< cgsize_t > resIDs; resIDs.reserve( points.size() / IndexSize() );
412                 for ( size_t i = 0; i < points.size(); i += IndexSize() )
413                   resIDs.push_back( zone.NodeID( points[i+0], points[i+1], points[i+2] ));
414                 resIDs.swap( points );
415               }
416               else if ( zone._nodeIdShift > 0 )
417               {
418                 for ( size_t i = 0; i < points.size(); ++i )
419                   points[i] += zone._nodeIdShift;
420               }
421             }
422             size_t nbN = std::min( ids.size(), donorIds.size());
423             if ( isEqualNodes( &ids[0], &donorIds[0], nbN, mesh ))
424               for ( size_t i = 0; i < nbN; ++i )
425                 _nodeReplacementMap.insert( make_pair( ids[i], donorIds[i] ));
426           }
427           else
428           {
429             error = cg_get_error();
430           }
431         }
432         else
433         {
434           error = cg_get_error();
435         }
436       }
437     }
438     else
439     {
440       error = cg_get_error();
441     }
442     return error;
443   }
444
445   //================================================================================
446   /*!
447    * \brief Replaces node ids according to nodeReplacementMap to take into account
448    *        connection of zones
449    */
450   //================================================================================
451
452   void TZoneData::ReplaceNodes( cgsize_t* ids, int nbIds, int idShift/* = 0*/ ) const
453   {
454     if ( !_nodeReplacementMap.empty() )
455     {
456       map< int, int >::const_iterator it, end = _nodeReplacementMap.end();
457       for ( int i = 0; i < nbIds; ++i )
458         if (( it = _nodeReplacementMap.find( ids[i] + idShift)) != end )
459           ids[i] = it->second;
460         else
461           ids[i] += idShift;
462     }
463     else if ( idShift )
464     {
465       for ( int i = 0; i < nbIds; ++i )
466         ids[i] += idShift;
467     }
468   }
469   //================================================================================
470   /*!
471    * \brief functions adding an element of a particular type
472    */
473   SMDS_MeshElement* add_0D(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
474   {
475     return mesh->Add0DElementWithID( ids[0], ID );
476   }
477   SMDS_MeshElement* add_BAR_2(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
478   {
479     return mesh->AddEdgeWithID( ids[0], ids[1], ID );
480   }
481   SMDS_MeshElement* add_BAR_3(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
482   {
483     return mesh->AddEdgeWithID( ids[0], ids[1], ids[2], ID );
484   }
485   SMDS_MeshElement* add_TRI_3(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
486   {
487     return mesh->AddFaceWithID( ids[0], ids[2], ids[1], ID );
488   }
489   SMDS_MeshElement* add_TRI_6(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
490   {
491     return mesh->AddFaceWithID( ids[0], ids[2], ids[1], ids[5], ids[4], ids[3], ID );
492   }
493   SMDS_MeshElement* add_QUAD_4(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
494   {
495     return mesh->AddFaceWithID( ids[0], ids[3], ids[2], ids[1], ID );
496   }
497   SMDS_MeshElement* add_QUAD_8(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
498   {
499     return mesh->AddFaceWithID( ids[0],ids[3],ids[2],ids[1],ids[7],ids[6],ids[5],ids[4], ID );
500   }
501   SMDS_MeshElement* add_QUAD_9(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
502   {
503     return mesh->AddFaceWithID( ids[0],ids[3],ids[2],ids[1],ids[7],ids[6],ids[5],ids[4],ids[8], ID);
504   }
505   SMDS_MeshElement* add_TETRA_4(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
506   {
507     return mesh->AddVolumeWithID( ids[0], ids[2], ids[1], ids[3], ID );
508   }
509   SMDS_MeshElement* add_TETRA_10(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
510   {
511     return mesh->AddVolumeWithID( ids[0],ids[2],ids[1],ids[3],ids[6],
512                                   ids[5],ids[4],ids[7],ids[9],ids[8], ID );
513   }
514   SMDS_MeshElement* add_PYRA_5(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
515   {
516     return mesh->AddVolumeWithID( ids[0],ids[3],ids[2],ids[1],ids[4],ID );
517   }
518   SMDS_MeshElement* add_PYRA_13(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
519   {
520     return mesh->AddVolumeWithID( ids[0],ids[3],ids[2],ids[1],ids[4],ids[8],ids[7],
521                                   ids[6],ids[5],ids[9],ids[12],ids[11],ids[10], ID );
522   }
523   SMDS_MeshElement* add_PENTA_6(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
524   {
525     return mesh->AddVolumeWithID( ids[0],ids[2],ids[1],ids[3],ids[5],ids[4], ID );
526   }
527   SMDS_MeshElement* add_PENTA_15(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
528   {
529     return mesh->AddVolumeWithID( ids[0],ids[2],ids[1],ids[3],ids[5],ids[4],ids[8],ids[7],
530                                   ids[6],ids[9],ids[11],ids[10],ids[14],ids[13],ids[12], ID );
531   }
532   SMDS_MeshElement* add_HEXA_8(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
533   {
534     return mesh->AddVolumeWithID( ids[0],ids[3],ids[2],ids[1],ids[4],ids[7],ids[6],ids[5], ID );
535   }
536   SMDS_MeshElement* add_HEXA_20(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
537   {
538     return mesh->AddVolumeWithID( ids[0],ids[3],ids[2],ids[1],ids[4],ids[7],ids[6],
539                                   ids[5],ids[11],ids[10],ids[9],ids[8],ids[12],ids[15],
540                                   ids[14],ids[13],ids[19],ids[18],ids[17],ids[16], ID );
541   }
542   SMDS_MeshElement* add_HEXA_27(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
543   {
544     return mesh->AddVolumeWithID( ids[0],ids[3],ids[2],ids[1],ids[4],ids[7],ids[6],
545                                   ids[5],ids[11],ids[10],ids[9],ids[8],ids[12],ids[15],
546                                   ids[14],ids[13],ids[19],ids[18],ids[17],ids[16],
547                                   ids[20],ids[24],ids[23],ids[22],ids[21],ids[25],ids[26], ID );
548   }
549   SMDS_MeshElement* add_NGON(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID)
550   {
551     vector<int> idVec( ids[0] );
552     for ( int i = 0; i < ids[0]; ++i )
553       idVec[ i ] = (int) ids[ i + 1];
554     return mesh->AddPolygonalFaceWithID( idVec, ID );
555   }
556
557   typedef SMDS_MeshElement* (* PAddElemFun) (cgsize_t* ids, SMESHDS_Mesh* mesh, int ID);
558   
559   //================================================================================
560   /*!
561    * \brief Return an array of functions each adding an element of a particular type
562    */
563   //================================================================================
564
565   PAddElemFun* getAddElemFunTable()
566   {
567     static vector< PAddElemFun > funVec;
568     if ( funVec.empty() )
569     {
570       funVec.resize( NofValidElementTypes, (PAddElemFun)0 );
571       funVec[ CGNS_ENUMV( NODE     )] = add_0D      ;
572       funVec[ CGNS_ENUMV( BAR_2    )] = add_BAR_2   ;
573       funVec[ CGNS_ENUMV( BAR_3    )] = add_BAR_3   ;
574       funVec[ CGNS_ENUMV( TRI_3    )] = add_TRI_3   ;
575       funVec[ CGNS_ENUMV( TRI_6    )] = add_TRI_6   ;
576       funVec[ CGNS_ENUMV( QUAD_4   )] = add_QUAD_4  ;
577       funVec[ CGNS_ENUMV( QUAD_8   )] = add_QUAD_8  ;
578       funVec[ CGNS_ENUMV( QUAD_9   )] = add_QUAD_9  ;
579       funVec[ CGNS_ENUMV( TETRA_4  )] = add_TETRA_4 ;
580       funVec[ CGNS_ENUMV( TETRA_10 )] = add_TETRA_10;
581       funVec[ CGNS_ENUMV( PYRA_5   )] = add_PYRA_5  ;
582       funVec[ CGNS_ENUMV( PYRA_13  )] = add_PYRA_13 ;
583       funVec[ CGNS_ENUMV( PYRA_14  )] = add_PYRA_13 ;
584       funVec[ CGNS_ENUMV( PENTA_6  )] = add_PENTA_6 ;
585       funVec[ CGNS_ENUMV( PENTA_15 )] = add_PENTA_15;
586       funVec[ CGNS_ENUMV( PENTA_18 )] = add_PENTA_15;
587       funVec[ CGNS_ENUMV( HEXA_8   )] = add_HEXA_8  ;
588       funVec[ CGNS_ENUMV( HEXA_20  )] = add_HEXA_20 ;
589       funVec[ CGNS_ENUMV( HEXA_27  )] = add_HEXA_27 ;
590       funVec[ CGNS_ENUMV( NGON_n   )] = add_NGON    ;
591     }
592     return &funVec[0];
593   }
594
595   //================================================================================
596   /*!
597    * \brief Finds an existing boundary element
598    */
599   //================================================================================
600
601   const SMDS_MeshElement* findElement(const cgsize_t*     nodeIDs,
602                                       const int           nbNodes,
603                                       const SMESHDS_Mesh* mesh)
604   {
605     const SMDS_MeshNode* nn[4]; // look for quad4 or seg2
606     if (( nn[0] = mesh->FindNode( nodeIDs[0] )))
607     {
608       SMDSAbs_ElementType eType = nbNodes==4 ? SMDSAbs_Face : SMDSAbs_Edge;
609       SMDS_ElemIteratorPtr eIt = nn[0]->GetInverseElementIterator( eType );
610       if ( eIt->more() )
611         for ( int i = 1; i < nbNodes; ++i )
612           nn[i] = mesh->FindNode( nodeIDs[i] );
613       while ( eIt->more() )
614       {
615         const SMDS_MeshElement* e = eIt->next();
616         if ( e->NbNodes() == nbNodes )
617         {
618           bool elemOK = true;
619           for ( int i = 1; i < nbNodes && elemOK; ++i )
620             elemOK = ( e->GetNodeIndex( nn[i] ) >= 0 );
621           if ( elemOK )
622             return e;
623         }
624       } 
625     }
626     return 0;
627   }
628
629 } // namespace
630
631 //================================================================================
632 /*!
633  * \brief Perform reading a myMeshId-th mesh
634  */
635 //================================================================================
636
637 Driver_Mesh::Status DriverCGNS_Read::Perform()
638 {
639   MESSAGE("DriverCGNS_Read::Perform");
640   myErrorMessages.clear();
641
642   Status aResult;
643   if (( aResult = open() ) != DRS_OK )
644     return aResult;
645
646   // read nb of meshes (CGNSBase_t)
647   if ( myMeshId < 0 || myMeshId >= GetNbMeshes(aResult))
648     return addMessage( SMESH_Comment("Invalid mesh index :") << myMeshId );
649   MESSAGE("NbMeshes: " << GetNbMeshes(aResult));
650
651   // read a name and a dimension of the mesh
652   const int cgnsBase = myMeshId + 1;
653   char meshName[CGNS_NAME_SIZE];
654   int meshDim, spaceDim;
655   if ( cg_base_read( _fn, cgnsBase, meshName, &meshDim, &spaceDim) != CG_OK )
656     return addMessage( cg_get_error() );
657
658   if ( spaceDim < 1 || spaceDim > 3 )
659     return addMessage( SMESH_Comment("Invalid space dimension: ") << spaceDim
660                        << " in mesh '" << meshName << "'");
661
662   myMeshName = meshName;
663   MESSAGE("myMeshName: " << myMeshName);
664
665
666   // read nb of domains (Zone_t) in the mesh
667   int nbZones = 0;
668   if ( cg_nzones (_fn, cgnsBase, &nbZones) != CG_OK )
669     return addMessage( cg_get_error() );
670
671   if ( nbZones < 1 )
672     return addMessage( SMESH_Comment("Empty mesh: '") << meshName << "'");
673   MESSAGE("nbZones: " << nbZones);
674
675   // read the domains (zones)
676   // ------------------------
677   map< string, TZoneData > zonesByName;
678   char name[CGNS_NAME_SIZE];
679   cgsize_t sizes[NB_ZONE_SIZE_VAL];
680   memset(sizes, 0, NB_ZONE_SIZE_VAL * sizeof(cgsize_t));
681
682   const SMDS_MeshInfo& meshInfo = myMesh->GetMeshInfo();
683   int groupID = myMesh->GetGroups().size();
684
685   for ( int iZone = 1; iZone <= nbZones; ++iZone )
686   {
687     // size and name of a zone
688     if ( cg_zone_read( _fn, cgnsBase, iZone, name, sizes) != CG_OK) {
689       addMessage( cg_get_error() );
690       continue;
691     }
692     TZoneData& zone = zonesByName[ name ];
693     zone._id          = iZone;
694     zone._nodeIdShift = meshInfo.NbNodes();
695     zone._elemIdShift = meshInfo.NbElements();
696     zone.SetSizeAndDim( sizes, meshDim );
697     MESSAGE("  zone name: " << name);
698
699     // mesh type of the zone
700     if ( cg_zone_type ( _fn, cgnsBase, iZone, &zone._type) != CG_OK) {
701       addMessage( cg_get_error() );
702       continue;
703     }
704
705     switch ( zone._type )
706     {
707     case CGNS_ENUMV( Unstructured ):
708       MESSAGE("  zone type: unstructured");
709       break;
710     case CGNS_ENUMV( Structured ):
711       MESSAGE("  zone type: structured");
712       break;
713     case CGNS_ENUMV( ZoneTypeNull ):
714       addMessage( "Meshes with ZoneTypeNull are not supported");
715       continue;
716     case CGNS_ENUMV( ZoneTypeUserDefined ):
717       addMessage( "Meshes with ZoneTypeUserDefined are not supported");
718       continue;
719     default:
720       addMessage( "Unknown ZoneType_t");
721       continue;
722     }
723
724     // -----------
725     // Read nodes
726     // -----------
727     MESSAGE("  Read nodes");
728     if ( cg_ncoords( _fn, cgnsBase, iZone, &spaceDim) != CG_OK ) {
729       addMessage( cg_get_error() );
730       continue;
731     }
732     if ( spaceDim < 1 ) {
733       addMessage( SMESH_Comment("No coordinates defined in zone ")
734                   << iZone << " of Mesh " << myMeshId );
735       continue;
736     }
737     // read coordinates
738
739     MESSAGE("  Read coordinates");
740     cgsize_t rmin[3] = {1,1,1}; // range of nodes to read
741     cgsize_t rmax[3] = {1,1,1};
742     int nbNodes = rmax[0] = zone._sizes[0];
743     if ( zone.IsStructured())
744       for ( int i = 1; i < meshDim; ++i )
745         nbNodes *= rmax[i] = zone._sizes[i];
746
747     vector<double> coords[3];
748     for ( int c = 1; c <= spaceDim; ++c)
749     {
750       coords[c-1].resize( nbNodes );
751
752       CGNS_ENUMV( DataType_t ) type;
753       if ( cg_coord_info( _fn, cgnsBase, iZone, c, &type, name) != CG_OK ||
754            cg_coord_read( _fn, cgnsBase, iZone, name, CGNS_ENUMV(RealDouble),
755                           rmin, rmax, (void*)&(coords[c-1][0])) != CG_OK)
756       {
757         addMessage( cg_get_error() );
758         coords[c-1].clear();
759         break;
760       }
761     }
762     if ( coords[ spaceDim-1 ].empty() )
763       continue; // there was an error while reading coordinates 
764
765     // fill coords with zero if spaceDim < 3
766     for ( int c = 2; c <= 3; ++c)
767       if ( coords[ c-1 ].empty() )
768         coords[ c-1 ].resize( nbNodes, 0.0 );
769
770     // create nodes
771     MESSAGE("  create nodes");
772     try {
773       for ( int i = 0; i < nbNodes; ++i )
774         myMesh->AddNodeWithID( coords[0][i], coords[1][i], coords[2][i], i+1+zone._nodeIdShift );
775     }
776     catch ( std::exception& exc ) // expect std::bad_alloc
777     {
778       addMessage( exc.what() );
779       break;
780     }
781
782     // Read connectivity between zones. Nodes of the zone interface will be
783     // replaced within the zones read later
784     string err = zone.ReadZonesConnection( _fn, cgnsBase, zonesByName, myMesh );
785     if ( !err.empty() )
786       addMessage( err );
787
788     // --------------
789     // Read elements
790     // --------------
791     MESSAGE("  read elements");
792     if ( zone.IsStructured())
793     {
794       int nbI = zone._sizeX - 1, nbJ = zone._sizeY - 1, nbK = zone._sizeZ - 1;
795       cgsize_t nID[8];
796       if ( meshDim > 2 && nbK > 0 )
797       {
798         for ( int k = 1; k <= nbK; ++k )
799           for ( int j = 1; j <= nbJ; ++j )
800             for ( int i = 1; i <= nbI; ++i )
801             {
802               zone.CellNodes( i, j, k, nID );
803               zone.ReplaceNodes( nID, 8 );
804               myMesh->AddVolumeWithID(nID[0],nID[1],nID[2],nID[3],nID[4],nID[5],nID[6],nID[7],
805                                       meshInfo.NbElements()+1);
806             }
807       }
808       else if ( meshDim > 1 && nbJ > 0 )
809       {
810         for ( int j = 1; j <= nbJ; ++j )
811           for ( int i = 1; i <= nbI; ++i )
812           {
813             zone.CellNodes( i, j, nID );
814             zone.ReplaceNodes( nID, 4 );
815             myMesh->AddFaceWithID(nID[0],nID[1],nID[2],nID[3], meshInfo.NbElements()+1);
816           }
817       }
818       else if ( meshDim > 0 && nbI > 0 )
819       {
820         nID[0] = zone.NodeID( 1, 0, 0 );
821         for ( int i = 1; i <= nbI; ++i, ++nID[0] )
822         {
823           nID[1] = nID[0]+1;
824           zone.ReplaceNodes( nID, 2 );
825           myMesh->AddEdgeWithID(nID[0],nID[1], meshInfo.NbElements()+1);
826         }
827       }
828     }
829     else
830     {
831       // elements can be stored in different sections each dedicated to one element type
832       int nbSections = 0;
833       if ( cg_nsections( _fn, cgnsBase, iZone, &nbSections) != CG_OK)
834       {
835         addMessage( cg_get_error() );
836         continue;
837       }
838       PAddElemFun* addElemFuns = getAddElemFunTable(), curAddElemFun = 0;
839       int nbNotSuppElem = 0; // nb elements of not supported types
840       bool polyhedError = false; // error at polyhedron creation
841
842       // read element data
843
844       MESSAGE("  read element data");
845       CGNS_ENUMT( ElementType_t ) elemType;
846       cgsize_t start, end; // range of ids of elements of a zone
847       cgsize_t eDataSize = 0;
848       int nbBnd, parent_flag;
849       for ( int iSec = 1; iSec <= nbSections; ++iSec )
850       {
851         MESSAGE("  section " << iSec << " of " << nbSections);
852         if ( cg_section_read( _fn, cgnsBase, iZone, iSec, name, &elemType,
853                               &start, &end, &nbBnd, &parent_flag) != CG_OK ||
854              cg_ElementDataSize( _fn, cgnsBase, iZone, iSec, &eDataSize ) != CG_OK )
855         {
856           addMessage( cg_get_error() );
857           continue;
858         }
859         vector< cgsize_t > elemData( eDataSize );
860         if ( cg_elements_read( _fn, cgnsBase, iZone, iSec, &elemData[0], NULL ) != CG_OK )
861         {
862           addMessage( cg_get_error() );
863           continue;
864         }
865         // store elements
866
867         MESSAGE("   store elements");
868         int pos = 0, cgnsNbNodes = 0, elemID = start + zone._elemIdShift;
869         cg_npe( elemType, &cgnsNbNodes ); // get nb nodes by element type
870         curAddElemFun = addElemFuns[ elemType ];
871         SMDS_MeshElement* newElem = 0;
872         const SMDS_MeshElement* face;
873
874         while ( pos < eDataSize )
875         {
876           CGNS_ENUMT( ElementType_t ) currentType = elemType;
877           if ( currentType == CGNS_ENUMV( MIXED )) {
878             //ElementConnectivity = Etype1, Node11, Node21, ... NodeN1,
879             //                      Etype2, Node12, Node22, ... NodeN2,
880             //                      ...
881             //                      EtypeM, Node1M, Node2M, ... NodeNM
882             currentType = (CGNS_ENUMT(ElementType_t)) elemData[ pos++ ];
883             cg_npe( currentType, &cgnsNbNodes );
884             curAddElemFun = addElemFuns[ currentType ];
885           }
886           if ( cgnsNbNodes < 1 ) // poly elements
887           {
888             if ( currentType == CGNS_ENUMV( NFACE_n )) // polyhedron
889             {
890               //ElementConnectivity = Nfaces1, Face11, Face21, ... FaceN1,
891               //                      Nfaces2, Face12, Face22, ... FaceN2,
892               //                      ...
893               //                      NfacesM, Face1M, Face2M, ... FaceNM
894               const int nbFaces = elemData[ pos++ ];
895               vector<int> quantities( nbFaces );
896               vector<const SMDS_MeshNode*> nodes, faceNodes;
897               nodes.reserve( nbFaces * 4 );
898               for ( int iF = 0; iF < nbFaces; ++iF )
899               {
900                 const int faceID = std::abs( elemData[ pos++ ]) + zone._elemIdShift; 
901                 if (( face = myMesh->FindElement( faceID )) && face->GetType() == SMDSAbs_Face )
902                 {
903                   const bool reverse = ( elemData[ pos-1 ] < 0 );
904                   const int    iQuad = face->IsQuadratic() ? 1 : 0;
905                   SMDS_NodeIteratorPtr nIter = face->interlacedNodesIterator();
906                   faceNodes.assign( SMDS_MeshElement::iterator( nIter ),
907                                     SMDS_MeshElement::iterator());
908                   if ( iQuad && reverse )
909                     nodes.push_back( faceNodes[0] );
910                   if ( reverse )
911                     nodes.insert( nodes.end(), faceNodes.rbegin(), faceNodes.rend() - iQuad );
912                   else
913                     nodes.insert( nodes.end(), faceNodes.begin(), faceNodes.end() );
914
915                   quantities[ iF ] = face->NbNodes();
916                 }
917                 else {
918                   polyhedError = true;
919                   break;
920                 }
921               }
922               if ( quantities.back() )
923               {
924                 myMesh->AddPolyhedralVolumeWithID( nodes, quantities, elemID );
925               }
926             }
927             else if ( currentType == CGNS_ENUMV( NGON_n )) // polygon
928             {
929               // ElementConnectivity = Nnodes1, Node11, Node21, ... NodeN1,
930               //                       Nnodes2, Node12, Node22, ... NodeN2,
931               //                       ...
932               //                       NnodesM, Node1M, Node2M, ... NodeNM
933               const int nbNodes = elemData[ pos ];
934               zone.ReplaceNodes( &elemData[pos+1], nbNodes, zone._nodeIdShift );
935               newElem = add_NGON( &elemData[pos  ], myMesh, elemID );
936               pos += nbNodes + 1;
937             }
938           }
939           else // standard elements
940           {
941             zone.ReplaceNodes( &elemData[pos], cgnsNbNodes, zone._nodeIdShift );
942             newElem = curAddElemFun( &elemData[pos], myMesh, elemID );
943             pos += cgnsNbNodes;
944             nbNotSuppElem += int( newElem && newElem->NbNodes() != cgnsNbNodes );
945           }
946           elemID++;
947
948         } // loop on elemData
949       } // loop on cgns sections
950
951       if ( nbNotSuppElem > 0 )
952         addMessage( SMESH_Comment(nbNotSuppElem) << " elements of not supported types"
953                     << " have beem converted to close types");
954       if ( polyhedError )
955         addMessage( "Some polyhedral elements have been skipped due to internal(?) errors" );
956
957     } // reading unstructured elements
958
959     zone._nbNodes = meshInfo.NbNodes() - zone._nodeIdShift;
960     zone._nbElems = meshInfo.NbElements() - zone._elemIdShift;
961
962     // -------------------------------------------
963     // Read Boundary Conditions into SMESH groups
964     // -------------------------------------------
965     
966     MESSAGE("  read Boundary Conditions");
967     int nbBC = 0;
968     if ( cg_nbocos( _fn, cgnsBase, iZone, &nbBC) == CG_OK )
969     {
970       CGNS_ENUMT( BCType_t ) bcType;
971       CGNS_ENUMT( PointSetType_t ) psType;
972       CGNS_ENUMT( DataType_t ) normDataType;
973       cgsize_t nbPnt, normFlag;
974       int normIndex[3], nbDS;
975       MESSAGE("  nbBC: " << nbBC);
976       for ( int iBC = 1; iBC <= nbBC; ++iBC )
977       {
978         MESSAGE("  iBC: " << iBC);
979         if ( cg_boco_info( _fn, cgnsBase, iZone, iBC, name, &bcType, &psType,
980                            &nbPnt, normIndex, &normFlag, &normDataType, &nbDS ) != CG_OK )
981         {
982           addMessage( cg_get_error() );
983           continue;
984         }
985         MESSAGE("  iBC info OK: " << iBC);
986         vector< cgsize_t > ids( nbPnt * zone.IndexSize() );
987         CGNS_ENUMT( GridLocation_t ) location;
988         if ( cg_boco_read( _fn, cgnsBase, iZone, iBC, &ids[0], NULL ) != CG_OK ||
989              cg_boco_gridlocation_read( _fn, cgnsBase, iZone, iBC, &location) != CG_OK )
990         {
991           addMessage( cg_get_error() );
992           continue;
993         }
994         SMDSAbs_ElementType elemType = SMDSAbs_All;
995         switch ( location ) {
996         case CGNS_ENUMV( Vertex      ): elemType = SMDSAbs_Node; break;
997         case CGNS_ENUMV( FaceCenter  ): elemType = SMDSAbs_Face; break;
998         case CGNS_ENUMV( IFaceCenter ): elemType = SMDSAbs_Face; break;
999         case CGNS_ENUMV( JFaceCenter ): elemType = SMDSAbs_Face; break;
1000         case CGNS_ENUMV( KFaceCenter ): elemType = SMDSAbs_Face; break;
1001         case CGNS_ENUMV( EdgeCenter  ): elemType = SMDSAbs_Edge; break;
1002         default:;
1003         }
1004         SMESHDS_Group* group = new SMESHDS_Group ( groupID++, myMesh, elemType );
1005         myMesh->AddGroup( group );
1006         SMESH_Comment groupName( name ); groupName << " " << cg_BCTypeName( bcType );
1007         group->SetStoreName( groupName.c_str() );
1008         SMDS_MeshGroup& groupDS = group->SMDSGroup();
1009
1010         if ( elemType == SMDSAbs_Node )
1011         {
1012           if ( zone.IsStructured() )
1013           {
1014             vector< cgsize_t > nodeIds;
1015             if ( psType == CGNS_ENUMV( PointRange ))
1016             {
1017               // nodes are given as (ijkMin, ijkMax)
1018               TPointRangeIterator idIt( & ids[0], meshDim );
1019               nodeIds.reserve( idIt.Size() );
1020               while ( idIt.More() )
1021                 nodeIds.push_back( zone.NodeID( idIt.Next() ));
1022             }
1023             else
1024             {
1025               // nodes are given as (ijk1, ijk2, ..., ijkN)
1026               nodeIds.reserve( ids.size() / meshDim );
1027               for ( size_t i = 0; i < ids.size(); i += meshDim )
1028                 nodeIds.push_back( zone.NodeID( ids[i], ids[i+1], ids[i+2] ));
1029             }
1030             ids.swap( nodeIds );
1031           }
1032           else if ( zone._nodeIdShift )
1033           {
1034             for ( size_t i = 0; i < ids.size(); ++i )
1035               ids[i] += zone._nodeIdShift;
1036           }
1037           zone.ReplaceNodes( &ids[0], ids.size() );
1038
1039           for ( size_t i = 0; i < ids.size(); ++i )
1040             if ( const SMDS_MeshNode* n = myMesh->FindNode( ids[i] ))
1041               groupDS.Add( n );
1042         }
1043         else // BC applied to elements
1044         {
1045           if ( zone.IsStructured() )
1046           {
1047             int axis = 0; // axis perpendiculaire to which boundary elements are oriented
1048             if ( (int) ids.size() >= meshDim * 2 )
1049             {
1050               for ( ; axis < meshDim; ++axis )
1051                 if ( ids[axis] - ids[axis+meshDim] == 0 )
1052                   break;
1053             }
1054             else
1055             {
1056               for ( ; axis < meshDim; ++axis )
1057                 if ( normIndex[axis] != 0 )
1058                   break;
1059             }
1060             if ( axis == meshDim )
1061             {
1062               addMessage( SMESH_Comment("Invalid NormalIndex in BC ") << name );
1063               continue;
1064             }
1065             const int nbElemNodesByDim[] = { 1, 2, 4, 8 };
1066             const int nbElemNodes = nbElemNodesByDim[ meshDim ];
1067
1068             if ( psType == CGNS_ENUMV( PointRange ) ||
1069                  psType == CGNS_ENUMV( ElementRange ))
1070             {
1071               // elements are given as (ijkMin, ijkMax)
1072               typedef void (TZoneData::*PGetNodesFun)( const gp_XYZ& ijk, cgsize_t* ids ) const;
1073               PGetNodesFun getNodesFun = 0;
1074               if ( elemType == SMDSAbs_Face  && meshDim == 3 )
1075                 switch ( axis ) {
1076                 case 0: getNodesFun = & TZoneData::IFaceNodes; break;
1077                 case 1: getNodesFun = & TZoneData::JFaceNodes; break;
1078                 case 2: getNodesFun = & TZoneData::KFaceNodes; break;
1079                 }
1080               else if ( elemType == SMDSAbs_Edge && meshDim == 2 )
1081                 switch ( axis ) {
1082                 case 0: getNodesFun = & TZoneData::IEdgeNodes; break;
1083                 case 1: getNodesFun = & TZoneData::JEdgeNodes; break;
1084                 }
1085               if ( !getNodesFun )
1086               {
1087                 addMessage( SMESH_Comment("Unsupported BC location in BC ") << name
1088                             << " " << cg_GridLocationName( location )
1089                             << " in " << meshDim << " mesh");
1090                 continue;
1091               }
1092               TPointRangeIterator rangeIt( & ids[0], meshDim );
1093               vector< cgsize_t > elemNodeIds( rangeIt.Size() * nbElemNodes );
1094               for ( int i = 0; rangeIt.More(); i+= nbElemNodes )
1095                 (zone.*getNodesFun)( rangeIt.Next(), &elemNodeIds[i] );
1096
1097               ids.swap( elemNodeIds );
1098             }
1099             else
1100             {
1101               // elements are given as (ijk1, ijk2, ..., ijkN)
1102               typedef void (TZoneData::*PGetNodesFun)( int i, int j, int k, cgsize_t* ids ) const;
1103               PGetNodesFun getNodesFun = 0;
1104               if ( elemType == SMDSAbs_Face )
1105                 switch ( axis ) {
1106                 case 0: getNodesFun = & TZoneData::IFaceNodes; break;
1107                 case 1: getNodesFun = & TZoneData::JFaceNodes; break;
1108                 case 2: getNodesFun = & TZoneData::KFaceNodes; break;
1109                 }
1110               else if ( elemType == SMDSAbs_Edge && meshDim == 2 )
1111                 switch ( axis ) {
1112                 case 0: getNodesFun = & TZoneData::IEdgeNodes; break;
1113                 case 1: getNodesFun = & TZoneData::JEdgeNodes; break;
1114                 }
1115               if ( !getNodesFun )
1116               {
1117                 addMessage( SMESH_Comment("Unsupported BC location in BC ") << name
1118                             << " " << cg_GridLocationName( location )
1119                             << " in " << meshDim << " mesh");
1120                 continue;
1121               }
1122               vector< cgsize_t > elemNodeIds( ids.size()/meshDim * nbElemNodes );
1123               for ( size_t i = 0, j = 0; i < ids.size(); i += meshDim, j += nbElemNodes )
1124                 (zone.*getNodesFun)( ids[i], ids[i+1], ids[i+2], &elemNodeIds[j] );
1125
1126               ids.swap( elemNodeIds );
1127             }
1128             zone.ReplaceNodes( &ids[0], ids.size() );
1129
1130             PAddElemFun addElemFun = 0;
1131             switch ( meshDim ) {
1132             case 1: addElemFun = & add_BAR_2;  break;
1133             case 2: addElemFun = & add_QUAD_4; break;
1134             case 3: addElemFun = & add_HEXA_8; break;
1135             }
1136             int elemID = meshInfo.NbElements();
1137             const SMDS_MeshElement* elem = 0;
1138             for ( size_t i = 0; i < ids.size(); i += nbElemNodes )
1139             {
1140               if ( iZone == 1 || !( elem = findElement( &ids[i], nbElemNodes, myMesh )))
1141                 elem = addElemFun( &ids[i], myMesh, ++elemID );
1142               groupDS.Add( elem );
1143             }
1144           }
1145           else // unstructured zone
1146           {
1147             if ( zone._elemIdShift )
1148               for ( size_t i = 0; i < ids.size(); ++i )
1149                 ids[i] += zone._elemIdShift;
1150
1151             if ( psType == CGNS_ENUMV( PointRange ) && ids.size() == 2 )
1152             {
1153               for ( cgsize_t i = ids[0]; i <= ids[1]; ++i )
1154                 if ( const SMDS_MeshElement* e = myMesh->FindElement( i ))
1155                   groupDS.Add( e );
1156             }
1157             else
1158             {
1159               for ( size_t i = 0; i < ids.size(); ++i )
1160                 if ( const SMDS_MeshElement* e = myMesh->FindElement( ids[i] ))
1161                   groupDS.Add( e );
1162             }
1163           }
1164         } // end "BC applied to elements"
1165
1166         // to have group type according to a real elem type
1167         group->SetType( groupDS.GetType() );
1168
1169       } // loop on BCs of the zone
1170     }
1171     else addMessage( cg_get_error() );
1172
1173     
1174     MESSAGE("  read flow solutions");
1175     int nsols = 0;
1176     if ( cg_nsols( _fn, cgnsBase, iZone, &nsols) == CG_OK )
1177     {
1178        MESSAGE("  nb flow solutions: " << nsols);
1179     }
1180     else addMessage( cg_get_error() );
1181     
1182     MESSAGE("  read discrete data");
1183     int nbdiscrete = 0;
1184     if ( cg_ndiscrete( _fn, cgnsBase, iZone, &nbdiscrete) == CG_OK )
1185     {
1186         MESSAGE("  nb discrete data: " << nbdiscrete);
1187         char nameDiscrete[CGNS_NAME_SIZE];
1188         for (int idisc = 1; idisc <= nbdiscrete; idisc++)
1189         {
1190             if ( cg_discrete_read( _fn, cgnsBase, iZone, idisc, nameDiscrete) == CG_OK )
1191             {
1192                 MESSAGE("  discrete data #"<< idisc << " name: " << nameDiscrete);
1193                 PointSetType_t ptset_type;
1194                 cgsize_t npnts;
1195                 if ( cg_discrete_ptset_info( _fn, cgnsBase, iZone, idisc, &ptset_type, &npnts) == CG_OK )
1196                 {
1197                     MESSAGE("  discrete data #"<< idisc << " npnts: " << npnts);
1198                 }
1199                 else addMessage( cg_get_error() );
1200             }
1201             else addMessage( cg_get_error() );
1202         }
1203     }
1204     else addMessage( cg_get_error() );
1205
1206
1207     MESSAGE("  read subregions");
1208     int nbSubrg = 0;
1209     if ( cg_nsubregs( _fn, cgnsBase, iZone, &nbSubrg) == CG_OK )
1210     {
1211        MESSAGE("  nb subregions: " << nbSubrg);
1212     }
1213     else addMessage( cg_get_error() );
1214
1215     MESSAGE("  end zone");
1216   } // loop on the zones of a mesh
1217
1218     MESSAGE("read families");
1219     int nbFam = 0;
1220     if ( cg_nfamilies( _fn, cgnsBase, &nbFam) == CG_OK )
1221     {
1222         MESSAGE("nb families: " << nbFam);
1223     }
1224     else addMessage( cg_get_error() );
1225
1226     
1227
1228   // ------------------------------------------------------------------------
1229   // Make groups for multiple zones and remove free nodes at zone interfaces
1230   // ------------------------------------------------------------------------
1231   map< string, TZoneData >::iterator nameZoneIt = zonesByName.begin();
1232   for ( ; nameZoneIt != zonesByName.end(); ++nameZoneIt )
1233   {
1234     MESSAGE("nameZone: " << nameZoneIt->first);
1235     TZoneData& zone = nameZoneIt->second;
1236     if ( zone._nbElems == 0 ) continue;
1237     if ( zone._nbElems == meshInfo.NbElements() ) break; // there is only one non-empty zone
1238
1239     // make a group
1240     SMDSAbs_ElementType elemType = myMesh->GetElementType( zone._elemIdShift + 1,
1241                                                            /*iselem=*/true );
1242     SMESHDS_Group* group = new SMESHDS_Group ( groupID++, myMesh, elemType );
1243     myMesh->AddGroup( group );
1244     group->SetStoreName( nameZoneIt->first.c_str() );
1245     SMDS_MeshGroup& groupDS = group->SMDSGroup();
1246
1247     for ( int i = 1; i <= zone._nbElems; ++i )
1248       if ( const SMDS_MeshElement* e = myMesh->FindElement( i + zone._elemIdShift ))
1249         groupDS.Add( e );
1250
1251     // remove free nodes
1252     map< int, int >::iterator nnRmKeepIt = zone._nodeReplacementMap.begin();
1253     for ( ; nnRmKeepIt != zone._nodeReplacementMap.end(); ++nnRmKeepIt )
1254       if ( const SMDS_MeshNode* n = myMesh->FindNode( nnRmKeepIt->first ))
1255         if ( n->NbInverseElements() == 0 )
1256           myMesh->RemoveFreeNode( n, (SMESHDS_SubMesh *)0, /*fromGroups=*/false );
1257   }
1258
1259   aResult = myErrorMessages.empty() ? DRS_OK : DRS_WARN_SKIP_ELEM;
1260
1261   myMesh->Modified();
1262   myMesh->CompactMesh();
1263   MESSAGE("end perform");
1264   return aResult;
1265 }
1266
1267 //================================================================================
1268 /*!
1269  * \brief Constructor
1270  */
1271 //================================================================================
1272
1273 DriverCGNS_Read::DriverCGNS_Read()
1274 {
1275   _fn = -1;
1276 }
1277 //================================================================================
1278 /*!
1279  * \brief Close the cgns file at destruction
1280  */
1281 //================================================================================
1282
1283 DriverCGNS_Read::~DriverCGNS_Read()
1284 {
1285   if ( _fn > 0 )
1286     cg_close( _fn );
1287 }
1288
1289 //================================================================================
1290 /*!
1291  * \brief Opens myFile
1292  */
1293 //================================================================================
1294
1295 Driver_Mesh::Status DriverCGNS_Read::open()
1296 {
1297   if ( _fn < 0 )
1298   {
1299     
1300 #ifdef CG_MODE_READ
1301     int res = cg_open(myFile.c_str(), CG_MODE_READ, &_fn);
1302 #else
1303     int res = cg_open(myFile.c_str(), MODE_READ, &_fn);
1304 #endif
1305     if ( res != CG_OK)
1306     {
1307       addMessage( cg_get_error(), /*fatal = */true );
1308     }
1309   }
1310   return _fn >= 0 ? DRS_OK : DRS_FAIL;
1311 }
1312
1313 //================================================================================
1314 /*!
1315  * \brief Reads nb of meshes in myFile
1316  */
1317 //================================================================================
1318
1319 int DriverCGNS_Read::GetNbMeshes(Status& theStatus)
1320 {
1321   if (( theStatus = open()) != DRS_OK )
1322     return 0;
1323
1324   int nbases = 0;
1325   if(cg_nbases( _fn, &nbases) != CG_OK)
1326     theStatus = addMessage( cg_get_error(), /*fatal = */true );
1327
1328   return nbases;
1329 }