Salome HOME
Be able to use library by setting MG_Hybrid_Parameters.SetToUseLibrary(True)
[plugins/hybridplugin.git] / src / HYBRIDPlugin / MG_HYBRID_API.cxx
1 // Copyright (C) 2004-2024  CEA, EDF
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, or (at your option) any later version.
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 #include "MG_HYBRID_API.hxx"
21
22 #include <SMESH_Comment.hxx>
23 #include <SMESH_File.hxx>
24 #include <SMESH_MGLicenseKeyGen.hxx>
25 #include <Utils_SALOME_Exception.hxx>
26 #include "utilities.h"
27
28 #include <cstring>
29 #include <iostream>
30 #include <iterator>
31 #include <vector>
32 #include <sstream>
33
34 #ifdef USE_MG_LIBS
35
36 extern "C"{
37 #include <meshgems/meshgems.h>
38 #include <meshgems/hybrid.h>
39 }
40
41 struct MG_HYBRID_API::LibData
42 {
43   // MG objects
44   context_t *       _context;
45   hybrid_session_t *_session;
46   mesh_t *          _surf_mesh;
47   sizemap_t *       _sizemap;
48   mesh_t *          _hybrid_mesh;
49
50   // data to pass to MG
51   std::vector<double> _xyz;
52   std::vector<double> _nodeSize; // required nodes
53   std::vector<int>    _edgeNodesTags;
54   int                 _nbRequiredEdges;
55   std::vector<int>    _triaNodesTags;
56   int                 _nbRequiredTria;
57   std::vector<int>    _quadNodes;
58   std::vector<int>    _corners;
59
60   int                 _count;
61   volatile bool&      _cancelled_flag;
62   std::string         _errorStr;
63
64   double&             _progress;
65   double              _msgCost;
66
67   LibData( volatile bool & cancelled_flag, double& progress )
68     : _context(0), _session(0), _surf_mesh(0), _sizemap(0), _hybrid_mesh(0),
69       _nbRequiredEdges(0), _nbRequiredTria(0),
70       _cancelled_flag( cancelled_flag ), _progress( progress ), _msgCost( 0.00015 )
71   {
72   }
73   // methods setting callbacks implemented after callback definitions
74   void Init();
75   bool Compute();
76
77   ~LibData()
78   {
79     if ( _hybrid_mesh )
80       hybrid_regain_mesh( _session, _hybrid_mesh );
81     if ( _session )
82       hybrid_session_delete( _session );
83     if ( _surf_mesh )
84       mesh_delete( _surf_mesh );
85     if ( _sizemap )
86       sizemap_delete( _sizemap );
87     if ( _context )
88       context_delete( _context );
89
90     _hybrid_mesh = 0;
91     _session = 0;
92     _surf_mesh = 0;
93     _sizemap = 0;
94     _context = 0;
95   }
96
97   void AddError( const char *txt )
98   {
99     if ( txt )
100     {
101       _errorStr += txt;
102     }
103   }
104
105   const std::string& GetErrors()
106   {
107     return _errorStr;
108   }
109
110   void MG_Error(const char* txt="")
111   {
112     SMESH_Comment msg("\nMeshGems error. ");
113     msg << txt << "\n";
114     std::cout << msg;
115     AddError( msg.c_str() );
116   }
117
118   //================================================================================
119   /*!
120    * \brief SetParam to define a parameter by its value
121    *  \param [in] param - the parameter to set
122    *  \param [in] valus - its value
123    *  \return bool - Ok or not
124    */
125   //================================================================================
126   bool SetParam( const std::string& param, const std::string& value )
127   {
128     status_t ret = hybrid_set_param( _session, param.c_str(), value.c_str() );
129     MESSAGE(param << " = " << value);
130     return ( ret == STATUS_OK );
131   }
132
133
134   //================================================================================
135   /*!
136    * \brief SetTags to define boundary layers
137    *  \param [in] param - the parameter to set
138    *  \param [in] values - a list of ids separated by a comma
139    *  \param [in] size - the size of the boundary layer
140    *  \return bool - Ok or not
141    */
142   //================================================================================
143   bool SetTags( const std::string& param, const std::string& values, const std::string& size )
144   {
145     // constructing stream from the string
146     std::stringstream ss(values);
147     std::string s;
148     // for each string value separated by ',' call hybrid API to set the tag
149     while (getline(ss, s, ','))
150     {
151       status_t ret;
152       int tag = stoi(s);
153       if ( param=="boundary_layer_imprinting_tags" )
154       {
155         ret = hybrid_set_boundary_layer_imprinting_tag(_session, tag);
156         MESSAGE("imprinting " << tag);
157       }
158       else if ( param=="boundary_layer_snapping_tags" )
159       {
160         ret = hybrid_set_boundary_layer_snapping_tag(_session, tag);
161         MESSAGE("snapping " << tag);
162       }
163       else if ( param=="boundary_layer_surface_tags" )
164       {
165         ret = hybrid_set_initial_height_on_surface_tag(_session, tag, stod(size));
166         MESSAGE("height " << tag << " = " << stod(size));
167       }
168       if ( ret != STATUS_OK )
169       {
170         MESSAGE("PBBBBBBBBBBBBBBBBBBBBBB STATUS not OK ");
171         return false;
172       }
173     }
174     return true;
175   }
176
177   bool Cancelled()
178   {
179     return _cancelled_flag;
180   }
181
182   int ReadNbSubDomains()
183   {
184     integer nb = 0;
185     status_t ret = mesh_get_subdomain_count( _hybrid_mesh, & nb );
186
187     if ( ret != STATUS_OK ) MG_Error("mesh_get_subdomain_count problem");
188     return nb;
189   }
190
191   int ReadNbNodes()
192   {
193     _corners.clear();
194
195     integer nb = 0;
196     status_t ret = mesh_get_vertex_count( _hybrid_mesh, & nb );
197
198     if ( ret != STATUS_OK ) MG_Error("mesh_get_vertex_count problem");
199     return nb;
200   }
201
202   int ReadNbEdges()
203   {
204     integer nb = 0;
205     status_t ret = mesh_get_edge_count( _hybrid_mesh, & nb );
206
207     if ( ret != STATUS_OK ) MG_Error("mesh_get_edge_count problem");
208     return nb;
209   }
210
211   int ReadNbTria()
212   {
213     integer nb = 0;
214     status_t ret = mesh_get_triangle_count( _hybrid_mesh, & nb );
215
216     if ( ret != STATUS_OK ) MG_Error("mesh_get_triangle_count problem");
217     return nb;
218   }
219
220   int ReadNbQuads()
221   {
222     integer nb = 0;
223     status_t ret = mesh_get_quadrangle_count( _hybrid_mesh, & nb );
224
225     if ( ret != STATUS_OK ) MG_Error("mesh_get_quadrangle_count problem");
226     return nb;
227   }
228
229   int ReadNbTetra()
230   {
231     integer nb = 0;
232     status_t ret = mesh_get_tetrahedron_count( _hybrid_mesh, & nb );
233
234     if ( ret != STATUS_OK ) MG_Error("mesh_get_tetrahedron_count problem");
235     return nb;
236   }
237
238   int ReadNbHexa()
239   {
240     integer nb = 0;
241     status_t ret = mesh_get_hexahedron_count( _hybrid_mesh, & nb );
242
243     if ( ret != STATUS_OK ) MG_Error("mesh_get_hexahedron_count problem");
244     return nb;
245   }
246
247   int ReadNbPrisms()
248   {
249     integer nb = 0;
250     status_t ret = mesh_get_prism_count( _hybrid_mesh, & nb );
251
252     if ( ret != STATUS_OK ) MG_Error("mesh_get_prism_count problem");
253     return nb;
254   }
255
256   int ReadNbPyramids()
257   {
258     integer nb = 0;
259     status_t ret = mesh_get_pyramid_count( _hybrid_mesh, & nb );
260
261     if ( ret != STATUS_OK ) MG_Error("mesh_get_pyramid_count problem");
262     return nb;
263   }
264
265   int ReadNbCorners()
266   {
267     return _corners.size();
268   }
269
270   void ResetCounter()
271   {
272     _count = 1;
273   }
274
275   void ReadSubDomain( int* nbNodes, int* faceInd, int* ori, int* domain )
276   {
277     integer tag, seed_type, seed_idx, seed_orientation;
278     status_t ret = mesh_get_subdomain_description( _hybrid_mesh, _count,
279                                                    &tag, &seed_type, &seed_idx, &seed_orientation);
280
281     if ( ret != STATUS_OK ) MG_Error( "unable to get a sub-domain description");
282
283     *nbNodes = 3;
284     *faceInd = seed_idx;
285     *domain  = tag;
286     *ori     = seed_orientation;
287
288     ++_count;
289   }
290   void ReadNodeXYZ( double* x, double* y, double *z, int* /*domain*/  )
291   {
292     real coo[3];
293     status_t ret = mesh_get_vertex_coordinates( _hybrid_mesh, _count, coo );
294     if ( ret != STATUS_OK ) MG_Error( "unable to get resulting vertices" );
295
296     *x = coo[0];
297     *y = coo[1];
298     *z = coo[2];
299
300     integer isCorner = 0;
301     ret = mesh_get_vertex_corner_property( _hybrid_mesh, _count, &isCorner);
302     if (ret != STATUS_OK) MG_Error( "unable to get resulting vertex property" );
303     if ( isCorner )
304       _corners.push_back( _count );
305
306     ++_count;
307   }
308
309   void ReadEdgeNodes( int* node1, int* node2, int* domain )
310   {
311     integer vtx[2], tag;
312     status_t ret = mesh_get_edge_vertices( _hybrid_mesh, _count, vtx);
313     if (ret != STATUS_OK) MG_Error( "unable to get resulting edge" );
314
315     *node1 = vtx[0];
316     *node2 = vtx[1];
317
318     ret = mesh_get_edge_tag( _hybrid_mesh, _count, &tag );
319     if (ret != STATUS_OK) MG_Error( "unable to get resulting edge tag" );
320
321     *domain = tag;
322
323     ++_count;
324   }
325
326   void ReadTriaNodes( int* node1, int* node2, int* node3, int* domain )
327   {
328     integer vtx[3], tag;
329     status_t ret = mesh_get_triangle_vertices( _hybrid_mesh, _count, vtx);
330     if (ret != STATUS_OK) MG_Error( "unable to get resulting triangle" );
331
332     *node1 = vtx[0];
333     *node2 = vtx[1];
334     *node3 = vtx[2];
335
336     ret = mesh_get_triangle_tag( _hybrid_mesh, _count, &tag );
337     if (ret != STATUS_OK) MG_Error( "unable to get resulting triangle tag" );
338
339     *domain = tag;
340
341     ++_count;
342   }
343
344   void ReadQuadNodes( int* node1, int* node2, int* node3, int* node4, int* domain )
345   {
346     integer vtx[4], tag;
347     status_t ret = mesh_get_quadrangle_vertices( _hybrid_mesh, _count, vtx);
348     if (ret != STATUS_OK) MG_Error( "unable to get resulting quadrangle" );
349
350     *node1 = vtx[0];
351     *node2 = vtx[1];
352     *node3 = vtx[2];
353     *node4 = vtx[3];
354
355     ret = mesh_get_quadrangle_tag( _hybrid_mesh, _count, &tag );
356     if (ret != STATUS_OK) MG_Error( "unable to get resulting quadrangle tag" );
357
358     *domain = tag;
359
360     ++_count;
361   }
362
363   void ReadTetraNodes( int* node1, int* node2, int* node3, int* node4, int* domain )
364   {
365     integer vtx[4], tag;
366     status_t ret = mesh_get_tetrahedron_vertices( _hybrid_mesh, _count, vtx);
367     if (ret != STATUS_OK) MG_Error( "unable to get resulting tetrahedron" );
368
369     *node1 = vtx[0];
370     *node2 = vtx[1];
371     *node3 = vtx[2];
372     *node4 = vtx[3];
373
374     ret = mesh_get_tetrahedron_tag( _hybrid_mesh, _count, &tag );
375     if (ret != STATUS_OK) MG_Error( "unable to get resulting tetrahedron tag" );
376
377     *domain = tag;
378
379     ++_count;
380   }
381
382   void ReadHexaNodes( int* node1, int* node2, int* node3, int* node4,
383                       int* node5, int* node6, int* node7, int* node8, int* domain )
384   {
385     integer vtx[8], tag;
386     status_t ret = mesh_get_hexahedron_vertices( _hybrid_mesh, _count, vtx);
387     if (ret != STATUS_OK) MG_Error( "unable to get resulting hexahedron" );
388
389     *node1 = vtx[0];
390     *node2 = vtx[1];
391     *node3 = vtx[2];
392     *node4 = vtx[3];
393     *node5 = vtx[4];
394     *node6 = vtx[5];
395     *node7 = vtx[6];
396     *node8 = vtx[7];
397
398     ret = mesh_get_hexahedron_tag( _hybrid_mesh, _count, &tag );
399     if (ret != STATUS_OK) MG_Error( "unable to get resulting hexahedron tag" );
400
401     *domain = tag;
402
403     ++_count;
404   }
405
406   void ReadPrismNodes( int* node1, int* node2, int* node3, int* node4,
407                        int* node5, int* node6, int* /*domain*/ )
408   {
409     integer vtx[6];
410     status_t ret = mesh_get_prism_vertices( _hybrid_mesh, _count, vtx);
411     if (ret != STATUS_OK) MG_Error( "unable to get resulting prism" );
412
413     *node1 = vtx[0];
414     *node2 = vtx[1];
415     *node3 = vtx[2];
416     *node4 = vtx[3];
417     *node5 = vtx[4];
418     *node6 = vtx[5];
419
420     // integer tag;
421     // ret = mesh_get_hexahedron_tag( _hybrid_mesh, _count, &tag );
422     // if (ret != STATUS_OK) MG_Error( "unable to get resulting hexahedron tag" );
423
424     // *domain = tag;
425
426     ++_count;
427   }
428
429   void ReadPyramidNodes( int* node1, int* node2, int* node3, int* node4, int* node5, int* domain )
430   {
431     integer vtx[6];
432     status_t ret = mesh_get_pyramid_vertices( _hybrid_mesh, _count, vtx);
433     if (ret != STATUS_OK) MG_Error( "unable to get resulting pyramid" );
434
435     *node1 = vtx[0];
436     *node2 = vtx[1];
437     *node3 = vtx[2];
438     *node4 = vtx[3];
439     *node5 = vtx[4];
440
441     integer tag;
442     ret = mesh_get_pyramid_tag( _hybrid_mesh, _count, &tag );
443     if (ret != STATUS_OK) MG_Error( "unable to get resulting pyramid tag" );
444
445     *domain = tag;
446
447     ++_count;
448   }
449
450   void ReadCorner( int* node )
451   {
452     if ( _count <= ReadNbCorners() )
453       *node = _corners[ _count - 1 ];
454     else
455       *node = 0;
456
457     ++_count;
458   }
459
460   void SetNbVertices( int nb )
461   {
462     _xyz.reserve( _xyz.capacity() + nb );
463   }
464
465   void SetNbEdges( int nb )
466   {
467     _edgeNodesTags.reserve( nb * 3 );
468   }
469
470   void SetNbTria( int nb )
471   {
472     _triaNodesTags.reserve( nb * 4 );
473   }
474
475   void SetNbQuads( int nb )
476   {
477     _quadNodes.reserve( nb * 4 );
478   }
479
480   void SetNbReqVertices( int nb )
481   {
482     _nodeSize.reserve( nb );
483   }
484
485   void SetNbReqEdges( int nb )
486   {
487     _nbRequiredEdges = nb;
488   }
489
490   void SetNbReqTria( int nb )
491   {
492     _nbRequiredTria = nb;
493   }
494
495   void AddNode( double x, double y, double z, int /*domain*/ )
496   {
497     _xyz.push_back( x );
498     _xyz.push_back( y );
499     _xyz.push_back( z );
500   }
501
502   void AddSizeAtNode( double size )
503   {
504     _nodeSize.push_back( size );
505   }
506   
507   void AddEdgeNodes( int node1, int node2, int domain )
508   {
509     _edgeNodesTags.push_back( node1 );
510     _edgeNodesTags.push_back( node2 );
511     _edgeNodesTags.push_back( domain );
512   }
513   
514   void AddTriaNodes( int node1, int node2, int node3, int domain )
515   {
516     _triaNodesTags.push_back( node1 );
517     _triaNodesTags.push_back( node2 );
518     _triaNodesTags.push_back( node3 );
519     _triaNodesTags.push_back( domain );
520   }
521
522   void AddQuadNodes( int node1, int node2, int node3, int node4 )
523   {
524     _quadNodes.push_back( node1 );
525     _quadNodes.push_back( node2 );
526     _quadNodes.push_back( node3 );
527     _quadNodes.push_back( node4 );
528   }
529
530   int NbNodes()
531   {
532     return _xyz.size() / 3;
533   }
534
535   double* NodeCoord( int iNode )
536   {
537     return & _xyz[ iNode * 3 ];
538   }
539
540   int NbEdges()
541   {
542     return _edgeNodesTags.size() / 3;
543   }
544
545   int* GetEdgeNodes( int iEdge )
546   {
547     return & _edgeNodesTags[ iEdge * 3 ];
548   }
549
550   int GetEdgeTag( int iEdge )
551   {
552     return _edgeNodesTags[ iEdge * 3 + 2 ];
553   }
554
555   int NbTriangles()
556   {
557     return _triaNodesTags.size() / 4;
558   }
559
560   int * GetTriaNodes( int iTria )
561   {
562     return & _triaNodesTags[ iTria * 4 ];
563   }
564
565   int GetTriaTag( int iTria )
566   {
567     return _triaNodesTags[ iTria * 4 + 3 ];
568   }
569
570   int NbQuads()
571   {
572     return _quadNodes.size() / 4;
573   }
574
575   int * GetQuadNodes( int iQ )
576   {
577     return & _quadNodes[ iQ * 4 ];
578   }
579
580   int IsVertexRequired( int iNode )
581   {
582     return ! ( iNode < int( NbNodes() - _nodeSize.size() ));
583   }
584
585   double GetSizeAtVertex( int iNode )
586   {
587     return IsVertexRequired( iNode ) ? _nodeSize[ iNode - NbNodes() + _nodeSize.size() ] : 0.;
588   }
589 };
590
591 namespace // functions called by MG library to exchange with the application
592 {
593   status_t get_vertex_count(integer * nbvtx, void *user_data)
594   {
595     MG_HYBRID_API::LibData* data = (MG_HYBRID_API::LibData *) user_data;
596     *nbvtx = data->NbNodes();
597
598     return STATUS_OK;
599   }
600
601   status_t get_vertex_coordinates(integer ivtx, real * xyz, void *user_data)
602   {
603     MG_HYBRID_API::LibData* data = (MG_HYBRID_API::LibData *) user_data;
604     double* coord = data->NodeCoord( ivtx-1 );
605     for (int j = 0; j < 3; j++)
606       xyz[j] = coord[j];
607
608     return STATUS_OK;
609   }
610   status_t get_edge_count(integer * nbedge, void *user_data)
611   {
612     MG_HYBRID_API::LibData* data = (MG_HYBRID_API::LibData *) user_data;
613     *nbedge = data->NbEdges();
614
615     return STATUS_OK;
616   }
617
618   status_t get_edge_vertices(integer iedge, integer * vedge, void *user_data)
619   {
620     MG_HYBRID_API::LibData* data = (MG_HYBRID_API::LibData *) user_data;
621     int* nodes = data->GetEdgeNodes( iedge-1 );
622     vedge[0] = nodes[0];
623     vedge[1] = nodes[1];
624
625     return STATUS_OK;
626   }
627
628   status_t get_edge_tag(integer iedge, integer * tag, void *user_data)
629   {
630     MG_HYBRID_API::LibData* data = (MG_HYBRID_API::LibData *) user_data;
631     * tag = data->GetEdgeTag( iedge-1 );
632
633     return STATUS_OK;
634   }
635
636   status_t get_triangle_count(integer * nbtri, void *user_data)
637   {
638     MG_HYBRID_API::LibData* data = (MG_HYBRID_API::LibData *) user_data;
639     *nbtri = data->NbTriangles();
640
641     return STATUS_OK;
642   }
643
644   status_t get_triangle_vertices(integer itri, integer * vtri, void *user_data)
645   {
646     MG_HYBRID_API::LibData* data = (MG_HYBRID_API::LibData *) user_data;
647     int* nodes = data->GetTriaNodes( itri-1 );
648     vtri[0] = nodes[0];
649     vtri[1] = nodes[1];
650     vtri[2] = nodes[2];
651
652     return STATUS_OK;
653   }
654
655   status_t get_triangle_tag(integer itri, integer * tag, void *user_data)
656   {
657     MG_HYBRID_API::LibData* data = (MG_HYBRID_API::LibData *) user_data;
658     * tag = data->GetTriaTag( itri-1 );
659
660     return STATUS_OK;
661   }
662
663   status_t get_quadrangle_count(integer * nbq, void *user_data)
664   {
665     MG_HYBRID_API::LibData* data = (MG_HYBRID_API::LibData *) user_data;
666     *nbq = data->NbQuads();
667
668     return STATUS_OK;
669   }
670
671   status_t get_quadrangle_vertices(integer iq, integer * vq, void *user_data)
672   {
673     MG_HYBRID_API::LibData* data = (MG_HYBRID_API::LibData *) user_data;
674     int* nodes = data->GetQuadNodes( iq-1 );
675     vq[0] = nodes[0];
676     vq[1] = nodes[1];
677     vq[2] = nodes[2];
678     vq[3] = nodes[3];
679
680     return STATUS_OK;
681   }
682
683   status_t get_vertex_required_property(integer ivtx, integer * rvtx, void *user_data)
684   {
685     MG_HYBRID_API::LibData* data = (MG_HYBRID_API::LibData *) user_data;
686     *rvtx = data->IsVertexRequired( ivtx - 1 );
687
688     return STATUS_OK;
689   }
690
691   status_t get_vertex_weight(integer ivtx, real * wvtx, void *user_data)
692   {
693     MG_HYBRID_API::LibData* data = (MG_HYBRID_API::LibData *) user_data;
694     *wvtx = data->GetSizeAtVertex( ivtx - 1 );
695
696     return STATUS_OK;
697   }
698
699   status_t my_message_cb(message_t * msg, void *user_data)
700   {
701     char *desc;
702     integer e, n, m;
703     integer i, i_data[10];
704     real r_data[10];
705     n = m = 0;
706     message_get_description(msg, &desc);
707     message_get_number(msg, &e);
708
709     if (e < 0) {
710       printf("mg-hybrid ERROR %i : %s", MESHGEMS_ABS_CODE(e), desc);
711       message_get_integer_data_count(msg, &n);
712       message_get_real_data_count(msg, &m);
713       printf("MGMESSAGE %i ", e);
714       printf(" %i", n);
715       if (n > 0) {
716         message_get_integer_data(msg, 1, n, i_data);
717         for (i = 0; i < n; i++)
718           printf(" %i", i_data[i]);
719       }
720       printf(" %i", m);
721       if (m > 0) {
722         message_get_real_data(msg, 1, m, r_data);
723         for (i = 0; i < m; i++)
724           printf(" %f", r_data[i]);
725       }
726       printf(" \n");
727
728     }
729     if (e >= 0) {
730       if (e == 0)
731         printf("\rmg-hybrid info : %s", desc);
732       else
733         printf("mg-hybrid info %i : %s", MESHGEMS_CODE(e), desc);
734     }
735     message_get_description(msg, &desc);
736
737     MG_HYBRID_API::LibData* data = (MG_HYBRID_API::LibData *) user_data;
738     data->AddError( desc );
739
740     return STATUS_OK;
741   }
742
743   status_t my_interrupt_callback(integer *interrupt_status, void *user_data)
744   {
745     MG_HYBRID_API::LibData* data = (MG_HYBRID_API::LibData *) user_data;
746     *interrupt_status = ( data->Cancelled() ? INTERRUPT_STOP : INTERRUPT_CONTINUE );
747
748     return STATUS_OK;
749   }
750
751 } // end namespace
752
753
754 void MG_HYBRID_API::LibData::Init()
755 {
756   status_t ret;
757
758   // Create the meshgems working context
759   _context = context_new();
760   if ( !_context ) MG_Error( "unable to create a new context" );
761
762   // Set the message callback for the _context.
763   ret = context_set_message_callback( _context, my_message_cb, this );
764   if ( ret != STATUS_OK ) MG_Error("in context_set_message_callback");
765
766   // Create the structure holding the callbacks giving access to triangle mesh
767   _surf_mesh = mesh_new( _context );
768   if ( !_surf_mesh ) MG_Error("unable to create a new mesh");
769
770   // Set callbacks to provide triangle mesh data
771   mesh_set_get_vertex_count( _surf_mesh, get_vertex_count, this );
772   mesh_set_get_vertex_coordinates( _surf_mesh, get_vertex_coordinates, this );
773   mesh_set_get_vertex_required_property( _surf_mesh, get_vertex_required_property, this );
774   mesh_set_get_edge_count( _surf_mesh, get_edge_count, this);
775   mesh_set_get_edge_vertices( _surf_mesh, get_edge_vertices, this );
776   mesh_set_get_edge_tag( _surf_mesh, get_edge_tag, this );
777   mesh_set_get_triangle_count( _surf_mesh, get_triangle_count, this );
778   mesh_set_get_triangle_vertices( _surf_mesh, get_triangle_vertices, this );
779   mesh_set_get_triangle_tag( _surf_mesh, get_triangle_tag, this );
780   mesh_set_get_quadrangle_count( _surf_mesh, get_quadrangle_count, this );
781   mesh_set_get_quadrangle_vertices( _surf_mesh, get_quadrangle_vertices, this );
782
783   // Create a hybrid session
784   _session = hybrid_session_new( _context );
785   if ( !_session ) MG_Error( "unable to create a new hybrid session");
786
787   ret = hybrid_set_interrupt_callback( _session, my_interrupt_callback, this );
788   if ( ret != STATUS_OK ) MG_Error("in hybrid_set_interrupt_callback");
789
790 }
791
792 bool MG_HYBRID_API::LibData::Compute()
793 {
794   // MG license
795   std::string errorTxt;
796   status_t ret;
797
798   if ( !SMESHUtils_MGLicenseKeyGen::SignMesh( _surf_mesh, "hybrid", errorTxt ))
799   {
800     AddError( SMESH_Comment( "Problem with library SalomeMeshGemsKeyGenerator: ") << errorTxt );
801     return false;
802   }
803
804   // Set surface mesh
805   ret = hybrid_set_surface_mesh( _session, _surf_mesh );
806   if ( ret != STATUS_OK ) MG_Error( "unable to set surface mesh");
807
808 #ifndef WIN32
809   // Set a sizemap
810   if ( !_nodeSize.empty() )
811   {
812     _sizemap = meshgems_sizemap_new( _surf_mesh, meshgems_sizemap_type_iso_mesh_vertex,
813                                      (void*) &get_vertex_weight, this );
814     if ( !_sizemap ) MG_Error("unable to create a new sizemap");
815
816     ret = hybrid_set_sizemap( _session, _sizemap );
817     if ( ret != STATUS_OK ) MG_Error( "unable to set sizemap");
818   }
819 #endif
820
821   //////////////////////////////////////////////////////////////////////////////////////////
822   // const char* file  =  "/tmp/ghs3d_IN.mesh";
823   // mesh_write_mesh( _surf_mesh,file);
824   // std::cout << std::endl << std::endl << "Write " << file << std::endl << std::endl << std::endl;
825
826   ret = hybrid_compute_mesh( _session );
827   if ( ret != STATUS_OK ) return false;
828
829   ret = hybrid_get_mesh( _session, &_hybrid_mesh);
830   if (ret != STATUS_OK) MG_Error( "unable to get resulting mesh");
831
832   //////////////////////////////////////////////////////////////////////////////////////////
833   // file  =  "/tmp/ghs3d_OUT.mesh";
834   // mesh_write_mesh( _hybrid_mesh,file);
835   // std::cout << std::endl << std::endl << "Write " << file << std::endl << std::endl << std::endl;
836
837   return true;
838 }
839
840 #else // ifdef USE_MG_LIBS
841
842 struct MG_HYBRID_API::LibData // to avoid compiler warnings
843 {
844   volatile bool& _cancelled_flag;
845   double& _progress;
846   LibData(volatile bool& cancelled_flag, double& progress): _cancelled_flag{cancelled_flag}, _progress{progress} {}
847 };
848
849 #endif // ifdef USE_MG_LIBS
850
851
852 //================================================================================
853 /*!
854  * \brief Constructor
855  */
856 //================================================================================
857
858 MG_HYBRID_API::MG_HYBRID_API(volatile bool& cancelled_flag, double& progress)
859   :_nbNodes(0), _nbEdges(0), _nbFaces(0), _nbVolumes(0)
860 {
861   _useLib = false;
862   _libData = new LibData( cancelled_flag, progress );
863 }
864
865 //================================================================================
866 /*!
867  * \brief Destructor
868  */
869 //================================================================================
870
871 MG_HYBRID_API::~MG_HYBRID_API()
872 {
873   delete _libData;
874   _libData = 0;
875   std::set<int>::iterator id = _openFiles.begin();
876   for ( ; id != _openFiles.end(); ++id )
877     ::GmfCloseMesh( *id );
878   _openFiles.clear();
879 }
880
881 //================================================================================
882 /*!
883  * \brief Return the way of MG usage
884  */
885 //================================================================================
886
887 bool MG_HYBRID_API::IsLibrary()
888 {
889   return _useLib;
890 }
891
892 //================================================================================
893 /*!
894  * \brief Switch to usage of MG-HYBRID library
895  */
896 //================================================================================
897
898 void MG_HYBRID_API::SetUseLibrary()
899 {
900   _useLib = true;
901 #ifdef USE_MG_LIBS
902   _libData->Init();
903 #endif
904 }
905
906 //================================================================================
907 /*!
908  * \brief Switch to usage of MG-HYBRID executable
909  */
910 //================================================================================
911
912 void MG_HYBRID_API::SetUseExecutable()
913 {
914   _useLib = false;
915 }
916
917 //================================================================================
918 /*!
919  * \brief Compute the hybrid mesh
920  *  \param [in] cmdLine - a command to run mg_hybrid.exe
921  *  \return bool - Ok or not
922  */
923 //================================================================================
924
925 bool MG_HYBRID_API::Compute( const std::string& cmdLine, std::string& errStr )
926 {
927   if ( _useLib ) {
928 #ifdef USE_MG_LIBS
929     // split cmdLine
930     std::istringstream strm( cmdLine );
931     std::istream_iterator<std::string> sIt( strm ), sEnd;
932     std::vector< std::string > args( sIt, sEnd );
933
934     // set parameters
935     std::string param, value;
936     std::string boundary_layer_size;
937
938     for ( size_t i = 1; i < args.size(); i=i+2 )
939     {
940       param = args[i];
941       value = args[i+1];
942       MESSAGE("param: " <<  param);
943       MESSAGE("value: " <<  value);
944
945       // skipping output redirection, it is not a param to set
946       if (param=="1>")
947         continue;
948
949       // removing -- from param
950       while ( param[0] == '-')
951         param = param.substr( 1 );
952
953       // store this value for boundary layer definition (needed by setTags after)
954       if (param == "boundary_layer_global_initial_height")
955         boundary_layer_size = value;
956
957       // set parameters with list of tags (string of ids separated by a comma)
958       if (param=="boundary_layer_imprinting_tags" || param=="boundary_layer_snapping_tags" || param=="boundary_layer_surface_tags")
959       {
960         if (!_libData->SetTags(param, value, boundary_layer_size))
961           std::cout << "Warning: error in SetTags(" << param << ", " << value << ", " << boundary_layer_size << ")" << std::endl;
962       }
963       // set other parameters
964       else if ( !_libData->SetParam( param, value ))
965         std::cout << "Warning: wrong param: '" << param <<"' = '" << value << "'" << std::endl;
966     }
967
968     // compute
969     bool ok =  _libData->Compute();
970
971     GetLog(); // write a log file
972     _logFile = ""; // not to write it again
973
974     return ok;
975 #endif
976   }
977
978   // not library => call executable
979
980   // add MG license key
981   {
982     std::string errorTxt, meshIn;
983     std::string key = SMESHUtils_MGLicenseKeyGen::GetKey( meshIn,
984                                                           _nbNodes, _nbEdges, _nbFaces, _nbVolumes,
985                                                           errorTxt );
986     if ( key.empty() )
987     {
988       errStr = "Problem with library SalomeMeshGemsKeyGenerator: " + errorTxt;
989       return false;
990     }
991     if ( key != "0")
992       const_cast< std::string& >( cmdLine ) += " --key " + key;
993   }
994
995   int err = system( cmdLine.c_str() ); // run
996
997   if ( err )
998     errStr = SMESH_Comment("system(mg-hybrid.exe ...) command failed with error: ")
999       << strerror( errno );
1000
1001   return !err;
1002
1003 }
1004
1005 //================================================================================
1006 /*!
1007  * \brief Prepare for reading a mesh data
1008  */
1009 //================================================================================
1010
1011 int  MG_HYBRID_API::GmfOpenMesh(const char* theFile, int rdOrWr, int * ver, int * dim)
1012 {
1013   if ( _useLib ) {
1014 #ifdef USE_MG_LIBS
1015     return 1;
1016 #endif
1017   }
1018   int id = ::GmfOpenMesh(theFile, rdOrWr, ver, dim );
1019   _openFiles.insert( id );
1020   return id;
1021 }
1022
1023 //================================================================================
1024 /*!
1025  * \brief Return nb of entities
1026  */
1027 //================================================================================
1028
1029 int MG_HYBRID_API::GmfStatKwd( int iMesh, GmfKwdCod what )
1030 {
1031   if ( _useLib ) {
1032 #ifdef USE_MG_LIBS
1033     switch ( what )
1034     {
1035     case GmfSubDomainFromGeom: return _libData->ReadNbSubDomains();
1036     case GmfVertices:          return _libData->ReadNbNodes();
1037     case GmfEdges:             return _libData->ReadNbEdges();
1038     case GmfTriangles:         return _libData->ReadNbTria();
1039     case GmfQuadrilaterals:    return _libData->ReadNbQuads();
1040     case GmfTetrahedra:        return _libData->ReadNbTetra();
1041     case GmfPrisms:            return _libData->ReadNbPrisms();
1042     case GmfPyramids:          return _libData->ReadNbPyramids();
1043     case GmfHexahedra:         return _libData->ReadNbHexa();
1044     case GmfCorners:           return _libData->ReadNbCorners();
1045     default:                   return 0;
1046     }
1047     return 0;
1048 #endif
1049   }
1050   return ::GmfStatKwd( iMesh, what );
1051 }
1052
1053 //================================================================================
1054 /*!
1055  * \brief Prepare for reading some data
1056  */
1057 //================================================================================
1058
1059 void MG_HYBRID_API::GmfGotoKwd( int iMesh, GmfKwdCod what )
1060 {
1061   if ( _useLib ) {
1062 #ifdef USE_MG_LIBS
1063     _libData->ResetCounter();
1064     return;
1065 #endif
1066   }
1067   ::GmfGotoKwd( iMesh, what );
1068 }
1069
1070 //================================================================================
1071 /*!
1072  * \brief Return index of a domain identified by a triangle normal
1073  *  \param [in] iMesh - mesh file index
1074  *  \param [in] what - must be GmfSubDomainFromGeom
1075  *  \param [out] nbNodes - nb nodes in a face
1076  *  \param [out] faceInd - face index
1077  *  \param [out] ori - face orientation
1078  *  \param [out] domain - domain index
1079  *  \param [in] dummy - an artificial param used to discriminate from GmfGetLin() reading
1080  *              a triangle
1081  */
1082 //================================================================================
1083
1084 void MG_HYBRID_API::GmfGetLin( int iMesh, GmfKwdCod what, int* nbNodes, int* faceInd, int* ori, int* domain, int /*dummy*/ )
1085 {
1086   if ( _useLib ) {
1087 #ifdef USE_MG_LIBS
1088     _libData->ReadSubDomain( nbNodes, faceInd, ori, domain );
1089     return;
1090 #endif
1091   }
1092   ::GmfGetLin( iMesh, what, nbNodes, faceInd, ori, domain );
1093 }
1094
1095 //================================================================================
1096 /*!
1097  * \brief Return coordinates of a next node
1098  */
1099 //================================================================================
1100
1101 void MG_HYBRID_API::GmfGetLin(int iMesh, GmfKwdCod what,
1102                              double* x, double* y, double *z, int* domain )
1103 {
1104   if ( _useLib ) {
1105 #ifdef USE_MG_LIBS
1106     _libData->ReadNodeXYZ( x, y, z, domain );
1107     return;
1108 #endif
1109   }
1110   ::GmfGetLin(iMesh, what, x, y, z, domain );
1111 }
1112
1113 //================================================================================
1114 /*!
1115  * \brief Return coordinates of a next node
1116  */
1117 //================================================================================
1118
1119 void MG_HYBRID_API::GmfGetLin(int iMesh, GmfKwdCod what,
1120                              float* x, float* y, float *z, int* domain )
1121 {
1122   if ( _useLib ) {
1123 #ifdef USE_MG_LIBS
1124     double X,Y,Z;
1125     _libData->ReadNodeXYZ( &X, &Y, &Z, domain );
1126     *x = X;
1127     *y = Y;
1128     *z = Z;
1129     return;
1130 #endif
1131   }
1132   ::GmfGetLin(iMesh, what, x, y, z, domain );
1133 }
1134
1135 //================================================================================
1136 /*!
1137  * \brief Return node index of a next corner
1138  */
1139 //================================================================================
1140
1141 void MG_HYBRID_API::GmfGetLin(int iMesh, GmfKwdCod what, int* node )
1142 {
1143   if ( _useLib ) {
1144 #ifdef USE_MG_LIBS
1145     _libData->ReadCorner( node );
1146     return;
1147 #endif
1148   }
1149   ::GmfGetLin(iMesh, what, node );
1150 }
1151
1152 //================================================================================
1153 /*!
1154  * \brief Return node indices of a next edge
1155  */
1156 //================================================================================
1157
1158 void MG_HYBRID_API::GmfGetLin(int iMesh, GmfKwdCod what, int* node1, int* node2, int* domain )
1159 {
1160   if ( _useLib ) {
1161 #ifdef USE_MG_LIBS
1162     _libData->ReadEdgeNodes( node1, node2, domain );
1163     return;
1164 #endif
1165   }
1166   ::GmfGetLin( iMesh, what, node1, node2, domain );
1167 }
1168
1169 //================================================================================
1170 /*!
1171  * \brief Return node indices of a next triangle
1172  */
1173 //================================================================================
1174
1175 void MG_HYBRID_API::GmfGetLin(int iMesh, GmfKwdCod what,
1176                              int* node1, int* node2, int* node3, int* domain )
1177 {
1178   if ( _useLib ) {
1179 #ifdef USE_MG_LIBS
1180     _libData->ReadTriaNodes( node1, node2, node3, domain );
1181     return;
1182 #endif
1183   }
1184   ::GmfGetLin(iMesh, what, node1, node2, node3, domain );
1185 }
1186
1187 //================================================================================
1188 /*!
1189  * \brief Return node indices of a next tetrahedron or quadrangle
1190  */
1191 //================================================================================
1192
1193 void MG_HYBRID_API::GmfGetLin(int iMesh, GmfKwdCod what,
1194                              int* node1, int* node2, int* node3, int* node4, int* domain )
1195 {
1196   if ( _useLib ) {
1197 #ifdef USE_MG_LIBS
1198     if ( what == GmfQuadrilaterals )
1199       _libData->ReadQuadNodes( node1, node2, node3, node4, domain );
1200     else
1201       _libData->ReadTetraNodes( node1, node2, node3, node4, domain );
1202     return;
1203 #endif
1204   }
1205   ::GmfGetLin(iMesh, what, node1, node2, node3, node4, domain );
1206 }
1207
1208 //================================================================================
1209 /*!
1210  * \brief Return node indices of a next hexahedron
1211  */
1212 //================================================================================
1213
1214 void MG_HYBRID_API::GmfGetLin(int iMesh, GmfKwdCod what,
1215                              int* node1, int* node2, int* node3, int* node4,
1216                              int* node5, int* node6, int* node7, int* node8,
1217                              int* domain )
1218 {
1219   if ( _useLib ) {
1220 #ifdef USE_MG_LIBS
1221     _libData->ReadHexaNodes( node1, node2, node3, node4, node5, node6, node7, node8, domain );
1222     return;
1223 #endif
1224   }
1225   ::GmfGetLin(iMesh, what, node1, node2, node3, node4, node5, node6, node7, node8, domain );
1226 }
1227
1228 //================================================================================
1229 /*!
1230  * \brief Return node indices of a next pyramid
1231  */
1232 //================================================================================
1233
1234 void MG_HYBRID_API::GmfGetLin(int iMesh, GmfKwdCod what,
1235                               int* node1, int* node2, int* node3, int* node4,
1236                               int* node5, int* domain )
1237 {
1238   if ( _useLib ) {
1239 #ifdef USE_MG_LIBS
1240     _libData->ReadPyramidNodes( node1, node2, node3, node4, node5, domain );
1241     return;
1242 #endif
1243   }
1244   ::GmfGetLin(iMesh, what, node1, node2, node3, node4, node5, domain );
1245 }
1246
1247 //================================================================================
1248 /*!
1249  * \brief Return node indices of a next prism
1250  */
1251 //================================================================================
1252
1253 void MG_HYBRID_API::GmfGetLin(int iMesh, GmfKwdCod what,
1254                               int* node1, int* node2, int* node3, int* node4,
1255                               int* node5, int* node6, int* domain )
1256 {
1257   if ( _useLib ) {
1258 #ifdef USE_MG_LIBS
1259     _libData->ReadPrismNodes( node1, node2, node3, node4, node5, node6, domain );
1260     return;
1261 #endif
1262   }
1263   ::GmfGetLin(iMesh, what, node1, node2, node3, node4, node5, node6, domain );
1264 }
1265
1266 //================================================================================
1267 /*!
1268  * \brief Prepare for passing data to MeshGems
1269  */
1270 //================================================================================
1271
1272 int  MG_HYBRID_API::GmfOpenMesh(const char* theFile, int rdOrWr, int ver, int dim)
1273 {
1274   if ( _useLib ) {
1275 #ifdef USE_MG_LIBS
1276     return 1;
1277 #endif
1278   }
1279   int id = ::GmfOpenMesh(theFile, rdOrWr, ver, dim);
1280   _openFiles.insert( id );
1281   return id;
1282 }
1283
1284 //================================================================================
1285 /*!
1286  * \brief Set number of entities
1287  */
1288 //================================================================================
1289
1290 void MG_HYBRID_API::GmfSetKwd(int iMesh, GmfKwdCod what, int nb )
1291 {
1292   if ( iMesh == 1 )
1293   {
1294     switch ( what ) {
1295     case GmfVertices:       _nbNodes = nb; break;
1296     case GmfEdges:          _nbEdges = nb; break;
1297     case GmfTriangles:      _nbFaces += nb; break;
1298     case GmfQuadrilaterals: _nbFaces += nb; break;
1299     default:;
1300     }
1301   }
1302   if ( _useLib ) {
1303 #ifdef USE_MG_LIBS
1304     switch ( what ) {
1305     case GmfVertices:          _libData->SetNbVertices( nb ); break;
1306     case GmfEdges:             _libData->SetNbEdges   ( nb ); break;
1307     case GmfRequiredEdges:     _libData->SetNbReqEdges( nb ); break;
1308     case GmfTriangles:         _libData->SetNbTria    ( nb ); break;
1309     case GmfRequiredTriangles: _libData->SetNbReqTria ( nb ); break;
1310     default:;
1311     }
1312     return;
1313 #endif
1314   }
1315   ::GmfSetKwd(iMesh, what, nb );
1316 }
1317
1318 //================================================================================
1319 /*!
1320  * \brief Add coordinates of a node
1321  */
1322 //================================================================================
1323
1324 void MG_HYBRID_API::GmfSetLin(int iMesh, GmfKwdCod what, double x, double y, double z, int domain)
1325 {
1326   if ( _useLib ) {
1327 #ifdef USE_MG_LIBS
1328     _libData->AddNode( x, y, z, domain );
1329     return;
1330 #endif
1331   }
1332   ::GmfSetLin(iMesh, what, x, y, z, domain);
1333 }
1334
1335 //================================================================================
1336 /*!
1337  * \brief Set number of field entities
1338  *  \param [in] iMesh - solution file index
1339  *  \param [in] what - solution type
1340  *  \param [in] nbNodes - nb of entities
1341  *  \param [in] nbTypes - nb of data entries in each entity
1342  *  \param [in] type - types of the data entries
1343  *
1344  * Used to prepare to storing size at nodes
1345  */
1346 //================================================================================
1347
1348 void MG_HYBRID_API::GmfSetKwd(int iMesh, GmfKwdCod what, int nbNodes, int dummy, int type[] )
1349 {
1350   if ( _useLib ) {
1351 #ifdef USE_MG_LIBS
1352     if ( what == GmfSolAtVertices ) _libData->SetNbReqVertices( nbNodes );
1353     return;
1354 #endif
1355   }
1356   ::GmfSetKwd(iMesh, what, nbNodes, dummy, type );
1357 }
1358
1359 //================================================================================
1360 /*!
1361  * \brief Add solution data
1362  */
1363 //================================================================================
1364
1365 void MG_HYBRID_API::GmfSetLin(int iMesh, GmfKwdCod what, double vals[])
1366 {
1367   if ( _useLib ) {
1368 #ifdef USE_MG_LIBS
1369     _libData->AddSizeAtNode( vals[0] );
1370     return;
1371 #endif
1372   }
1373   ::GmfSetLin(iMesh, what, vals);
1374 }
1375
1376 //================================================================================
1377 /*!
1378  * \brief Add edge nodes
1379  */
1380 //================================================================================
1381
1382 void MG_HYBRID_API::GmfSetLin(int iMesh, GmfKwdCod what, int node1, int node2, int domain )
1383 {
1384   if ( _useLib ) {
1385 #ifdef USE_MG_LIBS
1386     _libData->AddEdgeNodes( node1, node2, domain );
1387     return;
1388 #endif
1389   }
1390   ::GmfSetLin(iMesh, what, node1, node2, domain );
1391 }
1392
1393 //================================================================================
1394 /*!
1395  * \brief Add a 'required' flag
1396  */
1397 //================================================================================
1398
1399 void MG_HYBRID_API::GmfSetLin(int iMesh, GmfKwdCod what, int id )
1400 {
1401   if ( _useLib ) {
1402 #ifdef USE_MG_LIBS
1403     return;
1404 #endif
1405   }
1406   ::GmfSetLin(iMesh, what, id );
1407 }
1408
1409 //================================================================================
1410 /*!
1411  * \brief Add triangle nodes
1412  */
1413 //================================================================================
1414
1415 void MG_HYBRID_API::GmfSetLin(int iMesh, GmfKwdCod what, int node1, int node2, int node3, int domain )
1416 {
1417   if ( _useLib ) {
1418 #ifdef USE_MG_LIBS
1419     _libData->AddTriaNodes( node1, node2, node3, domain );
1420     return;
1421 #endif
1422   }
1423   ::GmfSetLin(iMesh, what, node1, node2, node3, domain );
1424 }
1425
1426 //================================================================================
1427 /*!
1428  * \brief Add quadrangle nodes
1429  */
1430 //================================================================================
1431
1432 void MG_HYBRID_API::GmfSetLin(int iMesh, GmfKwdCod what, int node1, int node2, int node3, int node4, int domain )
1433 {
1434   if ( _useLib ) {
1435 #ifdef USE_MG_LIBS
1436     _libData->AddQuadNodes( node1, node2, node3, node4 );
1437     return;
1438 #endif
1439   }
1440   ::GmfSetLin(iMesh, what, node1, node2, node3, node4, domain );
1441 }
1442
1443 //================================================================================
1444 /*!
1445  * \brief Close a file
1446  */
1447 //================================================================================
1448
1449 void MG_HYBRID_API::GmfCloseMesh( int iMesh )
1450 {
1451   if ( _useLib ) {
1452 #ifdef USE_MG_LIBS
1453     return;
1454 #endif
1455   }
1456   ::GmfCloseMesh( iMesh );
1457   _openFiles.erase( iMesh );
1458 }
1459
1460 //================================================================================
1461 /*!
1462  * \brief Return true if the log is not empty
1463  */
1464 //================================================================================
1465
1466 bool MG_HYBRID_API::HasLog()
1467 {
1468   if ( _useLib ) {
1469 #ifdef USE_MG_LIBS
1470     return !_libData->GetErrors().empty();
1471 #endif
1472   }
1473   SMESH_File file( _logFile );
1474   return file.size() > 0;
1475 }
1476
1477 //================================================================================
1478 /*!
1479  * \brief Return log contents
1480  */
1481 //================================================================================
1482
1483 std::string MG_HYBRID_API::GetLog()
1484 {
1485   if ( _useLib ) {
1486 #ifdef USE_MG_LIBS
1487     const std::string& err = _libData->GetErrors();
1488     if ( !_logFile.empty() && !err.empty() )
1489     {
1490       SMESH_File file( _logFile, /*openForReading=*/false );
1491       file.openForWriting();
1492       file.write( err.c_str(), err.size() );
1493     }
1494     return err;
1495 #endif
1496   }
1497   SMESH_File file( _logFile );
1498   return file.getPos();
1499 }