]> SALOME platform Git repositories - plugins/ghs3dplugin.git/blob - src/GHS3DPlugin_GHS3D.cxx
Salome HOME
Merging with V3_2_6pre4
[plugins/ghs3dplugin.git] / src / GHS3DPlugin_GHS3D.cxx
1 // Copyright (C) 2005  CEA/DEN, EDF R&D, OPEN CASCADE, PRINCIPIA R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library is distributed in the hope that it will be useful
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 //=============================================================================
20 // File      : GHS3DPlugin_GHS3D.cxx
21 // Created   : 
22 // Author    : Edward AGAPOV, modified by Lioka RAZAFINDRAZAKA (CEA) 09/02/2007
23 // Project   : SALOME
24 // Copyright : CEA 2003
25 // $Header$
26 //=============================================================================
27 using namespace std;
28
29 #include "GHS3DPlugin_GHS3D.hxx"
30 #include "SMESH_Gen.hxx"
31 #include "SMESH_Mesh.hxx"
32 #include "SMESH_Comment.hxx"
33
34 #include "SMDS_MeshElement.hxx"
35 #include "SMDS_MeshNode.hxx"
36
37 #include <TopExp_Explorer.hxx>
38 #include <OSD_File.hxx>
39
40 #include "utilities.h"
41
42 #ifndef WIN32
43 #include <sys/sysinfo.h>
44 #endif
45
46 //#include <Standard_Stream.hxx>
47
48 #include <BRepGProp.hxx>
49 #include <BRepBndLib.hxx>
50 #include <BRepClass_FaceClassifier.hxx>
51 #include <BRepClass3d_SolidClassifier.hxx>
52 #include <TopAbs.hxx>
53 #include <Bnd_Box.hxx>
54 #include <GProp_GProps.hxx>
55 #include <Precision.hxx>
56
57 #ifdef _DEBUG_
58 #define DUMP(txt) \
59 //  cout << txt
60 #else
61 #define DUMP(txt)
62 #endif
63
64 extern "C"
65 {
66 #ifndef WNT
67 #include <unistd.h>
68 #include <sys/mman.h>
69 #endif
70 #include <sys/stat.h>
71 #include <fcntl.h>
72 }
73
74 //=============================================================================
75 /*!
76  *  
77  */
78 //=============================================================================
79
80 GHS3DPlugin_GHS3D::GHS3DPlugin_GHS3D(int hypId, int studyId, SMESH_Gen* gen)
81   : SMESH_3D_Algo(hypId, studyId, gen)
82 {
83   MESSAGE("GHS3DPlugin_GHS3D::GHS3DPlugin_GHS3D");
84   _name = "GHS3D_3D";
85   _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID);// 1 bit /shape type
86   _iShape=0;
87   _nbShape=0;
88 }
89
90 //=============================================================================
91 /*!
92  *  
93  */
94 //=============================================================================
95
96 GHS3DPlugin_GHS3D::~GHS3DPlugin_GHS3D()
97 {
98   MESSAGE("GHS3DPlugin_GHS3D::~GHS3DPlugin_GHS3D");
99 }
100
101 //=============================================================================
102 /*!
103  *  
104  */
105 //=============================================================================
106
107 bool GHS3DPlugin_GHS3D::CheckHypothesis ( SMESH_Mesh&                          aMesh,
108                                           const TopoDS_Shape&                  aShape,
109                                           SMESH_Hypothesis::Hypothesis_Status& aStatus )
110 {
111 //  MESSAGE("GHS3DPlugin_GHS3D::CheckHypothesis");
112   aStatus = SMESH_Hypothesis::HYP_OK;
113   return true;
114 }
115
116 //=======================================================================
117 //function : writeFaces
118 //purpose  : 
119 //=======================================================================
120
121 static bool writeFaces (ofstream &            theFile,
122                         SMESHDS_Mesh *        theMesh,
123                         const map <int,int> & theSmdsToGhs3dIdMap)
124 {
125   // record structure:
126   //
127   // NB_ELEMS DUMMY_INT
128   // Loop from 1 to NB_ELEMS
129   // NB_NODES NODE_NB_1 NODE_NB_2 ... (NB_NODES + 1) times: DUMMY_INT
130
131   // get all faces bound to theShape
132
133   int nbFaces = 0;
134   TopoDS_Shape theShape = theMesh->ShapeToMesh();
135   list< const SMDS_MeshElement* > faces;
136   TopExp_Explorer fExp( theShape, TopAbs_FACE );
137   SMESHDS_SubMesh* sm;
138   SMDS_ElemIteratorPtr eIt;
139
140   const char* space    = "  ";
141   const int   dummyint = 0;
142
143   list< const SMDS_MeshElement* >::iterator f;
144   map<int,int>::const_iterator it;
145   SMDS_ElemIteratorPtr nodeIt;
146   const SMDS_MeshElement* elem;
147   int nbNodes;
148   int aSmdsID;
149
150   for ( ; fExp.More(); fExp.Next() ) {
151     sm = theMesh->MeshElements( fExp.Current() );
152     if ( sm ) {
153       eIt = sm->GetElements();
154       while ( eIt->more() ) {
155         faces.push_back( eIt->next() );
156         nbFaces++;
157       }
158     }
159   }
160
161   if ( nbFaces == 0 )
162     return false;
163
164   cout << nbFaces << " triangles" << endl;
165
166   // NB_ELEMS DUMMY_INT
167   theFile << space << nbFaces << space << dummyint << endl;
168
169   // Loop from 1 to NB_ELEMS
170
171   f = faces.begin();
172   for ( ; f != faces.end(); ++f )
173   {
174     // NB_NODES PER FACE
175     elem = *f;
176     nbNodes = elem->NbNodes();
177     theFile << space << nbNodes;
178
179     // NODE_NB_1 NODE_NB_2 ...
180     nodeIt = elem->nodesIterator();
181     while ( nodeIt->more() )
182     {
183       // find GHS3D ID
184       aSmdsID = nodeIt->next()->GetID();
185       it = theSmdsToGhs3dIdMap.find( aSmdsID );
186       ASSERT( it != theSmdsToGhs3dIdMap.end() );
187       theFile << space << (*it).second;
188     }
189
190     // (NB_NODES + 1) times: DUMMY_INT
191     for ( int i=0; i<=nbNodes; i++)
192       theFile << space << dummyint;
193
194     theFile << endl;
195   }
196
197   return true;
198 }
199
200 //=======================================================================
201 //function : writePoints
202 //purpose  : 
203 //=======================================================================
204
205 static bool writePoints (ofstream &                       theFile,
206                          SMESHDS_Mesh *                   theMesh,
207                          map <int,int> &                  theSmdsToGhs3dIdMap,
208                          map <int,const SMDS_MeshNode*> & theGhs3dIdToNodeMap)
209 {
210   // record structure:
211   //
212   // NB_NODES
213   // Loop from 1 to NB_NODES
214   //   X Y Z DUMMY_INT
215
216   int nbNodes = theMesh->NbNodes();
217   if ( nbNodes == 0 )
218     return false;
219
220   const char* space    = "  ";
221   const int   dummyint = 0;
222
223   int aGhs3dID = 1;
224   SMDS_NodeIteratorPtr it = theMesh->nodesIterator();
225   const SMDS_MeshNode* node;
226
227   // NB_NODES
228   theFile << space << nbNodes << endl;
229   cout << "The initial 2D mesh contains " << nbNodes << " nodes and ";
230
231   // Loop from 1 to NB_NODES
232
233   while ( it->more() )
234   {
235     node = it->next();
236     theSmdsToGhs3dIdMap.insert( map <int,int>::value_type( node->GetID(), aGhs3dID ));
237     theGhs3dIdToNodeMap.insert (map <int,const SMDS_MeshNode*>::value_type( aGhs3dID, node ));
238     aGhs3dID++;
239
240     // X Y Z DUMMY_INT
241     theFile
242       << space << node->X()
243       << space << node->Y()
244       << space << node->Z()
245       << space << dummyint;
246
247     theFile << endl;
248   }
249
250   return true;
251 }
252
253 //=======================================================================
254 //function : findSolid
255 //purpose  : 
256 //=======================================================================
257
258 static TopoDS_Shape findSolid(const SMDS_MeshNode *aNode[],
259                               TopoDS_Shape        aSolid,
260                               const TopoDS_Shape  shape[],
261                               const double        box[][6],
262                               const int           nShape) {
263
264   Standard_Real PX, PY, PZ;
265   int iShape;
266
267   PX = ( aNode[0]->X() + aNode[1]->X() + aNode[2]->X() + aNode[3]->X() ) / 4.0;
268   PY = ( aNode[0]->Y() + aNode[1]->Y() + aNode[2]->Y() + aNode[3]->Y() ) / 4.0;
269   PZ = ( aNode[0]->Z() + aNode[1]->Z() + aNode[2]->Z() + aNode[3]->Z() ) / 4.0;
270   gp_Pnt aPnt(PX, PY, PZ);
271
272   BRepClass3d_SolidClassifier SC (aSolid, aPnt, Precision::Confusion());
273   if ( not(SC.State() == TopAbs_IN) ) {
274     for (iShape = 0; iShape < nShape; iShape++) {
275       aSolid = shape[iShape];
276       if ( not( PX < box[iShape][0] || box[iShape][1] < PX ||
277                 PY < box[iShape][2] || box[iShape][3] < PY ||
278                 PZ < box[iShape][4] || box[iShape][5] < PZ) ) {
279         BRepClass3d_SolidClassifier SC (aSolid, aPnt, Precision::Confusion());
280         if (SC.State() == TopAbs_IN)
281           break;
282       }
283     }
284   }
285   return aSolid;
286 }
287
288 //=======================================================================
289 //function : readMapIntLine
290 //purpose  : 
291 //=======================================================================
292
293 static char* readMapIntLine(char* ptr, int tab[]) {
294   long int intVal;
295   cout << endl;
296
297   for ( int i=0; i<17; i++ ) {
298     intVal = strtol(ptr, &ptr, 10);
299     if ( i < 3 )
300       tab[i] = intVal;
301   }
302   return ptr;
303 }
304
305 //=======================================================================
306 //function : readLine
307 //purpose  : 
308 //=======================================================================
309
310 #define GHS3DPlugin_BUFLENGTH 256
311 #define GHS3DPlugin_ReadLine(aPtr,aBuf,aFile,aLineNb) \
312 {  aPtr = fgets( aBuf, GHS3DPlugin_BUFLENGTH - 2, aFile ); aLineNb++; DUMP(endl); }
313
314
315 //=======================================================================
316 //function : readResultFile
317 //purpose  : 
318 //=======================================================================
319
320 static bool readResultFile(const int                       fileOpen,
321                            SMESHDS_Mesh*                   theMeshDS,
322                            TopoDS_Shape                    tabShape[],
323                            double                          tabBox[][6],
324                            const int                       nShape,
325                            map <int,const SMDS_MeshNode*>& theGhs3dIdToNodeMap) {
326
327   struct stat  status;
328   size_t       length;
329
330   char *ptr, *mapPtr;
331   char *tetraPtr;
332   char *shapePtr;
333
334   int fileStat;
335   int nbElems, nbNodes, nbInputNodes;
336   int nodeId, triangleId;
337   int tab[3], tabID[nShape];
338   int nbTriangle;
339   int ID, shapeID, ghs3dShapeID;
340
341   double coord [3];
342
343   TopoDS_Shape aSolid;
344   SMDS_MeshNode * aNewNode;
345   const SMDS_MeshNode * node[4];
346   map <int,const SMDS_MeshNode*>::iterator IdNode;
347   SMDS_MeshElement* aTet;
348
349   for (int i=0; i<nShape; i++)
350     tabID[i] = 0;
351
352   // Read the file state
353   fileStat = fstat(fileOpen, &status);
354   length   = status.st_size;
355
356   // Mapping the result file into memory
357   ptr = (char *) mmap(0,length,PROT_READ,MAP_PRIVATE,fileOpen,0);
358   mapPtr = ptr;
359
360   ptr      = readMapIntLine(ptr, tab);
361   tetraPtr = ptr;
362
363   nbElems      = tab[0];
364   nbNodes      = tab[1];
365   nbInputNodes = tab[2];
366
367   // Reading the nodeId
368   for (int i=0; i < 4*nbElems; i++)
369     nodeId = strtol(ptr, &ptr, 10);
370
371   // Reading the nodeCoor and update the nodeMap
372   for (int iNode=0; iNode < nbNodes; iNode++) {
373     for (int iCoor=0; iCoor < 3; iCoor++)
374       coord[ iCoor ] = strtod(ptr, &ptr);
375     if ((iNode+1) > nbInputNodes) {
376       aNewNode = theMeshDS->AddNode( coord[0],coord[1],coord[2] );
377       theGhs3dIdToNodeMap.insert(make_pair( (iNode+1), aNewNode ));
378     }
379   }
380
381   // Reading the triangles
382   nbTriangle = strtol(ptr, &ptr, 10);
383
384   for (int i=0; i < 3*nbTriangle; i++)
385     triangleId = strtol(ptr, &ptr, 10);
386
387   shapePtr = ptr;
388
389   // Associating the tetrahedrons to the shapes
390   for (int iElem = 0; iElem < nbElems; iElem++) {
391     for (int iNode = 0; iNode < 4; iNode++) {
392       ID = strtol(tetraPtr, &tetraPtr, 10);
393       IdNode = theGhs3dIdToNodeMap.find(ID);
394       node[ iNode ] = IdNode->second;
395     }
396     aTet = theMeshDS->AddVolume( node[1], node[0], node[2], node[3] );
397     ghs3dShapeID = strtol(shapePtr, &shapePtr, 10);
398     if ( tabID[ ghs3dShapeID - 1 ] == 0 ) {
399       if (iElem == 0)
400         aSolid = tabShape[0];
401       aSolid = findSolid(node, aSolid, tabShape, tabBox, nbTriangle);
402       shapeID = theMeshDS->ShapeToIndex( aSolid );
403       tabID[ ghs3dShapeID - 1] = shapeID;
404     }
405     else
406       shapeID = tabID[ ghs3dShapeID - 1];
407     theMeshDS->SetMeshElementOnShape( aTet, shapeID );
408     if ( (iElem + 1) == nbElems )
409       cout << nbElems << " tetrahedrons have been associated to " << nbTriangle << " shapes" << endl;
410   }
411   munmap(mapPtr, length);
412   close(fileOpen);
413   return true;
414 }
415
416 //=======================================================================
417 //function : getTmpDir
418 //purpose  : 
419 //=======================================================================
420
421 static TCollection_AsciiString getTmpDir()
422 {
423   TCollection_AsciiString aTmpDir;
424
425   char *Tmp_dir = getenv("SALOME_TMP_DIR");
426   if(Tmp_dir != NULL) {
427     aTmpDir = Tmp_dir;
428 #ifdef WIN32
429     if(aTmpDir.Value(aTmpDir.Length()) != '\\') aTmpDir+='\\';
430 #else
431     if(aTmpDir.Value(aTmpDir.Length()) != '/') aTmpDir+='/';
432 #endif      
433   }
434   else {
435 #ifdef WIN32
436     aTmpDir = TCollection_AsciiString("C:\\");
437 #else
438     aTmpDir = TCollection_AsciiString("/tmp/");
439 #endif
440   }
441   return aTmpDir;
442 }
443
444 //================================================================================
445 /*!
446  * \brief Decrease amount of memory GHS3D may use until it can allocate it
447   * \param nbMB - memory size to adjust
448   * \param aLogFileName - file for GHS3D output
449   * \retval bool - false if GHS3D can not run for any reason
450  */
451 //================================================================================
452
453 static bool adjustMemory(int & nbMB, const TCollection_AsciiString & aLogFileName)
454 {
455   TCollection_AsciiString cmd( "ghs3d -m " );
456   cmd += nbMB;
457   cmd += " 1>";
458   cmd += aLogFileName;
459
460   system( cmd.ToCString() ); // run
461
462   // analyse log file
463
464   FILE * aLogFile = fopen( aLogFileName.ToCString(), "r" );
465   if ( aLogFile )
466   {
467     bool memoryOK = true;
468     char * aPtr;
469     char aBuffer[ GHS3DPlugin_BUFLENGTH ];
470     int aLineNb = 0;
471     do { 
472       GHS3DPlugin_ReadLine( aPtr, aBuffer, aLogFile, aLineNb );
473       if ( aPtr ) {
474         TCollection_AsciiString line( aPtr );
475         if ( line.Search( "UNABLE TO ALLOCATE MEMORY" ) > 0 )
476           memoryOK = false;
477       }
478     } while ( aPtr && memoryOK );
479
480     fclose( aLogFile );
481
482     if ( !memoryOK ) {
483       nbMB *= 0.75;
484       return adjustMemory( nbMB, aLogFileName );
485     }
486     return true;
487   }
488   return false;
489 }
490
491 //=============================================================================
492 /*!
493  *Here we are going to use the GHS3D mesher
494  */
495 //=============================================================================
496
497 bool GHS3DPlugin_GHS3D::Compute(SMESH_Mesh&         theMesh,
498                                 const TopoDS_Shape& theShape)
499 {
500   bool Ok(false);
501   SMESHDS_Mesh* meshDS = theMesh.GetMeshDS();
502
503   if (_iShape == 0 && _nbShape == 0) {
504     cout << endl;
505     cout << "Ghs3d execution..." << endl;
506     cout << endl;
507
508     TopExp_Explorer exp (meshDS->ShapeToMesh(), TopAbs_SOLID);
509     for (; exp.More(); exp.Next())
510       _nbShape++;
511   }
512
513   _iShape++;
514
515   if ( _iShape == _nbShape ) {
516
517     // create bounding box for every shape
518
519     int iShape = 0;
520     TopoDS_Shape tabShape[_nbShape];
521     double tabBox[_nbShape][6];
522     Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
523
524     TopExp_Explorer expBox (meshDS->ShapeToMesh(), TopAbs_SOLID);
525     for (; expBox.More(); expBox.Next()) {
526       tabShape[iShape] = expBox.Current();
527       Bnd_Box BoundingBox;
528       BRepBndLib::Add(expBox.Current(), BoundingBox);
529       BoundingBox.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
530       tabBox[iShape][0] = Xmin; tabBox[iShape][1] = Xmax;
531       tabBox[iShape][2] = Ymin; tabBox[iShape][3] = Ymax;
532       tabBox[iShape][4] = Zmin; tabBox[iShape][5] = Zmax;
533       iShape++;
534     }
535
536     // make a unique working file name
537     // to avoid access to the same files by eg different users
538   
539     TCollection_AsciiString aGenericName, aTmpDir = getTmpDir();
540     aGenericName = aTmpDir + "GHS3D_";
541 #ifdef WIN32
542     aGenericName += GetCurrentProcessId();
543 #else
544     aGenericName += getpid();
545 #endif
546     aGenericName += "_";
547     aGenericName += meshDS->ShapeToIndex( theShape );
548
549     TCollection_AsciiString aFacesFileName, aPointsFileName, aResultFileName;
550     TCollection_AsciiString aBadResFileName, aBbResFileName, aLogFileName;
551     aFacesFileName  = aGenericName + ".faces";  // in faces
552     aPointsFileName = aGenericName + ".points"; // in points
553     aResultFileName = aGenericName + ".noboite";// out points and volumes
554     aBadResFileName = aGenericName + ".boite";  // out bad result
555     aBbResFileName  = aGenericName + ".bb";     // out vertex stepsize
556     aLogFileName    = aGenericName + ".log";    // log
557
558     // -----------------
559     // make input files
560     // -----------------
561
562     ofstream aFacesFile  ( aFacesFileName.ToCString()  , ios::out);
563     ofstream aPointsFile ( aPointsFileName.ToCString() , ios::out);
564     // bool Ok =
565     Ok =
566 #ifdef WIN32
567       aFacesFile->is_open() && aPointsFile->is_open();
568 #else
569       aFacesFile.rdbuf()->is_open() && aPointsFile.rdbuf()->is_open();
570 #endif
571     if (!Ok)
572         return error(dfltErr(), SMESH_Comment("Can't write into ") << aTmpDir.ToCString());
573
574     map <int,int> aSmdsToGhs3dIdMap;
575     map <int,const SMDS_MeshNode*> aGhs3dIdToNodeMap;
576
577     Ok = writePoints( aPointsFile, meshDS, aSmdsToGhs3dIdMap, aGhs3dIdToNodeMap ) &&
578          writeFaces ( aFacesFile,  meshDS, aSmdsToGhs3dIdMap );
579
580     aFacesFile.close();
581     aPointsFile.close();
582
583     if ( ! Ok ) {
584       if ( !getenv("GHS3D_KEEP_FILES") ) {
585         OSD_File( aFacesFileName ).Remove();
586         OSD_File( aPointsFileName ).Remove();
587       }
588       return error(COMPERR_BAD_INPUT_MESH);
589     }
590
591     // -----------------
592     // run ghs3d mesher              WIN32???
593     // -----------------
594
595     // ghs3d need to know amount of memory it may use (MB).
596     // Default memory is defined at ghs3d installation but it may be not enough,
597     // so allow to use about all available memory
598
599     TCollection_AsciiString memory;
600 #ifndef WIN32
601     struct sysinfo si;
602     int err = sysinfo( &si );
603     if ( err == 0 ) {
604         int MB = 0.9 * ( si.freeram + si.freeswap ) * si.mem_unit / 1024 / 1024;
605         adjustMemory( MB, aLogFileName );
606         memory = "-m ";
607         memory += MB;
608     }
609 #endif
610
611     MESSAGE("GHS3DPlugin_GHS3D::Compute");
612     TCollection_AsciiString cmd( "ghs3d " ); // command to run
613     cmd +=
614       memory +                     // memory
615       " -c0 -f " + aGenericName +  // file to read
616            " 1>" + aLogFileName;   // dump into file
617
618     system( cmd.ToCString() ); // run
619
620     cout << endl;
621     cout << "End of Ghs3d execution !" << endl;
622
623     // --------------
624     // read a result
625     // --------------
626
627     // Mapping the result file
628
629     int fileOpen;
630     fileOpen = open( aResultFileName.ToCString(), O_RDONLY);
631     if ( fileOpen < 0 ) {
632       cout << endl;
633       cout << "Error when opening the " << aResultFileName.ToCString() << " file" << endl;
634       cout << endl;
635       Ok = false;
636     }
637     else
638       Ok = readResultFile( fileOpen, meshDS, tabShape, tabBox, _nbShape, aGhs3dIdToNodeMap );
639
640   // ---------------------
641   // remove working files
642   // ---------------------
643
644     if ( Ok ) {
645         OSD_File( aLogFileName ).Remove();
646     }
647     else if ( OSD_File( aLogFileName ).Size() > 0 ) {
648         Ok = error(dfltErr(), SMESH_Comment("See ")<< aLogFileName.ToCString() );
649     }
650     else {
651         OSD_File( aLogFileName ).Remove();
652     }
653   }
654   return Ok;
655 }