Salome HOME
bos #20256: [CEA 18523] Porting SMESH to int 64 bits
[modules/smesh.git] / src / DriverCGNS / DriverCGNS_Write.cxx
index f83fe915e283cb75693c039c6f63f3717a4f8488..9320b826ac675f902802c7b482322e9e04635dcf 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2021  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
@@ -25,6 +25,7 @@
 
 #include "DriverCGNS_Write.hxx"
 
+#include "SMDS_IteratorOnIterators.hxx"
 #include "SMDS_MeshNode.hxx"
 #include "SMDS_VolumeTool.hxx"
 #include "SMESHDS_GroupBase.hxx"
@@ -129,6 +130,11 @@ namespace
         interlaces[SMDSEntity_Quad_Penta] = ids;
         cgTypes   [SMDSEntity_Quad_Penta] = CGNS_ENUMV( PENTA_15 );
       }
+      {
+        static int ids[] = { 0,2,1,3,5,4,8,7,6,9,11,10,14,13,12,15,16,17 }; // TODO: check CGNS ORDER
+        interlaces[SMDSEntity_BiQuad_Penta] = ids;
+        cgTypes   [SMDSEntity_BiQuad_Penta] = CGNS_ENUMV( PENTA_18 );
+      }
       {
         static int ids[] = { 0,3,2,1,4,7,6,5 };
         interlaces[SMDSEntity_Hexa] = ids;
@@ -172,7 +178,7 @@ namespace
     {
       for ( int t = 0; t < NofValidBCTypes; ++t )
       {
-        CGNS_ENUMT( BCType_t ) type = CGNS_ENUMT( BCType_t)( t );
+        CGNS_ENUMT( BCType_t ) type = CGNS_ENUMT( BCType_t )( t );
         string typeName = cg_BCTypeName( type );
         if ( typeName == &groupName[0] + bcBeg )
         {
@@ -195,17 +201,17 @@ namespace
    */
   struct TPolyhedFace
   {
-    int _id; // id of NGON_n
-    vector< int > _nodes; // lowest node IDs used for sorting
+    smIdType _id; // id of NGON_n
+    vector< smIdType > _nodes; // lowest node IDs used for sorting
 
-    TPolyhedFace( const SMDS_MeshNode** nodes, const int nbNodes, int ID):_id(ID)
+    TPolyhedFace( const SMDS_MeshNode** nodes, const smIdType nbNodes, smIdType ID):_id(ID)
     {
-      set< int > ids;
-      for ( int i = 0; i < nbNodes; ++i )
+      set< smIdType > ids;
+      for ( smIdType 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();
+      set< smIdType >::iterator idIt = ids.begin();
       for ( size_t j = 0; j < _nodes.size(); ++j, ++idIt )
         _nodes[j] = *idIt;
     }
@@ -227,6 +233,25 @@ namespace
     return ( e2id == elem2cgID.end() ? elem->GetID() : e2id->second );
   }
 
+  //================================================================================
+  /*!
+   * \brief save nb nodes of a polygon
+   */
+  //================================================================================
+
+  void addPolySize( const cgsize_t            nbNodes,
+                    std::vector< cgsize_t >& elemData,
+                    std::vector< cgsize_t >& polyOffset )
+  {
+#if CGNS_VERSION < 4100
+    elemData.push_back( nbNodes );
+    polyOffset.clear(); // just avoid warning: unused parameter
+#else
+    polyOffset.push_back((cgsize_t) elemData.size() );
+    (void)nbNodes; // avoid warning: unused parameter
+#endif
+  }
+
 } // namespace
 
 //================================================================================
@@ -242,6 +267,9 @@ Driver_Mesh::Status DriverCGNS_Write::Perform()
   if ( !myMesh || myMesh->GetMeshInfo().NbElements() < 1 )
     return addMessage( !myMesh ? "NULL mesh" : "Empty mesh (no elements)", /*fatal = */true );
 
+  if ( Driver_Mesh::IsMeshTooLarge< cgsize_t >( myMesh, /*checkIDs =*/ false))
+    return DRS_TOO_LARGE_MESH;
+
   // 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 )
@@ -251,32 +279,34 @@ Driver_Mesh::Status DriverCGNS_Write::Perform()
   // --------------
 
   const int spaceDim = 3;
-  int meshDim = 1;
-  if ( myMesh->NbFaces() > 0 ) meshDim = 2;
+  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)
+    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))
+  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();
+  smIdType 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 };
+  cgsize_t size[9] = { FromSmIdType<cgsize_t>( myMesh->NbNodes() ),
+                       FromSmIdType<cgsize_t>( 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 )
@@ -295,26 +325,26 @@ Driver_Mesh::Status DriverCGNS_Write::Perform()
     vector< double > coords( myMesh->NbNodes() );
     int iC;
     // X
-    SMDS_NodeIteratorPtr nIt = myMesh->nodesIterator( /*idInceasingOrder=*/true );
+    SMDS_NodeIteratorPtr nIt = myMesh->nodesIterator();
     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 );
