Salome HOME
Working version for run_mesher for netgen 3d
[plugins/netgenplugin.git] / src / NETGENPlugin / NETGENPlugin_NETGEN_3D.cxx
index 1a5ad5cf78be6d8eb1fef7b0bacd27ff89fd84f5..caa026822593ba126d8a9efdb4bd8aec01aa97c5 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2022  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
 #include "NETGENPlugin_NETGEN_3D.hxx"
 
 #include "NETGENPlugin_Hypothesis.hxx"
+#include "NETGENPlugin_Provider.hxx"
+
+#include "DriverStep.hxx"
+#include "DriverMesh.hxx"
+#include "netgen_param.hxx"
 
 #include <SMDS_MeshElement.hxx>
 #include <SMDS_MeshNode.hxx>
@@ -45,6 +50,7 @@
 #include <StdMeshers_MaxElementVolume.hxx>
 #include <StdMeshers_QuadToTriaAdaptor.hxx>
 #include <StdMeshers_ViscousLayers.hxx>
+#include <SMESH_subMesh.hxx>
 
 #include <BRepGProp.hxx>
 #include <BRep_Tool.hxx>
 #include <vector>
 #include <map>
 
+#include <cstdlib>
+#include <boost/filesystem.hpp>
+namespace fs = boost::filesystem;
+
 /*
   Netgen include files
 */
 #define OCCGEOMETRY
 #endif
 #include <occgeom.hpp>
+
+#ifdef NETGEN_V5
+#include <ngexception.hpp>
+#endif
+#ifdef NETGEN_V6
+#include <core/exception.hpp>
+#endif
+
 namespace nglib {
 #include <nglib.h>
 }
 namespace netgen {
-#ifdef NETGEN_V5
-  extern int OCCGenerateMesh (OCCGeometry&, Mesh*&, MeshingParameters&, int, int);
-#else
-  extern int OCCGenerateMesh (OCCGeometry&, Mesh*&, int, int, char*);
-#endif
-  extern MeshingParameters mparam;
+
+  NETGENPLUGIN_DLL_HEADER
+
+  NETGENPLUGIN_DLL_HEADER
   extern volatile multithreadt multithread;
 }
 using namespace nglib;
@@ -88,15 +104,13 @@ using namespace std;
 
 //=============================================================================
 /*!
- *  
+ *
  */
 //=============================================================================
 
-NETGENPlugin_NETGEN_3D::NETGENPlugin_NETGEN_3D(int hypId, int studyId,
-                             SMESH_Gen* gen)
-  : SMESH_3D_Algo(hypId, studyId, gen)
+NETGENPlugin_NETGEN_3D::NETGENPlugin_NETGEN_3D(int hypId, SMESH_Gen* gen)
+  : SMESH_3D_Algo(hypId, gen)
 {
-  MESSAGE("NETGENPlugin_NETGEN_3D::NETGENPlugin_NETGEN_3D");
   _name = "NETGEN_3D";
   _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID);// 1 bit /shape type
   _compatibleHypothesis.push_back("MaxElementVolume");
