
Separating mesh face and proxy mesh for quand adaptors and VL in 3D. Intermedial commit First version of 1D SA. 2D SA version and definition of simpleHypo. Define the NETGENPlugin_NETGEN_1D2D3D_SA class to implement 1D,1D2D,1D2D3D SA version of the mesh. Using NETGENPlugin_NETGEN_2D_SA class to define the 2D SA version. Cleaning code. Toward 2D SA version. Function to feed 1D elements from imported mesh into netgen. 2D SA version for netgen. Finish support for parallel computing of 2D mesh with netgen. Add the NETGEN_2D_Remote. UsIn NETGEN_2D_SA class use bounding box of faces to allow fast discarting edge nodes far from the faces been meshed.
358 lines
13 KiB
C++
358 lines
13 KiB
C++
// Copyright (C) 2007-2023 CEA, EDF, OPEN CASCADE
|
|
//
|
|
// This library is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
// License as published by the Free Software Foundation; either
|
|
// version 2.1 of the License, or (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
//
|
|
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
|
|
//
|
|
|
|
// NETGENPlugin : C++ implementation
|
|
// File : NETGENPlugin_NETGEN_2D3D_SA.cxx
|
|
// Author : Cesar Conopoima (OCC)
|
|
// Date : 01/11/2023
|
|
// Project : SALOME
|
|
//=============================================================================
|
|
//
|
|
|
|
#include "NETGENPlugin_DriverParam.hxx"
|
|
#include "NETGENPlugin_Hypothesis.hxx"
|
|
#include "NETGENPlugin_SimpleHypothesis_3D.hxx"
|
|
|
|
#include "NETGENPlugin_NETGEN_2D.hxx"
|
|
#include "NETGENPlugin_NETGEN_1D2D3D_SA.hxx"
|
|
|
|
#include <SMESHDS_Mesh.hxx>
|
|
#include <SMESH_ControlsDef.hxx>
|
|
#include <SMESH_Gen.hxx>
|
|
#include <SMESH_Mesh.hxx>
|
|
#include <SMESH_MesherHelper.hxx>
|
|
#include <SMESH_DriverShape.hxx>
|
|
#include <SMESH_DriverMesh.hxx>
|
|
#include <utilities.h>
|
|
|
|
#include <list>
|
|
|
|
namespace nglib {
|
|
#include <nglib.h>
|
|
}
|
|
#include <meshing.hpp>
|
|
|
|
using namespace nglib;
|
|
|
|
//=============================================================================
|
|
/*!
|
|
*
|
|
*/
|
|
//=============================================================================
|
|
|
|
NETGENPlugin_NETGEN_1D2D3D_SA::NETGENPlugin_NETGEN_1D2D3D_SA()
|
|
: NETGENPlugin_NETGEN_2D3D(0, new SMESH_Gen())
|
|
{
|
|
_name = "NETGEN_1D2D3D_SA";
|
|
}
|
|
|
|
//=============================================================================
|
|
/*!
|
|
*
|
|
*/
|
|
//=============================================================================
|
|
|
|
NETGENPlugin_NETGEN_1D2D3D_SA::~NETGENPlugin_NETGEN_1D2D3D_SA()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* @brief fill plugin hypothesis from the netgen_params structure
|
|
*
|
|
* @param aParams the structure
|
|
*/
|
|
void NETGENPlugin_NETGEN_1D2D3D_SA::fillHyp(netgen_params aParams)
|
|
{
|
|
if( aParams.myType == hypoType::Hypo )
|
|
{
|
|
NETGENPlugin_Hypothesis * hypParameters = new NETGENPlugin_Hypothesis(0, GetGen());
|
|
|
|
hypParameters->SetMaxSize(aParams.maxh);
|
|
hypParameters->SetMinSize(aParams.minh);
|
|
hypParameters->SetNbSegPerEdge(aParams.segmentsperedge);
|
|
hypParameters->SetGrowthRate(aParams.grading);
|
|
hypParameters->SetNbSegPerRadius(aParams.curvaturesafety);
|
|
hypParameters->SetSecondOrder(aParams.secondorder);
|
|
hypParameters->SetQuadAllowed(aParams.quad);
|
|
hypParameters->SetOptimize(aParams.optimize);
|
|
hypParameters->SetFineness((NETGENPlugin_Hypothesis::Fineness)aParams.fineness);
|
|
hypParameters->SetSurfaceCurvature(aParams.uselocalh);
|
|
hypParameters->SetFuseEdges(aParams.merge_solids);
|
|
hypParameters->SetChordalErrorEnabled(aParams.chordalError);
|
|
if(aParams.optimize){
|
|
hypParameters->SetNbSurfOptSteps(aParams.optsteps2d);
|
|
hypParameters->SetNbVolOptSteps(aParams.optsteps3d);
|
|
}
|
|
hypParameters->SetElemSizeWeight(aParams.elsizeweight);
|
|
hypParameters->SetWorstElemMeasure(aParams.opterrpow);
|
|
hypParameters->SetUseDelauney(aParams.delaunay);
|
|
hypParameters->SetCheckOverlapping(aParams.checkoverlap);
|
|
hypParameters->SetCheckChartBoundary(aParams.checkchartboundary);
|
|
hypParameters->SetMeshSizeFile(aParams.meshsizefilename);
|
|
|
|
_hypothesis = dynamic_cast< const NETGENPlugin_Hypothesis *> (hypParameters);
|
|
}
|
|
else if ( aParams.myType == hypoType::Simple2D )
|
|
{
|
|
NETGENPlugin_SimpleHypothesis_2D * hypParameters = new NETGENPlugin_SimpleHypothesis_2D(0, GetGen());
|
|
|
|
// mandatory to fill in this branch case!
|
|
// Number of segments (int)
|
|
// localLenght (double)
|
|
// maxElement area (double)
|
|
// GetAllowQuadrangles (bool)
|
|
hypParameters->SetNumberOfSegments( aParams.numberOfSegments );
|
|
if ( !aParams.numberOfSegments )
|
|
hypParameters->SetLocalLength( aParams.localLength );
|
|
hypParameters->SetMaxElementArea( aParams.maxElementArea );
|
|
hypParameters->SetAllowQuadrangles( aParams.allowQuadrangles );
|
|
_hypothesis = dynamic_cast< const NETGENPlugin_SimpleHypothesis_2D *> (hypParameters);
|
|
}
|
|
else if ( aParams.myType == hypoType::Simple3D )
|
|
{
|
|
NETGENPlugin_SimpleHypothesis_3D * hypParameters = new NETGENPlugin_SimpleHypothesis_3D(0, GetGen());
|
|
|
|
// mandatory to fill in this branch case!
|
|
// Number of segments (int)
|
|
// localLenght (double)
|
|
// maxElement area (double)
|
|
// maxElement volume (double)
|
|
// GetAllowQuadrangles (bool)
|
|
hypParameters->SetNumberOfSegments( aParams.numberOfSegments );
|
|
if ( !aParams.numberOfSegments )
|
|
hypParameters->SetLocalLength( aParams.localLength );
|
|
hypParameters->SetMaxElementArea( aParams.maxElementArea );
|
|
hypParameters->SetMaxElementVolume( aParams.maxElementVol );
|
|
hypParameters->SetAllowQuadrangles( aParams.allowQuadrangles );
|
|
|
|
_hypothesis = dynamic_cast< const NETGENPlugin_SimpleHypothesis_3D *> (hypParameters);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Write a binary file containing information on the elements/nodes
|
|
* created by the netgen mesher
|
|
*
|
|
* @param nodeVec mapping between the mesh id and the netgen structure id
|
|
* @param ngLib Wrapper on netgen library
|
|
* @param new_element_file Name of the output file
|
|
* @param NumOfPremeshedNodes Number of nodes in the netgen structure
|
|
* @return true if there are some error
|
|
*/
|
|
bool NETGENPlugin_NETGEN_1D2D3D_SA::FillNewElementFile( std::vector< const SMDS_MeshNode* > &nodeVec, NETGENPlugin_NetgenLibWrapper &ngLib,
|
|
std::string new_element_file, const NETGENPlugin_Mesher::DIM dim )
|
|
{
|
|
|
|
// Particularities: As submeshing is not supported nodeVect is empty and NumberOfPremeshedNodes is also zero
|
|
Ng_Mesh* NetgenMesh = ngLib.ngMesh();
|
|
int NetgenNodes = Ng_GetNP(NetgenMesh);
|
|
int NetgenSeg2D = Ng_GetNSeg_2D( NetgenMesh );
|
|
int NetgenFaces = Ng_GetNSE(NetgenMesh);
|
|
int NetgenVols = Ng_GetNE(NetgenMesh);
|
|
int segmentId;
|
|
bool isOK = ( NetgenNodes > 0 && NetgenSeg2D > 0 );
|
|
if ( isOK && !new_element_file.empty() )
|
|
{
|
|
MESSAGE("Writting new elements")
|
|
std::ofstream df(new_element_file, ios::out|ios::binary);
|
|
|
|
double NetgenPoint[3];
|
|
int NetgenSegment[2];
|
|
int NetgenSurface[8];
|
|
int NetgenVolumens[10];
|
|
|
|
// Writing nodevec (correspondence netgen numbering mesh numbering)
|
|
// Number of nodes
|
|
const int NumOfPremeshedNodes = nodeVec.size();
|
|
df.write((char*) &NumOfPremeshedNodes, sizeof(int));
|
|
df.write((char*) &NetgenNodes, sizeof(int));
|
|
|
|
for (int nodeIndex = 1 ; nodeIndex <= NumOfPremeshedNodes; ++nodeIndex )
|
|
{
|
|
//Id of the point
|
|
int id = nodeVec.at(nodeIndex)->GetID();
|
|
df.write((char*) &id, sizeof(int));
|
|
}
|
|
|
|
// Writing all new points
|
|
for (int nodeIndex = NumOfPremeshedNodes + 1; nodeIndex <= NetgenNodes; ++nodeIndex )
|
|
{
|
|
Ng_GetPoint( NetgenMesh, nodeIndex, NetgenPoint );
|
|
// Coordinates of the point
|
|
df.write((char *) &NetgenPoint, sizeof(double)*3);
|
|
}
|
|
|
|
if ( dim >= NETGENPlugin_Mesher::D1 )
|
|
{
|
|
// create segments at boundaries.
|
|
df.write((char*) &NetgenSeg2D, sizeof(int));
|
|
for ( int elemIndex = 1; elemIndex <= NetgenSeg2D; ++elemIndex )
|
|
{
|
|
Ng_GetSegment_2D( NetgenMesh, elemIndex, NetgenSegment, &segmentId );
|
|
df.write((char*) &NetgenSegment, sizeof(int) * 2 );
|
|
}
|
|
}
|
|
if ( dim >= NETGENPlugin_Mesher::D2 )
|
|
{
|
|
// create surface elements.
|
|
df.write((char*) &NetgenFaces, sizeof(int));
|
|
for ( int elemIndex = 1; elemIndex <= NetgenFaces; ++elemIndex )
|
|
{
|
|
nglib::Ng_Surface_Element_Type elemType = Ng_GetSurfaceElement( NetgenMesh, elemIndex, NetgenSurface );
|
|
switch (elemType)
|
|
{
|
|
case nglib::NG_TRIG:
|
|
{
|
|
df.write((char*) &NetgenSurface, sizeof(int) * 3 );
|
|
break;
|
|
}
|
|
case nglib::NG_QUAD:
|
|
{
|
|
df.write((char*) &NetgenSurface, sizeof(int) * 4 );
|
|
break;
|
|
}
|
|
case nglib::NG_TRIG6:
|
|
{
|
|
df.write((char*) &NetgenSurface, sizeof(int) * 6 );
|
|
break;
|
|
}
|
|
case nglib::NG_QUAD8:
|
|
{
|
|
df.write((char*) &NetgenSurface, sizeof(int) * 8 );
|
|
break;
|
|
}
|
|
default:
|
|
{ break; }
|
|
}
|
|
}
|
|
}
|
|
if ( dim >= NETGENPlugin_Mesher::D3 )
|
|
{
|
|
// create volume elements.
|
|
df.write((char*) &NetgenVols, sizeof(int));
|
|
for ( int elemIndex = 1; elemIndex <= NetgenVols; ++elemIndex )
|
|
{
|
|
nglib::Ng_Volume_Element_Type elemType = Ng_GetVolumeElement( NetgenMesh, elemIndex, NetgenVolumens );
|
|
switch (elemType)
|
|
{
|
|
case nglib::NG_TET:
|
|
{
|
|
df.write((char*) &NetgenVolumens, sizeof(int) * 4 );
|
|
break;
|
|
}
|
|
case nglib::NG_PYRAMID:
|
|
{
|
|
df.write((char*) &NetgenVolumens, sizeof(int) * 5 );
|
|
break;
|
|
}
|
|
case nglib::NG_PRISM:
|
|
{
|
|
df.write((char*) &NetgenVolumens, sizeof(int) * 6 );
|
|
break;
|
|
}
|
|
case nglib::NG_TET10:
|
|
{
|
|
df.write((char*) &NetgenVolumens, sizeof(int) * 10 );
|
|
break;
|
|
}
|
|
default:
|
|
{ break; }
|
|
}
|
|
}
|
|
}
|
|
df.close();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @brief Compute the mesh based on the
|
|
*
|
|
* @param aMesh the read Mesh
|
|
* @param aShape the loaded shape
|
|
* @param new_element_file output file containing info the elements created by the mesher
|
|
* @param output_mesh whether or not write the created elements into the mesh
|
|
* @param dim the dimension to be meshed.
|
|
* @return negation of mesh fail: true, false
|
|
*/
|
|
bool NETGENPlugin_NETGEN_1D2D3D_SA::Compute(SMESH_Mesh& aMesh, TopoDS_Shape &aShape, std::string new_element_file, bool output_mesh, NETGENPlugin_Mesher::DIM dim )
|
|
{
|
|
//
|
|
netgen::multithread.terminate = 0;
|
|
NETGENPlugin_Mesher mesher(&aMesh, aShape, /*is3D = */ false );
|
|
mesher.SetParameters(dynamic_cast<const NETGENPlugin_Hypothesis*>(_hypothesis));
|
|
if ( dim == NETGENPlugin_Mesher::D3 )
|
|
mesher.SetParameters(dynamic_cast<const NETGENPlugin_SimpleHypothesis_3D*>(_hypothesis));
|
|
else
|
|
mesher.SetParameters(dynamic_cast<const NETGENPlugin_SimpleHypothesis_2D*>(_hypothesis));
|
|
NETGENPlugin_NetgenLibWrapper ngLib;
|
|
vector< const SMDS_MeshNode* > nodeVec;
|
|
bool err = mesher.Compute( ngLib, nodeVec, output_mesh, dim );
|
|
FillNewElementFile( nodeVec, ngLib, new_element_file, dim );
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* @brief Running the mesher on the given files
|
|
*
|
|
* @param input_mesh_file Mesh file (containing 2D elements)
|
|
* @param shape_file Shape file (BREP or STEP format)
|
|
* @param hypo_file Ascii file containing the netgen parameters
|
|
* @param element_orientation_file Binary file containing the orientation of surface elemnts
|
|
* @param new_element_file output file containing info the elements created by the mesher
|
|
* @param output_mesh_file output mesh file (if empty it will not be created)
|
|
* @return negation of mesh fail: true, false
|
|
*/
|
|
int NETGENPlugin_NETGEN_1D2D3D_SA::run(const std::string input_mesh_file,
|
|
const std::string shape_file,
|
|
const std::string hypo_file,
|
|
const std::string element_orientation_file,
|
|
const std::string new_element_file,
|
|
const std::string output_mesh_file,
|
|
const NETGENPlugin_Mesher::DIM dim )
|
|
{
|
|
|
|
// _element_orientation_file = element_orientation_file;
|
|
|
|
std::unique_ptr<SMESH_Mesh> myMesh(_gen->CreateMesh(false));
|
|
|
|
// Importing mesh
|
|
SMESH_DriverMesh::importMesh(input_mesh_file, *myMesh);
|
|
// Importing shape
|
|
TopoDS_Shape myShape;
|
|
SMESH_DriverShape::importShape(shape_file, myShape);
|
|
// Importing hypothesis
|
|
netgen_params myParams;
|
|
importNetgenParams(hypo_file, myParams);
|
|
fillHyp(myParams);
|
|
|
|
int ret = Compute( *myMesh, myShape, new_element_file, !output_mesh_file.empty(), dim );
|
|
if(ret){
|
|
std::cerr << "Meshing failed" << std::endl;
|
|
return ret;
|
|
}
|
|
|
|
if(!output_mesh_file.empty()){
|
|
std::string meshName = "MESH";
|
|
SMESH_DriverMesh::exportMesh(output_mesh_file, *myMesh, meshName);
|
|
}
|
|
|
|
return ret;
|
|
}
|