+    nIt = myMesh->nodesIterator();
     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 );
+    nIt = myMesh->nodesIterator();
     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 );
+    nIt = myMesh->nodesIterator();
     for ( int i = 0; nIt->more(); ++i )
     {
       const SMDS_MeshElement* n = nIt->next();
@@ -329,8 +359,25 @@ Driver_Mesh::Status DriverCGNS_Write::Perform()
 
   // write into a section all successive elements of one geom type
   int iSec;
-  vector< cgsize_t > elemData;
+  vector< cgsize_t > elemData, polyOffset;
   SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator();
+  vector< SMDS_ElemIteratorPtr > elemItVec;
+  if ( _elementsByType )
+  {
+    // create an iterator returning all elements by type
+    for ( int type = SMDSEntity_Node + 1; type < SMDSEntity_Last; ++type )
+    {
+      if ( type == SMDSEntity_Ball )
+        continue; // not supported
+      elemIt = myMesh->elementEntityIterator( SMDSAbs_EntityType( type ));
+      if ( elemIt->more() )
+        elemItVec.push_back( elemIt );
+    }
+    typedef SMDS_IteratorOnIterators< const SMDS_MeshElement*,
+                                      vector< SMDS_ElemIteratorPtr > > TVecIterator;
+    elemIt.reset( new TVecIterator( elemItVec ));
+  }
+
   const SMDS_MeshElement* elem = elemIt->next();
   while ( elem )
   {
@@ -361,7 +408,7 @@ Driver_Mesh::Status DriverCGNS_Write::Perform()
     else if ( elemType == SMDSEntity_Polygon ) // POLYGONS
       do
       {
-        elemData.push_back( elem->NbNodes() );
+        addPolySize( elem->NbNodes(), elemData, polyOffset );
         for ( int i = 0, nb = elem->NbNodes(); i < nb; ++i )
           elemData.push_back( cgnsID( elem->GetNode(i), n2cgID ));
         if ( elem->GetID() != cgID )
@@ -374,7 +421,7 @@ Driver_Mesh::Status DriverCGNS_Write::Perform()
     else if ( elemType == SMDSEntity_Quad_Polygon ) // QUADRATIC POLYGONS
       do // write as linear NGON_n
       {
-        elemData.push_back( elem->NbNodes() );
+        addPolySize( elem->NbNodes(), elemData, polyOffset );
         interlace = & SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon,
                                                           elem->NbNodes() )[0];
         for ( int i = 0, nb = elem->NbNodes(); i < nb; ++i )
@@ -397,14 +444,38 @@ Driver_Mesh::Status DriverCGNS_Write::Perform()
         elem = elemIt->more() ? elemIt->next() : 0;
       continue;
     }
+    else // skip NOT SUPPORTED elements
+    {
+      while ( elemIt->more() )
+      {
+        elem = elemIt->next();
+        if ( elem->GetEntityType() != elemType )
+          break;
+      }
+    }
 
     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 );
+
+#if CGNS_VERSION >= 4000
+    if ( !polyOffset.empty() )
+    {
+      polyOffset.push_back((cgsize_t) elemData.size() );
+      if ( cg_poly_section_write(_fn, iBase, iZone, sectionName.c_str(), cgType, startID,
+                                 cgID-1, /*nbndry=*/0,
+                                 elemData.data(), polyOffset.data(), &iSec) != CG_OK )
+        return addMessage( cg_get_error(), /*fatal = */true );
+    }
+    else
+#endif
+    {
+      if ( cg_section_write(_fn, iBase, iZone, sectionName.c_str(), cgType, startID,
+                            cgID-1, /*nbndry=*/0, elemData.data(), &iSec) != CG_OK )
+        return addMessage( cg_get_error(), /*fatal = */true );
+    }
   }
+
   // Write polyhedral volumes
   // -------------------------
 
@@ -417,11 +488,13 @@ Driver_Mesh::Status DriverCGNS_Write::Perform()
     set< TPolyhedFace > faces;
     set< TPolyhedFace >::iterator faceInSet;
     vector<const SMDS_MeshNode *> faceNodesVec;
+    vector< cgsize_t > faceOffset;
     int nbPolygones = 0, faceID;
 
     SMDS_VolumeTool vol;
 
     elemData.clear();
+    polyOffset.clear();
 
     int nbPolyhTreated = 0;
 
@@ -440,7 +513,7 @@ Driver_Mesh::Status DriverCGNS_Write::Perform()
         vol.Set( elem );
         vol.SetExternalNormal();
         const int nbFaces = vol.NbFaces();
-        elemData.push_back( nbFaces );
+        addPolySize( nbFaces, elemData, polyOffset );
         for ( int iF = 0; iF < nbFaces; ++iF )
         {
           const int nbNodes = vol.NbFaceNodes( iF );
@@ -456,7 +529,7 @@ Driver_Mesh::Status DriverCGNS_Write::Perform()
             // the face is not shared by volumes
             faceID = cgID++;
             ++nbPolygones;
-            faceData.push_back( nbNodes );
+            addPolySize( nbNodes, faceData, faceOffset );
             for ( int i = 0; i < nbNodes; ++i )
               faceData.push_back( cgnsID( faceNodes[i], n2cgID ));
           }