@@ -114,18 +128,17 @@ NETGENPlugin_NETGEN_3D::NETGENPlugin_NETGEN_3D(int hypId, int studyId,
 
 //=============================================================================
 /*!
- *  
+ *
  */
 //=============================================================================
 
 NETGENPlugin_NETGEN_3D::~NETGENPlugin_NETGEN_3D()
 {
-  MESSAGE("NETGENPlugin_NETGEN_3D::~NETGENPlugin_NETGEN_3D");
 }
 
 //=============================================================================
 /*!
- *  
+ *
  */
 //=============================================================================
 
@@ -133,20 +146,18 @@ bool NETGENPlugin_NETGEN_3D::CheckHypothesis (SMESH_Mesh&         aMesh,
                                               const TopoDS_Shape& aShape,
                                               Hypothesis_Status&  aStatus)
 {
-  MESSAGE("NETGENPlugin_NETGEN_3D::CheckHypothesis");
-
   _hypMaxElementVolume = NULL;
   _hypParameters = NULL;
   _viscousLayersHyp = NULL;
   _maxElementVolume = DBL_MAX;
 
   // for correct work of GetProgress():
-  netgen::multithread.percent = 0.;
-  netgen::multithread.task = "Volume meshing";
+  //netgen::multithread.percent = 0.;
+  //netgen::multithread.task = "Volume meshing";
   _progressByTic = -1.;
 
   list<const SMESHDS_Hypothesis*>::const_iterator itl;
-  const SMESHDS_Hypothesis* theHyp;
+  //const SMESHDS_Hypothesis* theHyp;
 
   const list<const SMESHDS_Hypothesis*>& hyps =
     GetUsedHypothesis(aMesh, aShape, /*ignoreAuxiliary=*/false);
@@ -162,14 +173,15 @@ bool NETGENPlugin_NETGEN_3D::CheckHypothesis (SMESH_Mesh&         aMesh,
   {
     if ( !_hypMaxElementVolume )
       _hypMaxElementVolume = dynamic_cast< const StdMeshers_MaxElementVolume*> ( *h );
-    // if ( !_viscousLayersHyp ) several _viscousLayersHyp's allowed
+    if ( !_viscousLayersHyp ) // several _viscousLayersHyp's allowed
       _viscousLayersHyp = dynamic_cast< const StdMeshers_ViscousLayers*> ( *h );
     if ( ! _hypParameters )
       _hypParameters = dynamic_cast< const NETGENPlugin_Hypothesis*> ( *h );
 
     if ( *h != _hypMaxElementVolume &&
          *h != _viscousLayersHyp &&
-         *h != _hypParameters)
+         *h != _hypParameters &&
+         !dynamic_cast< const StdMeshers_ViscousLayers*>(*h)) // several VL hyps allowed
       aStatus = HYP_INCOMPATIBLE;
   }
   if ( _hypMaxElementVolume && _hypParameters )
@@ -183,6 +195,297 @@ bool NETGENPlugin_NETGEN_3D::CheckHypothesis (SMESH_Mesh&         aMesh,
   return aStatus == HYP_OK;
 }
 
+
+void NETGENPlugin_NETGEN_3D::FillParameters(const NETGENPlugin_Hypothesis* hyp, netgen_params &aParams)
+{
+  aParams.maxh               = hyp->GetMaxSize();
+  aParams.minh               = hyp->GetMinSize();
+  aParams.segmentsperedge    = hyp->GetNbSegPerEdge();
+  aParams.grading            = hyp->GetGrowthRate();
+  aParams.curvaturesafety    = hyp->GetNbSegPerRadius();
+  aParams.secondorder        = hyp->GetSecondOrder() ? 1 : 0;
+  aParams.quad               = hyp->GetQuadAllowed() ? 1 : 0;
+  aParams.optimize           = hyp->GetOptimize();
+  aParams.fineness           = hyp->GetFineness();
+  aParams.uselocalh          = hyp->GetSurfaceCurvature();
+  aParams.merge_solids       = hyp->GetFuseEdges();
+  aParams.chordalError       = hyp->GetChordalErrorEnabled() ? hyp->GetChordalError() : -1.;
+  aParams.optsteps2d         = aParams.optimize ? hyp->GetNbSurfOptSteps() : 0;
+  aParams.optsteps3d         = aParams.optimize ? hyp->GetNbVolOptSteps()  : 0;
+  aParams.elsizeweight       = hyp->GetElemSizeWeight();
+  aParams.opterrpow          = hyp->GetWorstElemMeasure();
+  aParams.delaunay           = hyp->GetUseDelauney();
+  aParams.checkoverlap       = hyp->GetCheckOverlapping();
+  aParams.checkchartboundary = hyp->GetCheckChartBoundary();
+#ifdef NETGEN_V6
+  // std::string
+  aParams.meshsizefilename = hyp->GetMeshSizeFile();
+#else
+  // const char*
+  aParams.meshsizefilename = hyp->GetMeshSizeFile().empty() ? 0 : hyp->GetMeshSizeFile().c_str();
+#endif
+#ifdef NETGEN_V6
+  aParams.closeedgefac = 2;
+#else
+  aParams.closeedgefac = 0;
+#endif
+}
+
+void NETGENPlugin_NETGEN_3D::exportElementOrientation(SMESH_Mesh& aMesh,
+                                                      const TopoDS_Shape& aShape,
+                                                      netgen_params& aParams,
+                                                      const std::string output_file)
+{
+  SMESH_MesherHelper helper(aMesh);
+  NETGENPlugin_Internals internals( aMesh, aShape, /*is3D=*/true );
+  SMESH_ProxyMesh::Ptr proxyMesh( new SMESH_ProxyMesh( aMesh ));
+  std::map<vtkIdType, bool> elemOrientation;
+
+  for ( TopExp_Explorer exFa( aShape, TopAbs_FACE ); exFa.More(); exFa.Next())
+  {
+    const TopoDS_Shape& aShapeFace = exFa.Current();
+    int faceID = aMesh.GetMeshDS()->ShapeToIndex( aShapeFace );
+    bool isInternalFace = internals.isInternalShape( faceID );
+    bool isRev = false;
+    if ( !isInternalFace &&
+          helper.NbAncestors(aShapeFace, aMesh, aShape.ShapeType()) > 1 )
+      // IsReversedSubMesh() can work wrong on strongly curved faces,
+      // so we use it as less as possible
+      isRev = helper.IsReversedSubMesh( TopoDS::Face( aShapeFace ));
+
+    const SMESHDS_SubMesh * aSubMeshDSFace = proxyMesh->GetSubMesh( aShapeFace );
+    if ( !aSubMeshDSFace ) continue;
+
+    SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements();
+    if ( aParams._quadraticMesh &&
+          dynamic_cast< const SMESH_ProxyMesh::SubMesh*>( aSubMeshDSFace ))
+    {
+      // add medium nodes of proxy triangles to helper (#16843)
+      while ( iteratorElem->more() )
+        helper.AddTLinks( static_cast< const SMDS_MeshFace* >( iteratorElem->next() ));
+
+      iteratorElem = aSubMeshDSFace->GetElements();
+    }
+    while ( iteratorElem->more() ) // loop on elements on a geom face
+    {
+      // check mesh face
+      const SMDS_MeshElement* elem = iteratorElem->next();
+      if ( !elem )
+        error( COMPERR_BAD_INPUT_MESH, "Null element encounters");
+      if ( elem->NbCornerNodes() != 3 )
+        error( COMPERR_BAD_INPUT_MESH, "Not triangle element encounters");
+      elemOrientation[elem->GetID()] = isRev;
+      // Add nodes of triangles and triangles them-selves to netgen mesh
+
+      // add three nodes of triangle
+/*      bool hasDegen = false;
+      for ( int iN = 0; iN < 3; ++iN )
+      {
+        const SMDS_MeshNode* node = elem->GetNode( iN );
+        const int shapeID = node->getshapeId();
+        if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_EDGE &&
+              helper.IsDegenShape( shapeID ))
+        {
+          // ignore all nodes on degeneraged edge and use node on its vertex instead
+          TopoDS_Shape vertex = TopoDS_Iterator( meshDS->IndexToShape( shapeID )).Value();
+          node = SMESH_Algo::VertexNode( TopoDS::Vertex( vertex ), meshDS );
+          hasDegen = true;
+        }
+        int& ngID = nodeToNetgenID.insert(TN2ID( node, invalid_ID )).first->second;
+        if ( ngID == invalid_ID )
+        {
+          ngID = ++Netgen_NbOfNodes;
+          Netgen_point [ 0 ] = node->X();
+          Netgen_point [ 1 ] = node->Y();
+          Netgen_point [ 2 ] = node->Z();
+          Ng_AddPoint(Netgen_mesh, Netgen_point);
+        }
+        Netgen_triangle[ isRev ? 2-iN : iN ] = ngID;
+      }
+      // add triangle
+      if ( hasDegen && (Netgen_triangle[0] == Netgen_triangle[1] ||
+                        Netgen_triangle[0] == Netgen_triangle[2] ||
+                        Netgen_triangle[2] == Netgen_triangle[1] ))
+        continue;
+
+      Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle);
+
+      if ( isInternalFace && !proxyMesh->IsTemporary( elem ))
+      {
+        swap( Netgen_triangle[1], Netgen_triangle[2] );
+        Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle);
+      }*/
+    } // loop on elements on a face
+  } // loop on faces of a SOLID or SHELL
+
+  std::ofstream df(output_file, ios::out|ios::binary);
+  int size=elemOrientation.size();
+  std::cout << size<< std::endl;
+  std::cout << "vtkIdType " << sizeof(vtkIdType) << std::endl;
+
+  df.write((char*)&size, sizeof(int));
+  for(auto const& [id, orient]:elemOrientation){
+    df.write((char*)&id, sizeof(vtkIdType));
+    df.write((char*)&orient, sizeof(bool));
+  }
+  df.close();
+  // for(auto const& [id, orient] : elemOrientation)
+  //   {
+  //     std::cout << id << " : " << orient << ", ";
+  //   }
+}
+
+int NETGENPlugin_NETGEN_3D::ParallelCompute(SMESH_Mesh&         aMesh,
+                                             const TopoDS_Shape& aShape)
+{
+  aMesh.Lock();
+  SMESH_Hypothesis::Hypothesis_Status hypStatus;
+  CheckHypothesis(aMesh, aShape, hypStatus);
+
+  // Temporary folder for run
+  fs::path tmp_folder = aMesh.tmp_folder / fs::unique_path(fs::path("Volume-%%%%-%%%%"));
+  fs::create_directories(tmp_folder);
+  // Using MESH2D generated after all triangles where created.
+  fs::path mesh_file=aMesh.tmp_folder / fs::path("Mesh2D.med");
+  fs::path element_orientation_file=tmp_folder / fs::path("element_orientation.dat");
+  fs::path new_element_file=tmp_folder / fs::path("new_elements.dat");
+  fs::path tmp_mesh_file=tmp_folder / fs::path("tmp_mesh.med");
+  // TODO: Remove that file we do not use it
+  fs::path output_mesh_file=tmp_folder / fs::path("output_mesh.med");
+  fs::path shape_file=tmp_folder / fs::path("shape.step");
+  fs::path param_file=tmp_folder / fs::path("netgen3d_param.txt");
+  fs::path log_file=tmp_folder / fs::path("run_mesher.log");
+  //TODO: Handle variable mesh_name
+  std::string mesh_name = "Maillage_1";
+
+  //Writing Shape
+  export_shape(shape_file.string(), aShape);
+  //Writing hypo
+  netgen_params aParams;
+  FillParameters(_hypParameters, aParams);
+
+  export_netgen_params(param_file.string(), aParams);
+
+  // Exporting element orientation
+  exportElementOrientation(aMesh, aShape, aParams, element_orientation_file.string());
+
+  aMesh.Unlock();
+  // Calling run_mesher
+  std::string cmd;
+  // TODO: Add run_meher to bin
+  std::string run_mesher_exe = "/home/B61570/work_in_progress/ssmesh/run_mesher/build/src/run_mesher";
+  cmd = run_mesher_exe +
+                  " NETGEN3D " + mesh_file.string() + " "
+                               + shape_file.string() + " "
+                               + param_file.string() + " "
+                               + element_orientation_file.string() + " "
+                               + new_element_file.string() + " "
+                               + output_mesh_file.string() +
+                               " >> " + log_file.string();
+
+  std::cout << "Running command: " << std::endl;
+  std::cout << cmd << std::endl;
+
+  // Writing command in log
+  std::ofstream flog(log_file.string());
+  flog << cmd << endl;
+  flog.close();
+
+  int ret = system(cmd.c_str());
+
+  // TODO: error handling
+  if(ret != 0){
+    // Run crahed
+    //throw Exception("Meshing failed");
+    std::cerr << "Issue with command: " << std::endl;
+    std::cerr << cmd << std::endl;
+    return false;
+  }
+
+
+  aMesh.Lock();
+  std::ifstream df(new_element_file.string(), ios::binary);
+
+
+  int Netgen_NbOfNodes;
+  int Netgen_NbOfNodesNew;
+  int Netgen_NbOfTetra;
+  double Netgen_point[3];
+  int    Netgen_tetrahedron[4];
+  int nodeID;
+
+  SMESH_MesherHelper helper(aMesh);
+  // This function
+  int _quadraticMesh = helper.IsQuadraticSubMesh(aShape);
+  helper.SetElementsOnShape( true );
+
+  // Filling nodevec (correspondence netgen numbering mesh numbering)
+  // Number of nodes
+  df.read((char*) &Netgen_NbOfNodes, sizeof(int));
+  df.read((char*) &Netgen_NbOfNodesNew, sizeof(int));
+
+  vector< const SMDS_MeshNode* > nodeVec ( Netgen_NbOfNodesNew + 1 );
+
+  for (int nodeIndex = 1 ; nodeIndex <= Netgen_NbOfNodes; ++nodeIndex )
+  {
+    //Id of the point
+    df.read((char*) &nodeID, sizeof(int));
+    // std::cout << "Old Node " << nodeIndex << ": " << nodeID << std::endl;
+    // TODO: do stuff to fill nodeVec ??
+    nodeVec.at(nodeIndex) = nullptr;
+    SMDS_NodeIteratorPtr iteratorNode = aMesh.GetMeshDS()->nodesIterator();
+    while(iteratorNode->more()){
+      const SMDS_MeshNode* node = iteratorNode->next();
+      if(node->GetID() == nodeID){
+        nodeVec.at(nodeIndex) = node;
+        break;
+      }
+    }
+    if(nodeVec.at(nodeIndex) == nullptr){
+      std::cout << "Error could not identify id";
+      return false;
+    }
+  }
+
+  // Writing info on new points
+  for (int nodeIndex = Netgen_NbOfNodes +1 ; nodeIndex <= Netgen_NbOfNodesNew; ++nodeIndex )
+  {
+    // Coordinates of the point
+    df.read((char *) &Netgen_point, sizeof(double)*3);
+    // std::cout << "Node " << nodeIndex << ": ";
+    // for(auto coord:Netgen_point){
+    //   std::cout << coord << " ";
+    // }
+    // std::cout << std::endl;
+    nodeVec.at(nodeIndex) = helper.AddNode(Netgen_point[0],
+                                           Netgen_point[1],
+                                           Netgen_point[2]);
+
+  }
+
+  // create tetrahedrons
+  df.read((char*) &Netgen_NbOfTetra, sizeof(int));
+  for ( int elemIndex = 1; elemIndex <= Netgen_NbOfTetra; ++elemIndex )
+  {
+    df.read((char*) &Netgen_tetrahedron, sizeof(int)*4);
+    // std::cout << "Element " << elemIndex << ": ";
+    // for(auto elem:Netgen_tetrahedron){
+    //   std::cout << elem << " ";
+    // }
+    // std::cout << std::endl;
+    // TODO: Add tetra
+    helper.AddVolume (nodeVec.at( Netgen_tetrahedron[0] ),
+                      nodeVec.at( Netgen_tetrahedron[1] ),
+                      nodeVec.at( Netgen_tetrahedron[2] ),
+                      nodeVec.at( Netgen_tetrahedron[3] ));
+  }
+  df.close();
+
+  aMesh.Unlock();
+
+  return true;
+}
+
 //=============================================================================
 /*!
  *Here we are going to use the NETGEN mesher
@@ -192,25 +495,34 @@ bool NETGENPlugin_NETGEN_3D::CheckHypothesis (SMESH_Mesh&         aMesh,
 bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh&         aMesh,
                                      const TopoDS_Shape& aShape)
 {
-  netgen::multithread.terminate = 0;
-  netgen::multithread.task = "Volume meshing";
+
+  return ParallelCompute(aMesh, aShape);
+  aMesh.Lock();
+  SMESH_Hypothesis::Hypothesis_Status hypStatus;
+  CheckHypothesis(aMesh, aShape, hypStatus);
+  aMesh.Unlock();
+
+  //netgen::multithread.terminate = 0;
+  //netgen::multithread.task = "Volume meshing";
   _progressByTic = -1.;
 
   SMESHDS_Mesh* meshDS = aMesh.GetMeshDS();
 
-  SMESH_MesherHelper helper(aMesh);
-  bool _quadraticMesh = helper.IsQuadraticSubMesh(aShape);
-  helper.SetElementsOnShape( true );
+  SMESH_MesherHelper *helper = new SMESH_MesherHelper(aMesh);
+  _quadraticMesh = helper->IsQuadraticSubMesh(aShape);
+  helper->SetElementsOnShape( true );
 
   int Netgen_NbOfNodes = 0;
   double Netgen_point[3];
   int Netgen_triangle[3];
 
-  NETGENPlugin_NetgenLibWrapper ngLib;
-  Ng_Mesh * Netgen_mesh = ngLib._ngMesh;
+  NETGENPlugin_NetgenLibWrapper *ngLib;
+  int id_nglib = nglib_provider.take(&ngLib);
+  Ng_Mesh * Netgen_mesh = (Ng_Mesh*)ngLib->_ngMesh;
 
   // vector of nodes in which node index == netgen ID
   vector< const SMDS_MeshNode* > nodeVec;
+  aMesh.Lock();
   {
     const int invalid_ID = -1;
 
@@ -235,14 +547,14 @@ bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh&         aMesh,
     SMESH_ProxyMesh::Ptr proxyMesh( new SMESH_ProxyMesh( aMesh ));
     if ( _viscousLayersHyp )
     {
-      netgen::multithread.percent = 3;
+      //netgen::multithread.percent = 3;
       proxyMesh = _viscousLayersHyp->Compute( aMesh, aShape );
       if ( !proxyMesh )
         return false;
     }
     if ( aMesh.NbQuadrangles() > 0 )
     {
-      netgen::multithread.percent = 6;
+      //netgen::multithread.percent = 6;
       StdMeshers_QuadToTriaAdaptor* Adaptor = new StdMeshers_QuadToTriaAdaptor;
       Adaptor->Compute(aMesh,aShape,proxyMesh.get());
       proxyMesh.reset( Adaptor );
@@ -255,14 +567,24 @@ bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh&         aMesh,
       bool isInternalFace = internals.isInternalShape( faceID );
       bool isRev = false;
       if ( checkReverse && !isInternalFace &&
-           helper.NbAncestors(aShapeFace, aMesh, aShape.ShapeType()) > 1 )
+           helper->NbAncestors(aShapeFace, aMesh, aShape.ShapeType()) > 1 )
         // IsReversedSubMesh() can work wrong on strongly curved faces,
         // so we use it as less as possible
-        isRev = helper.IsReversedSubMesh( TopoDS::Face( aShapeFace ));
+        isRev = helper->IsReversedSubMesh( TopoDS::Face( aShapeFace ));
 
       const SMESHDS_SubMesh * aSubMeshDSFace = proxyMesh->GetSubMesh( aShapeFace );
       if ( !aSubMeshDSFace ) continue;
+
       SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements();
+      if ( _quadraticMesh &&
+           dynamic_cast< const SMESH_ProxyMesh::SubMesh*>( aSubMeshDSFace ))
+      {
+        // add medium nodes of proxy triangles to helper (#16843)
+        while ( iteratorElem->more() )
+          helper->AddTLinks( static_cast< const SMDS_MeshFace* >( iteratorElem->next() ));
+
+        iteratorElem = aSubMeshDSFace->GetElements();
+      }
       while ( iteratorElem->more() ) // loop on elements on a geom face
       {
         // check mesh face
@@ -281,7 +603,7 @@ bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh&         aMesh,
           const SMDS_MeshNode* node = elem->GetNode( iN );
           const int shapeID = node->getshapeId();
           if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_EDGE &&
-               helper.IsDegenShape( shapeID ))
+               helper->IsDegenShape( shapeID ))
           {
             // ignore all nodes on degeneraged edge and use node on its vertex instead
             TopoDS_Shape vertex = TopoDS_Iterator( meshDS->IndexToShape( shapeID )).Value();
@@ -322,6 +644,7 @@ bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh&         aMesh,
       nodeVec[ n_id->second ] = n_id->first;
     nodeToNetgenID.clear();
 
+    // TODO: Handle internal vertex
     if ( internals.hasInternalVertexInSolid() )
     {
       netgen::OCCGeometry occgeo;
@@ -331,14 +654,90 @@ bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh&         aMesh,
                                                    internals);
     }
   }
+  aMesh.Unlock();
 
   // -------------------------
   // Generate the volume mesh
   // -------------------------
+  ngLib->_isComputeOk = compute( aMesh, *helper, nodeVec, *ngLib );
+  bool ret = ngLib->_isComputeOk;
+  nglib_provider.release(id_nglib, true);
 
-  return ( ngLib._isComputeOk = compute( aMesh, helper, nodeVec, Netgen_mesh));
+  return ret;
 }
 
+// namespace
+// {
+//   void limitVolumeSize( netgen::Mesh* ngMesh,
+//                         double        maxh )
+//   {
+//     // get average h of faces
+//     double faceh = 0;
+//     int nbh = 0;
+//     for (int i = 1; i <= ngMesh->GetNSE(); i++)
+//     {
+//       const netgen::Element2d& face = ngMesh->SurfaceElement(i);
+//       for (int j=1; j <= face.GetNP(); ++j)
+//       {
+//         const netgen::PointIndex & i1 = face.PNumMod(j);
+//         const netgen::PointIndex & i2 = face.PNumMod(j+1);
+//         if ( i1 < i2 )
+//         {
+//           const netgen::Point3d & p1 = ngMesh->Point( i1 );
+//           const netgen::Point3d & p2 = ngMesh->Point( i2 );
+//           faceh += netgen::Dist2( p1, p2 );
+//           nbh++;
+//         }
+//       }
+//     }
+//     faceh = Sqrt( faceh / nbh );
+
+//     double compareh;
+//     if      ( faceh < 0.5 * maxh ) compareh = -1;
+//     else if ( faceh > 1.5 * maxh ) compareh = 1;
+//     else                           compareh = 0;
+//     // cerr << "faceh " << faceh << endl;
+//     // cerr << "init maxh " << maxh << endl;
+//     // cerr << "compareh " << compareh << endl;
+
+//     if ( compareh > 0 )
+//       maxh *= 1.2;
+//     else
+//       maxh *= 0.8;
+//     // cerr << "maxh " << maxh << endl;
+
+//     // get bnd box
+//     netgen::Point3d pmin, pmax;
+//     ngMesh->GetBox( pmin, pmax, 0 );
+//     const double dx = pmax.X() - pmin.X();
+//     const double dy = pmax.Y() - pmin.Y();
+//     const double dz = pmax.Z() - pmin.Z();
+
+//     if ( ! & ngMesh->LocalHFunction() )
+//       ngMesh->SetLocalH( pmin, pmax, compareh <= 0 ? 0.1 : 0.5 );
+
+//     // adjusted by SALOME_TESTS/Grids/smesh/bugs_08/I8
+//     const int nbX = Max( 2, int( dx / maxh * 2 ));
+//     const int nbY = Max( 2, int( dy / maxh * 2 ));
+//     const int nbZ = Max( 2, int( dz / maxh * 2 ));
+
+//     netgen::Point3d p;
+//     for ( int i = 0; i <= nbX; ++i )
+//     {
+//       p.X() = pmin.X() +  i * dx / nbX;
+//       for ( int j = 0; j <= nbY; ++j )
+//       {
+//         p.Y() = pmin.Y() +  j * dy / nbY;
+//         for ( int k = 0; k <= nbZ; ++k )
+//         {
+//           p.Z() = pmin.Z() +  k * dz / nbZ;
+//           ngMesh->RestrictLocalH( p, maxh );
+//         }
+//       }
+//     }
+//   }
+// }
+
 //================================================================================
 /*!
  * \brief set parameters and generate the volume mesh
@@ -348,62 +747,78 @@ bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh&         aMesh,
 bool NETGENPlugin_NETGEN_3D::compute(SMESH_Mesh&                     aMesh,
                                      SMESH_MesherHelper&             helper,
                                      vector< const SMDS_MeshNode* >& nodeVec,
-                                     Ng_Mesh *                       Netgen_mesh)
+                                     NETGENPlugin_NetgenLibWrapper&  ngLib)
 {
-  netgen::multithread.terminate = 0;
+  //netgen::multithread.terminate = 0;
 
-  netgen::Mesh* ngMesh = (netgen::Mesh*)Netgen_mesh;
-  int Netgen_NbOfNodes = Ng_GetNP(Netgen_mesh);
+  netgen::Mesh* ngMesh = ngLib._ngMesh;
+  Ng_Mesh* Netgen_mesh = ngLib.ngMesh();
+  int Netgen_NbOfNodes = Ng_GetNP( Netgen_mesh );
 
-#ifndef NETGEN_V5
-  char *optstr = 0;
-#endif
   int startWith = netgen::MESHCONST_MESHVOLUME;
   int endWith   = netgen::MESHCONST_OPTVOLUME;
   int err = 1;
 
   NETGENPlugin_Mesher aMesher( &aMesh, helper.GetSubShape(), /*isVolume=*/true );
-  netgen::OCCGeometry occgeo;
-  
+  netgen::OCCGeometry *occgeo;
+  int id_occgeo = occgeom_provider.take(&occgeo);
+  netgen::MeshingParameters mparam;
+  int id_mparam = mparam_provider.take(mparam);
+  aMesher.SetDefaultParameters(mparam);
+
   if ( _hypParameters )
   {
-    aMesher.SetParameters( _hypParameters );
+    aMesher.SetParameters( _hypParameters, mparam );
+
+    if ( !_hypParameters->GetLocalSizesAndEntries().empty() ||
+         !_hypParameters->GetMeshSizeFile().empty() )
+    {
+      if ( ! &ngMesh->LocalHFunction() )
+      {
+        netgen::Point3d pmin, pmax;
+        ngMesh->GetBox( pmin, pmax, 0 );
+        ngMesh->SetLocalH( pmin, pmax, _hypParameters->GetGrowthRate() );
+      }
+      aMesher.SetLocalSize( *occgeo, *ngMesh );
+
+      try {
+        ngMesh->LoadLocalMeshSize( mparam.meshsizefilename );
+      } catch (netgen::NgException & ex) {
+        return error( COMPERR_BAD_PARMETERS, ex.What() );
+      }
+    }
     if ( !_hypParameters->GetOptimize() )
       endWith = netgen::MESHCONST_MESHVOLUME;
   }
   else if ( _hypMaxElementVolume )
   {
-    netgen::mparam.maxh = pow( 72, 1/6. ) * pow( _maxElementVolume, 1/3. );
+    mparam.maxh = pow( 72, 1/6. ) * pow( _maxElementVolume, 1/3. );
+    // limitVolumeSize( ngMesh, mparam.maxh ); // result is unpredictable
   }
   else if ( aMesh.HasShapeToMesh() )
   {
-    aMesher.PrepareOCCgeometry( occgeo, helper.GetSubShape(), aMesh );
-    netgen::mparam.maxh = occgeo.GetBoundingBox().Diam()/2;
+    aMesher.PrepareOCCgeometry( *occgeo, helper.GetSubShape(), aMesh );
+    mparam.maxh = occgeo->GetBoundingBox().Diam()/2;
   }
   else
   {
     netgen::Point3d pmin, pmax;
     ngMesh->GetBox (pmin, pmax);
-    netgen::mparam.maxh = Dist(pmin, pmax)/2;
+    mparam.maxh = Dist(pmin, pmax)/2;
   }
 
   if ( !_hypParameters && aMesh.HasShapeToMesh() )
   {
-    netgen::mparam.minh = aMesher.GetDefaultMinSize( helper.GetSubShape(), netgen::mparam.maxh );
+    mparam.minh = aMesher.GetDefaultMinSize( helper.GetSubShape(), mparam.maxh );
   }
 
   try
   {
-#if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
     OCC_CATCH_SIGNALS;
-#endif
-#ifdef NETGEN_V5
-    ngMesh->CalcLocalH(netgen::mparam.grading);
-    err = netgen::OCCGenerateMesh(occgeo, ngMesh, netgen::mparam, startWith, endWith);
-#else
-    ngMesh->CalcLocalH();
-    err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr);
-#endif
+
+    ngLib.CalcLocalH(ngMesh);
+    err = ngLib.GenerateMesh(*occgeo, startWith, endWith, ngMesh, mparam);
+
     if(netgen::multithread.terminate)
       return false;
     if ( err )
@@ -418,7 +833,7 @@ bool NETGENPlugin_NETGEN_3D::compute(SMESH_Mesh&                     aMesh,
       str << ": " << ex.GetMessageString();
     error(str);
   }
-  catch (netgen::NgException exc)
+  catch (netgen::NgException& exc)
   {
     SMESH_Comment str("NgException");
     if ( strlen( netgen::multithread.task ) > 0 )
@@ -437,10 +852,6 @@ bool NETGENPlugin_NETGEN_3D::compute(SMESH_Mesh&                     aMesh,
   int Netgen_NbOfNodesNew = Ng_GetNP(Netgen_mesh);
   int Netgen_NbOfTetra    = Ng_GetNE(Netgen_mesh);
 
-  MESSAGE("End of Volume Mesh Generation. err=" << err <<
-          ", nb new nodes: " << Netgen_NbOfNodesNew - Netgen_NbOfNodes <<
-          ", nb tetra: " << Netgen_NbOfTetra);
-
   // -------------------------------------------------------------------
   // Feed back the SMESHDS with the generated Nodes and Volume Elements
   // -------------------------------------------------------------------
@@ -448,10 +859,14 @@ bool NETGENPlugin_NETGEN_3D::compute(SMESH_Mesh&                     aMesh,
   if ( err )
   {
     SMESH_ComputeErrorPtr ce = NETGENPlugin_Mesher::ReadErrors(nodeVec);
-    if ( ce && !ce->myBadElements.empty() )
+    if ( ce && ce->HasBadElems() )
       error( ce );
   }
 
+  mparam_provider.release(id_mparam);
+  occgeom_provider.release(id_occgeo, true);
+
+  aMesh.Lock();
   bool isOK = ( /*status == NG_OK &&*/ Netgen_NbOfTetra > 0 );// get whatever built
   if ( isOK )
   {
@@ -483,6 +898,8 @@ bool NETGENPlugin_NETGEN_3D::compute(SMESH_Mesh&                     aMesh,
       }
     }
   }
+  aMesh.Unlock();
+
 
   return !err;
 }
@@ -513,16 +930,11 @@ bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh&         aMesh,
   // ---------------------------------
 
   int Netgen_NbOfNodes = 0;
-  int Netgen_param2ndOrder = 0;
-  double Netgen_paramFine = 1.;
-  double Netgen_paramSize = pow( 72, 1/6. ) * pow( _maxElementVolume, 1/3. );
-
   double Netgen_point[3];
   int Netgen_triangle[3];
-  int Netgen_tetrahedron[4];
 
   NETGENPlugin_NetgenLibWrapper ngLib;
-  Ng_Mesh * Netgen_mesh = ngLib._ngMesh;
+  Ng_Mesh * Netgen_mesh = ngLib.ngMesh();
 
   SMESH_ProxyMesh::Ptr proxyMesh( new SMESH_ProxyMesh( aMesh ));
   if ( aMesh.NbQuadrangles() > 0 )
@@ -530,6 +942,13 @@ bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh&         aMesh,
     StdMeshers_QuadToTriaAdaptor* Adaptor = new StdMeshers_QuadToTriaAdaptor;
     Adaptor->Compute(aMesh);
     proxyMesh.reset( Adaptor );
+
+    if ( aHelper->IsQuadraticMesh() )
+    {
+      SMDS_ElemIteratorPtr fIt = proxyMesh->GetFaces();
+      while( fIt->more())
+        aHelper->AddTLinks( static_cast< const SMDS_MeshFace* >( fIt->next() ));
+    }
   }
 
   // maps nodes to ng ID
@@ -546,7 +965,7 @@ bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh&         aMesh,
       return error( COMPERR_BAD_INPUT_MESH, "Null element encounters");
     if ( elem->NbCornerNodes() != 3 )
       return error( COMPERR_BAD_INPUT_MESH, "Not triangle element encounters");
-      
+
     // add three nodes of triangle
     for ( int iN = 0; iN < 3; ++iN )
     {
@@ -578,7 +997,7 @@ bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh&         aMesh,
   // Generate the volume mesh
   // -------------------------
 
-  return ( ngLib._isComputeOk = compute( aMesh, *aHelper, nodeVec, Netgen_mesh));
+  return ( ngLib._isComputeOk = compute( aMesh, *aHelper, nodeVec, ngLib ));
 }
 
 void NETGENPlugin_NETGEN_3D::CancelCompute()
@@ -628,7 +1047,7 @@ bool NETGENPlugin_NETGEN_3D::Evaluate(SMESH_Mesh& aMesh,
                                       const TopoDS_Shape& aShape,
                                       MapShapeNbElems& aResMap)
 {
-  int nbtri = 0, nbqua = 0;
+  smIdType nbtri = 0, nbqua = 0;
   double fullArea = 0.0;
   for (TopExp_Explorer expF(aShape, TopAbs_FACE); expF.More(); expF.Next()) {
     TopoDS_Face F = TopoDS::Face( expF.Current() );
@@ -639,9 +1058,9 @@ bool NETGENPlugin_NETGEN_3D::Evaluate(SMESH_Mesh& aMesh,
       smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this));
       return false;
     }
-    std::vector<int> aVec = (*anIt).second;
-    nbtri += Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]);
-    nbqua += Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
+    std::vector<smIdType> aVec = (*anIt).second;
+    nbtri += std::max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]);
+    nbqua += std::max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
     GProp_GProps G;
     BRepGProp::SurfaceProperties(F,G);
     double anArea = G.Mass();
