0021676: EDF 2283 NETGENPLUGIN: Improve Netgen 1D-2D-3D to generate pyramids in case where input 2D mesh includes quadrangles
This commit is contained in:
parent
6eeed530c5
commit
1273dc58a7
@ -43,28 +43,21 @@
|
||||
#include <SMESH_Mesh.hxx>
|
||||
#include <SMESH_MesherHelper.hxx>
|
||||
#include <SMESH_subMesh.hxx>
|
||||
#include <StdMeshers_QuadToTriaAdaptor.hxx>
|
||||
|
||||
#include <utilities.h>
|
||||
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
|
||||
#include <BRepBuilderAPI_Copy.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <Bnd_B3d.hxx>
|
||||
#include <GCPnts_AbscissaPoint.hxx>
|
||||
#include <GeomAdaptor_Curve.hxx>
|
||||
#include <NCollection_Map.hxx>
|
||||
#include <OSD_File.hxx>
|
||||
#include <OSD_Path.hxx>
|
||||
#include <Standard_ErrorHandler.hxx>
|
||||
#include <Standard_ProgramError.hxx>
|
||||
#include <TCollection_AsciiString.hxx>
|
||||
#include <TopExp.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopTools_DataMapIteratorOfDataMapOfShapeInteger.hxx>
|
||||
#include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
|
||||
#include <TopTools_DataMapOfShapeInteger.hxx>
|
||||
#include <TopTools_DataMapOfShapeShape.hxx>
|
||||
#include <TopTools_ListIteratorOfListOfShape.hxx>
|
||||
#include <TopTools_MapOfShape.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
|
||||
@ -82,6 +75,9 @@ namespace netgen {
|
||||
extern volatile multithreadt multithread;
|
||||
}
|
||||
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
|
||||
using namespace nglib;
|
||||
using namespace std;
|
||||
|
||||
@ -211,7 +207,7 @@ void NETGENPlugin_Mesher::SetParameters(const NETGENPlugin_Hypothesis* hyp)
|
||||
mparams.secondorder = hyp->GetSecondOrder() ? 1 : 0;
|
||||
// quad-dominated surface meshing
|
||||
// only triangles are allowed for volumic mesh
|
||||
if (!_isVolume)
|
||||
//if (!_isVolume)
|
||||
mparams.quad = static_cast<const NETGENPlugin_Hypothesis_2D*>
|
||||
(hyp)->GetQuadAllowed() ? 1 : 0;
|
||||
_optimize = hyp->GetOptimize();
|
||||
@ -612,10 +608,11 @@ void NETGENPlugin_Mesher::RestrictLocalSize(netgen::Mesh& ngMesh, const gp_XYZ&
|
||||
*/
|
||||
//================================================================================
|
||||
|
||||
bool NETGENPlugin_Mesher::fillNgMesh(const netgen::OCCGeometry& occgeom,
|
||||
bool NETGENPlugin_Mesher::fillNgMesh(netgen::OCCGeometry& occgeom,
|
||||
netgen::Mesh& ngMesh,
|
||||
vector<const SMDS_MeshNode*>& nodeVec,
|
||||
const list< SMESH_subMesh* > & meshedSM)
|
||||
const list< SMESH_subMesh* > & meshedSM,
|
||||
SMESH_ProxyMesh::Ptr proxyMesh)
|
||||
{
|
||||
TNode2IdMap nodeNgIdMap;
|
||||
for ( int i = 1; i < nodeVec.size(); ++i )
|
||||
@ -627,7 +624,7 @@ bool NETGENPlugin_Mesher::fillNgMesh(const netgen::OCCGeometry& occgeom,
|
||||
|
||||
SMESH_MesherHelper helper (*_mesh);
|
||||
|
||||
int faceNgID = occgeom.fmap.Extent();
|
||||
int faceNgID = ngMesh.GetNFD();
|
||||
|
||||
list< SMESH_subMesh* >::const_iterator smIt, smEnd = meshedSM.end();
|
||||
for ( smIt = meshedSM.begin(); smIt != smEnd; ++smIt )
|
||||
@ -636,7 +633,7 @@ bool NETGENPlugin_Mesher::fillNgMesh(const netgen::OCCGeometry& occgeom,
|
||||
if ( !visitedShapes.Add( sm->GetSubShape() ))
|
||||
continue;
|
||||
|
||||
SMESHDS_SubMesh * smDS = sm->GetSubMeshDS();
|
||||
const SMESHDS_SubMesh * smDS = sm->GetSubMeshDS();
|
||||
if ( !smDS ) continue;
|
||||
|
||||
switch ( sm->GetSubShape().ShapeType() )
|
||||
@ -799,19 +796,38 @@ bool NETGENPlugin_Mesher::fillNgMesh(const netgen::OCCGeometry& occgeom,
|
||||
|
||||
// Find solids the geomFace bounds
|
||||
int solidID1 = 0, solidID2 = 0;
|
||||
PShapeIteratorPtr solidIt = helper.GetAncestors( geomFace, *sm->GetFather(), TopAbs_SOLID);
|
||||
while ( const TopoDS_Shape * solid = solidIt->next() )
|
||||
StdMeshers_QuadToTriaAdaptor* quadAdaptor =
|
||||
dynamic_cast<StdMeshers_QuadToTriaAdaptor*>( proxyMesh.get() );
|
||||
if ( quadAdaptor )
|
||||
{
|
||||
int id = occgeom.somap.FindIndex ( *solid );
|
||||
if ( solidID1 && id != solidID1 ) solidID2 = id;
|
||||
else solidID1 = id;
|
||||
solidID1 = occgeom.somap.FindIndex( quadAdaptor->GetShape() );
|
||||
}
|
||||
else
|
||||
{
|
||||
PShapeIteratorPtr solidIt = helper.GetAncestors( geomFace, *sm->GetFather(), TopAbs_SOLID);
|
||||
while ( const TopoDS_Shape * solid = solidIt->next() )
|
||||
{
|
||||
int id = occgeom.somap.FindIndex ( *solid );
|
||||
if ( solidID1 && id != solidID1 ) solidID2 = id;
|
||||
else solidID1 = id;
|
||||
}
|
||||
}
|
||||
faceNgID++;
|
||||
//_faceDescriptors[ faceNgID ].first = solidID1;
|
||||
//_faceDescriptors[ faceNgID ].second = solidID2;
|
||||
// Add ng face descriptors of meshed faces
|
||||
faceNgID++;
|
||||
ngMesh.AddFaceDescriptor (netgen::FaceDescriptor(faceNgID, solidID1, solidID2, 0));
|
||||
|
||||
// if second oreder is required, even already meshed faces must be passed to NETGEN
|
||||
int fID = occgeom.fmap.Add( geomFace );
|
||||
while ( fID < faceNgID ) // geomFace is already in occgeom.fmap, add a copy
|
||||
fID = occgeom.fmap.Add( BRepBuilderAPI_Copy( geomFace, /*copyGeom=*/false ));
|
||||
// Problem with the second order in a quadrangular mesh remains.
|
||||
// 1) All quadrangles geberated by NETGEN are moved to an inexistent face
|
||||
// by FillSMesh() (find AddFaceDescriptor)
|
||||
// 2) Temporary triangles generated by StdMeshers_QuadToTriaAdaptor
|
||||
// are on faces where quadrangles were.
|
||||
// Due to these 2 points, wrong geom faces are used while conversion to qudratic
|
||||
// of the mentioned above quadrangles and triangles
|
||||
|
||||
// Orient the face correctly in solidID1 (issue 0020206)
|
||||
bool reverse = false;
|
||||
if ( solidID1 ) {
|
||||
@ -830,8 +846,11 @@ bool NETGENPlugin_Mesher::fillNgMesh(const netgen::OCCGeometry& occgeom,
|
||||
|
||||
#ifdef DUMP_TRIANGLES
|
||||
cout << "SMESH face " << helper.GetMeshDS()->ShapeToIndex( geomFace )
|
||||
<< " internal="<<isInternalFace<< " border="<<isBorderFace << endl;
|
||||
<< " internal="<<isInternalFace << endl;
|
||||
#endif
|
||||
if ( proxyMesh )
|
||||
smDS = proxyMesh->GetSubMesh( geomFace );
|
||||
|
||||
SMDS_ElemIteratorPtr faces = smDS->GetElements();
|
||||
while ( faces->more() )
|
||||
{
|
||||
@ -1446,7 +1465,7 @@ void NETGENPlugin_Mesher::addIntVerticesInSolids(const netgen::OCCGeometry&
|
||||
//================================================================================
|
||||
|
||||
int NETGENPlugin_Mesher::FillSMesh(const netgen::OCCGeometry& occgeo,
|
||||
const netgen::Mesh& ngMesh,
|
||||
netgen::Mesh& ngMesh,
|
||||
const NETGENPlugin_ngMeshInfo& initState,
|
||||
SMESH_Mesh& sMesh,
|
||||
std::vector<const SMDS_MeshNode*>& nodeVec,
|
||||
@ -1459,7 +1478,10 @@ int NETGENPlugin_Mesher::FillSMesh(const netgen::OCCGeometry& occgeo,
|
||||
|
||||
SMESHDS_Mesh* meshDS = sMesh.GetMeshDS();
|
||||
|
||||
// create and insert nodes into nodeVec
|
||||
// -------------------------------------
|
||||
// Create and insert nodes into nodeVec
|
||||
// -------------------------------------
|
||||
|
||||
nodeVec.resize( nbNod + 1 );
|
||||
int i, nbInitNod = initState._nbNodes;
|
||||
for (i = nbInitNod+1; i <= nbNod; ++i )
|
||||
@ -1492,7 +1514,10 @@ int NETGENPlugin_Mesher::FillSMesh(const netgen::OCCGeometry& occgeo,
|
||||
nodeVec[i] = node;
|
||||
}
|
||||
|
||||
// create mesh segments along geometric edges
|
||||
// -------------------------------------------
|
||||
// Create mesh segments along geometric edges
|
||||
// -------------------------------------------
|
||||
|
||||
int nbInitSeg = initState._nbSegments;
|
||||
for (i = nbInitSeg+1; i <= nbSeg; ++i )
|
||||
{
|
||||
@ -1565,8 +1590,17 @@ int NETGENPlugin_Mesher::FillSMesh(const netgen::OCCGeometry& occgeo,
|
||||
}
|
||||
}
|
||||
|
||||
// create mesh faces along geometric faces
|
||||
// ----------------------------------------
|
||||
// Create mesh faces along geometric faces
|
||||
// ----------------------------------------
|
||||
|
||||
int nbInitFac = initState._nbFaces;
|
||||
int quadFaceID = ngMesh.GetNFD() + 1;
|
||||
if ( nbInitFac < nbFac )
|
||||
// add a faces descriptor to exclude qudrangle elements generated by NETGEN
|
||||
// from computation of 3D mesh
|
||||
ngMesh.AddFaceDescriptor (netgen::FaceDescriptor(quadFaceID, /*solid1=*/0, /*solid2=*/0, 0));
|
||||
|
||||
for (i = nbInitFac+1; i <= nbFac; ++i )
|
||||
{
|
||||
const netgen::Element2d& elem = ngMesh.SurfaceElement(i);
|
||||
@ -1604,6 +1638,8 @@ int NETGENPlugin_Mesher::FillSMesh(const netgen::OCCGeometry& occgeo,
|
||||
break;
|
||||
case netgen::QUAD:
|
||||
face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[3]);
|
||||
// exclude qudrangle elements from computation of 3D mesh
|
||||
const_cast< netgen::Element2d& >( elem ).SetIndex( quadFaceID );
|
||||
break;
|
||||
case netgen::TRIG6:
|
||||
face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[5],nodes[3],nodes[4]);
|
||||
@ -1611,6 +1647,8 @@ int NETGENPlugin_Mesher::FillSMesh(const netgen::OCCGeometry& occgeo,
|
||||
case netgen::QUAD8:
|
||||
face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[3],
|
||||
nodes[4],nodes[7],nodes[5],nodes[6]);
|
||||
// exclude qudrangle elements from computation of 3D mesh
|
||||
const_cast< netgen::Element2d& >( elem ).SetIndex( quadFaceID );
|
||||
break;
|
||||
default:
|
||||
MESSAGE("NETGEN created a face of unexpected type, ignoring");
|
||||
@ -1627,7 +1665,10 @@ int NETGENPlugin_Mesher::FillSMesh(const netgen::OCCGeometry& occgeo,
|
||||
meshDS->SetMeshElementOnShape(face, aFace);
|
||||
}
|
||||
|
||||
// create tetrahedra
|
||||
// ------------------
|
||||
// Create tetrahedra
|
||||
// ------------------
|
||||
|
||||
for (i = 1; i <= nbVol; ++i)
|
||||
{
|
||||
const netgen::Element& elem = ngMesh.VolumeElement(i);
|
||||
@ -1859,6 +1900,8 @@ bool NETGENPlugin_Mesher::Compute()
|
||||
return false;
|
||||
ngLib.setMesh(( Ng_Mesh*) ngMesh );
|
||||
|
||||
ngMesh->ClearFaceDescriptors(); // we make descriptors our-self
|
||||
|
||||
if ( _simpleHyp )
|
||||
{
|
||||
// Pass 1D simple parameters to NETGEN
|
||||
@ -2063,14 +2106,38 @@ bool NETGENPlugin_Mesher::Compute()
|
||||
// ---------------------
|
||||
// generate volume mesh
|
||||
// ---------------------
|
||||
// Fill ngMesh with nodes and faces of computed 2D submeshes
|
||||
if ( !err && _isVolume && !meshedSM[ MeshDim_2D ].empty() )
|
||||
// Fill ngMesh with nodes and faces of computed 2D submeshes
|
||||
if ( !err && _isVolume && ( !meshedSM[ MeshDim_2D ].empty() || mparams.quad ))
|
||||
{
|
||||
// load SMESH with computed segments and faces
|
||||
FillSMesh( occgeo, *ngMesh, initState, *_mesh, nodeVec, comment );
|
||||
// fill ng mesh
|
||||
|
||||
// compute pyramids on quadrangles
|
||||
SMESH_ProxyMesh::Ptr proxyMesh;
|
||||
if ( _mesh->NbQuadrangles() > 0 )
|
||||
for ( int iS = 1; iS <= occgeo.somap.Extent(); ++iS )
|
||||
{
|
||||
StdMeshers_QuadToTriaAdaptor* Adaptor = new StdMeshers_QuadToTriaAdaptor;
|
||||
proxyMesh.reset( Adaptor );
|
||||
|
||||
int nbPyrams = _mesh->NbPyramids();
|
||||
Adaptor->Compute( *_mesh, occgeo.somap(iS) );
|
||||
if ( nbPyrams != _mesh->NbPyramids() )
|
||||
{
|
||||
list< SMESH_subMesh* > quadFaceSM;
|
||||
for (TopExp_Explorer face(occgeo.somap(iS), TopAbs_FACE); face.More(); face.Next())
|
||||
if ( Adaptor->GetProxySubMesh( face.Current() ))
|
||||
{
|
||||
quadFaceSM.push_back( _mesh->GetSubMesh( face.Current() ));
|
||||
meshedSM[ MeshDim_2D ].remove( quadFaceSM.back() );
|
||||
}
|
||||
fillNgMesh(occgeo, *ngMesh, nodeVec, quadFaceSM, proxyMesh);
|
||||
}
|
||||
}
|
||||
// fill ngMesh with faces of sub-meshes
|
||||
err = ! ( fillNgMesh(occgeo, *ngMesh, nodeVec, meshedSM[ MeshDim_2D ]));
|
||||
initState = NETGENPlugin_ngMeshInfo(ngMesh);
|
||||
//toPython( ngMesh, "/tmp/ngPython.py");
|
||||
}
|
||||
if (!err && _isVolume)
|
||||
{
|
||||
@ -2236,7 +2303,7 @@ bool NETGENPlugin_Mesher::Compute()
|
||||
for (int i = 1; i <= occgeo.somap.Extent(); i++)
|
||||
if ( SMESH_subMesh* sm = _mesh->GetSubMeshContaining( occgeo.somap( i )))
|
||||
{
|
||||
bool smComputed = !sm->IsEmpty();
|
||||
bool smComputed = nbVol && !sm->IsEmpty();
|
||||
if ( smComputed && internals.hasInternalVertexInSolid( sm->GetId() ))
|
||||
{
|
||||
int nbIntV = internals.getSolidsWithVertices().find( sm->GetId() )->second.size();
|
||||
@ -2247,7 +2314,7 @@ bool NETGENPlugin_Mesher::Compute()
|
||||
if ( !smComputed && ( !smError || smError->IsOK() ))
|
||||
{
|
||||
smError.reset( new SMESH_ComputeError( *error ));
|
||||
if ( SMESH_Algo::GetMeshError( sm ) == SMESH_Algo::MEr_OK )
|
||||
if ( nbVol && SMESH_Algo::GetMeshError( sm ) == SMESH_Algo::MEr_OK )
|
||||
smError->myName = COMPERR_WARNING;
|
||||
}
|
||||
pb3D = pb3D || ( smError && smError->IsKO() );
|
||||
@ -2543,6 +2610,75 @@ NETGENPlugin_Mesher::readErrors(const vector<const SMDS_MeshNode* >& nodeVec)
|
||||
return err;
|
||||
}
|
||||
|
||||
//================================================================================
|
||||
/*!
|
||||
* \brief Write a python script creating an equivalent SALOME mesh.
|
||||
* This is useful to see what mesh is passed as input for the next step of mesh
|
||||
* generation (of mesh of higher dimension)
|
||||
*/
|
||||
//================================================================================
|
||||
|
||||
void NETGENPlugin_Mesher::toPython( const netgen::Mesh* ngMesh,
|
||||
const std::string& pyFile)
|
||||
{
|
||||
ofstream outfile(pyFile.c_str(), ios::out);
|
||||
if ( !outfile ) return;
|
||||
|
||||
outfile << "import smesh, SMESH" << endl
|
||||
<< "mesh = smesh.Mesh()" << endl << endl;
|
||||
|
||||
using namespace netgen;
|
||||
PointIndex pi;
|
||||
for (pi = PointIndex::BASE;
|
||||
pi < ngMesh->GetNP()+PointIndex::BASE; pi++)
|
||||
{
|
||||
outfile << "mesh.AddNode( ";
|
||||
outfile << (*ngMesh)[pi](0) << ", ";
|
||||
outfile << (*ngMesh)[pi](1) << ", ";
|
||||
outfile << (*ngMesh)[pi](2) << ")" << endl;
|
||||
}
|
||||
|
||||
int nbDom = ngMesh->GetNDomains();
|
||||
for ( int i = 0; i < nbDom; ++i )
|
||||
outfile<< "grp" << i+1 << " = mesh.CreateEmptyGroup( SMESH.FACE, 'domain"<< i+1 << "')"<< endl;
|
||||
|
||||
SurfaceElementIndex sei;
|
||||
for (sei = 0; sei < ngMesh->GetNSE(); sei++)
|
||||
{
|
||||
outfile << "mesh.AddFace([ ";
|
||||
Element2d sel = (*ngMesh)[sei];
|
||||
for (int j = 0; j < sel.GetNP(); j++)
|
||||
outfile << sel[j] << ( j+1 < sel.GetNP() ? ", " : " ])");
|
||||
outfile << endl;
|
||||
|
||||
if ((*ngMesh)[sei].GetIndex())
|
||||
{
|
||||
if ( int dom1 = ngMesh->GetFaceDescriptor((*ngMesh)[sei].GetIndex ()).DomainIn())
|
||||
outfile << "grp"<< dom1 <<".Add([ " << (int)sei+1 << " ])" << endl;
|
||||
if ( int dom2 = ngMesh->GetFaceDescriptor((*ngMesh)[sei].GetIndex ()).DomainOut())
|
||||
outfile << "grp"<< dom2 <<".Add([ " << (int)sei+1 << " ])" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
for (ElementIndex ei = 0; ei < ngMesh->GetNE(); ei++)
|
||||
{
|
||||
Element el = (*ngMesh)[ei];
|
||||
outfile << "mesh.AddVolume([ ";
|
||||
for (int j = 0; j < el.GetNP(); j++)
|
||||
outfile << el[j] << ( j+1 < el.GetNP() ? ", " : " ])");
|
||||
outfile << endl;
|
||||
}
|
||||
|
||||
for (int i = 1; i <= ngMesh->GetNSeg(); i++)
|
||||
{
|
||||
const Segment & seg = ngMesh->LineSegment (i);
|
||||
outfile << "mesh.AddEdge([ "
|
||||
<< seg[0] << ", "
|
||||
<< seg[1] << " ])" << endl;
|
||||
}
|
||||
cout << "Write " << pyFile << endl;
|
||||
}
|
||||
|
||||
//================================================================================
|
||||
/*!
|
||||
* \brief Constructor of NETGENPlugin_ngMeshInfo
|
||||
|
@ -30,9 +30,11 @@
|
||||
#define _NETGENPlugin_Mesher_HXX_
|
||||
|
||||
#include "NETGENPlugin_Defs.hxx"
|
||||
#include "StdMeshers_FaceSide.hxx"
|
||||
#include "SMDS_MeshElement.hxx"
|
||||
#include "SMESH_Algo.hxx"
|
||||
|
||||
#include <StdMeshers_FaceSide.hxx>
|
||||
#include <SMDS_MeshElement.hxx>
|
||||
#include <SMESH_Algo.hxx>
|
||||
#include <SMESH_ProxyMesh.hxx>
|
||||
|
||||
namespace nglib {
|
||||
#include <nglib.h>
|
||||
@ -103,16 +105,17 @@ class NETGENPLUGIN_EXPORT NETGENPlugin_Mesher
|
||||
static void RestrictLocalSize(netgen::Mesh& ngMesh, const gp_XYZ& p, const double size);
|
||||
|
||||
static int FillSMesh(const netgen::OCCGeometry& occgeom,
|
||||
const netgen::Mesh& ngMesh,
|
||||
netgen::Mesh& ngMesh,
|
||||
const NETGENPlugin_ngMeshInfo& initState,
|
||||
SMESH_Mesh& sMesh,
|
||||
std::vector<const SMDS_MeshNode*>& nodeVec,
|
||||
SMESH_Comment& comment);
|
||||
|
||||
bool fillNgMesh(const netgen::OCCGeometry& occgeom,
|
||||
bool fillNgMesh(netgen::OCCGeometry& occgeom,
|
||||
netgen::Mesh& ngMesh,
|
||||
std::vector<const SMDS_MeshNode*>& nodeVec,
|
||||
const std::list< SMESH_subMesh* > & meshedSM);
|
||||
const std::list< SMESH_subMesh* > & meshedSM,
|
||||
SMESH_ProxyMesh::Ptr proxyMesh=SMESH_ProxyMesh::Ptr());
|
||||
|
||||
static void fixIntFaces(const netgen::OCCGeometry& occgeom,
|
||||
netgen::Mesh& ngMesh,
|
||||
@ -134,6 +137,10 @@ class NETGENPLUGIN_EXPORT NETGENPlugin_Mesher
|
||||
|
||||
static SMESH_ComputeErrorPtr readErrors(const std::vector< const SMDS_MeshNode* >& nodeVec);
|
||||
|
||||
|
||||
static void toPython( const netgen::Mesh* ngMesh,
|
||||
const std::string& pyFile); // debug
|
||||
|
||||
private:
|
||||
SMESH_Mesh* _mesh;
|
||||
const TopoDS_Shape& _shape;
|
||||
|
Loading…
Reference in New Issue
Block a user