@@ -468,7 +541,7 @@ Driver_Mesh::Status DriverCGNS_Write::Perform()
             {
               faceID = cgID++;
               ++nbPolygones;
-              faceData.push_back( nbNodes );
+              addPolySize( nbNodes, faceData, faceOffset );
               for ( int i = 0; i < nbNodes; ++i )
                 faceData.push_back( cgnsID( faceNodes[i], n2cgID ));
             }
@@ -485,18 +558,35 @@ Driver_Mesh::Status DriverCGNS_Write::Perform()
       }
     }
 
+#if CGNS_VERSION >= 4000
+    if ( nbPolygones > 0 )
+    {
+      faceOffset.push_back((cgsize_t) faceData.size() );
+      if ( cg_poly_section_write(_fn, iBase, iZone, "Faces of Polyhedrons", CGNS_ENUMV( NGON_n ),
+                                 cgID - nbPolygones, cgID-1, /*nbndry=*/0,
+                                 faceData.data(), faceOffset.data(), &iSec) != CG_OK )
+        return addMessage( cg_get_error(), /*fatal = */true );
+    }
+
+    polyOffset.push_back((cgsize_t) elemData.size() );
+    if ( cg_poly_section_write(_fn, iBase, iZone, "Polyhedrons",
+                               CGNS_ENUMV( NFACE_n ), cgID, cgID+nbPolyhTreated-1,
+                               /*nbndry=*/0, &elemData[0], polyOffset.data(), &iSec) != CG_OK )
+      return addMessage( cg_get_error(), /*fatal = */true );
+#else
     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 )
+                            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 )
+
+    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 );
+#endif
 
     if ( !myMesh->GetGroups().empty() )
     {
@@ -534,21 +624,33 @@ Driver_Mesh::Status DriverCGNS_Write::Perform()
       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
+#if CGNS_VERSION > 3130
+        case SMDSAbs_Volume: location = CGNS_ENUMV( CellCenter ); break;
+#else
+        case SMDSAbs_Volume: location = CGNS_ENUMV( FaceCenter ); break;
+#endif
+        case SMDSAbs_Face:   location = CGNS_ENUMV( FaceCenter ); break;
+        case SMDSAbs_Edge:   location = CGNS_ENUMV( EdgeCenter ); break;
         default:;
         }
         break;
       case 2:
         switch ( group->GetType() ) {
-        case SMDSAbs_Face: location = CGNS_ENUMV( FaceCenter ); break; // ???
-        case SMDSAbs_Edge: location = CGNS_ENUMV( EdgeCenter ); break; // OK
+#if CGNS_VERSION > 3130
+        case SMDSAbs_Face: location = CGNS_ENUMV( CellCenter ); break;
+#else
+        case SMDSAbs_Face: location = CGNS_ENUMV( FaceCenter ); break;
+#endif
+        case SMDSAbs_Edge: location = CGNS_ENUMV( EdgeCenter ); break;
         default:;
         }
         break;
       case 1:
-        location = CGNS_ENUMV( EdgeCenter ); break; // ???
+#if CGNS_VERSION > 3130
+        location = CGNS_ENUMV( CellCenter ); break;
+#else
+        location = CGNS_ENUMV( EdgeCenter ); break;
+#endif
         break;
       }
     }
@@ -556,9 +658,16 @@ Driver_Mesh::Status DriverCGNS_Write::Perform()
     // 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());
-
+    if ( !groupNames.insert( name ).second ) // assure name uniqueness
+    {
+      int index = 1;
+      string newName;
+      do {
+        newName = SMESH_Comment( name ) << "_" << index++;
+      }
+      while ( !groupNames.insert( newName ).second );
+      name = newName;
+    }
     // write IDs of elements
     vector< cgsize_t > pnts;
     pnts.reserve( group->Extent() );
@@ -568,13 +677,15 @@ Driver_Mesh::Status DriverCGNS_Write::Perform()
       const SMDS_MeshElement* elem = elemIt->next();
       pnts.push_back( cgnsID( elem, elem2cgIDByEntity[ elem->GetEntityType() ]));
     }
+    if ( pnts.size() == 0 )
+      continue; // can't store empty group
     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 ( location != CGNS_ENUMV( Vertex ) || meshDim == 1 )
     {
       if ( cg_boco_gridlocation_write( _fn, iBase, iZone, iBC, location) != CG_OK )
         return addMessage( cg_get_error(), /*fatal = */false);
@@ -589,7 +700,7 @@ Driver_Mesh::Status DriverCGNS_Write::Perform()
  */
 //================================================================================
 
-DriverCGNS_Write::DriverCGNS_Write(): _fn(0)
+DriverCGNS_Write::DriverCGNS_Write(): _fn(0), _elementsByType( false )
 {
 }