@@ -649,7 +1068,7 @@ bool NETGENPlugin_NETGEN_3D::Evaluate(SMESH_Mesh& aMesh,
   }
 
   // collect info from edges
-  int nb0d_e = 0, nb1d_e = 0;
+  smIdType nb0d_e = 0, nb1d_e = 0;
   bool IsQuadratic = false;
   bool IsFirst = true;
   TopTools_MapOfShape tmpMap;
@@ -666,9 +1085,9 @@ bool NETGENPlugin_NETGEN_3D::Evaluate(SMESH_Mesh& aMesh,
                                             "Submesh can not be evaluated",this));
       return false;
     }
-    std::vector<int> aVec = (*anIt).second;
+    std::vector<smIdType> aVec = (*anIt).second;
     nb0d_e += aVec[SMDSEntity_Node];
-    nb1d_e += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]);
+    nb1d_e += std::max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]);
     if(IsFirst) {
       IsQuadratic = (aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]);
       IsFirst = false;
@@ -676,7 +1095,7 @@ bool NETGENPlugin_NETGEN_3D::Evaluate(SMESH_Mesh& aMesh,
   }
   tmpMap.Clear();
 
-  double ELen_face = sqrt(2.* ( fullArea/(nbtri+nbqua*2) ) / sqrt(3.0) );
+  double ELen_face = sqrt(2.* ( fullArea/double(nbtri+nbqua*2) ) / sqrt(3.0) );
   double ELen_vol = pow( 72, 1/6. ) * pow( _maxElementVolume, 1/3. );
   double ELen = Min(ELen_vol,ELen_face*2);
 
@@ -685,11 +1104,11 @@ bool NETGENPlugin_NETGEN_3D::Evaluate(SMESH_Mesh& aMesh,
   double aVolume = G.Mass();
   double tetrVol = 0.1179*ELen*ELen*ELen;
   double CoeffQuality = 0.9;
-  int nbVols = int( aVolume/tetrVol/CoeffQuality );
-  int nb1d_f = (nbtri*3 + nbqua*4 - nb1d_e) / 2;
-  int nb1d_in = (nbVols*6 - nb1d_e - nb1d_f ) / 5;
-  std::vector<int> aVec(SMDSEntity_Last);
-  for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i]=0;
+  smIdType nbVols = (smIdType)( aVolume/tetrVol/CoeffQuality );
+  smIdType nb1d_f = (nbtri*3 + nbqua*4 - nb1d_e) / 2;
+  smIdType nb1d_in = (nbVols*6 - nb1d_e - nb1d_f ) / 5;
+  std::vector<smIdType> aVec(SMDSEntity_Last);
+  for(smIdType i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i]=0;
   if( IsQuadratic ) {
     aVec[SMDSEntity_Node] = nb1d_in/6 + 1 + nb1d_in;
     aVec[SMDSEntity_Quad_Tetra] = nbVols - nbqua*2;
@@ -702,7 +1121,7 @@ bool NETGENPlugin_NETGEN_3D::Evaluate(SMESH_Mesh& aMesh,
   }
   SMESH_subMesh *sm = aMesh.GetSubMesh(aShape);
   aResMap.insert(std::make_pair(sm,aVec));
-  
+
   return true;
 }