bos #17015 [CEA 17008] Body fitting with Viscous Layers for CFD meshing

fix for inlet/outlet

Fix for negative volumes due to merge

increase tolerance for search of equal intersection points

Remove old tol2 declaration
This commit is contained in:
eap 2022-06-17 14:23:44 +03:00 committed by Christophe Bourcier
parent a53a9fc74d
commit c9294ee688
17 changed files with 1411 additions and 40 deletions

View File

@ -7,7 +7,9 @@ Body Fitting 3D meshing algorithm
Body Fitting algorithm generates hexahedrons of a Cartesian grid in
the internal part of geometry and polyhedrons and other types of
elements at the intersection of Cartesian cells with the geometrical
boundary.
boundary. The algorithm supports construction of
:ref:`viscous boundary layers<cartesian_VL_anchor>` (use
:ref:`Viscous Layers hypothesis <viscous_layers_anchor>` to define them).
.. image:: ../images/cartesian3D_sphere.png
:align: center
@ -15,8 +17,6 @@ boundary.
.. centered::
A sphere meshed by Body Fitting algorithm
.. note:: The algorithm creates only 3D elements. To add 2D elements use :ref:`Generate boundary elements <make_2dmesh_from_3d_page>` operation.
The meshing algorithm is as follows.
#. Lines of a Cartesian structured grid defined by :ref:`Body Fitting Parameters <cartesian_hyp_anchor>` hypothesis are intersected with the geometry boundary, thus nodes lying on the boundary are found. This step also allows finding out for each node of the Cartesian grid if it is inside or outside the geometry.
@ -27,7 +27,17 @@ The meshing algorithm is as follows.
* add a hexahedron in the mesh, if all nodes are inside
* add a polyhedron or another cell type in the mesh, if some nodes are inside and some outside.
To apply this algorithm when you define your mesh, select **Body Fitting** in the list of 3D algorithms and add **Body Fitting Parameters** hypothesis. The following dialog will appear:
.. _cartesian_VL_anchor:
**Viscous boundary layers** are constructed as follows:
* create an offset geometry with offset value equal to full layers thickness by using BRepOffset_MakeOffset OCCT class;
* mesh the offset geometry with the Body Fitting algorithm;
* create prisms of the layers by projecting boundary nodes of offset geometry onto the boundary of initial geometry.
.. note:: Viscous layers can't be constructed on geometry with **shared/internal** faces.
To apply the algorithm when you define your mesh, select **Body Fitting** in the list of 3D algorithms and add **Body Fitting Parameters** hypothesis. The following dialog will appear:
.. _cartesian_hyp_anchor:

View File

@ -555,12 +555,14 @@
group-id ="0"
priority ="20"
hypos ="CartesianParameters3D"
opt-hypos ="ViscousLayers"
support-submeshes="false"
output ="HEXA"
need-hyp ="true"
dim ="3">
<python-wrap>
<algo>Cartesian_3D=BodyFitted()</algo>
<hypo>ViscousLayers=ViscousLayers(SetTotalThickness(),SetNumberLayers(),SetStretchFactor(),SetFaces(1),SetFaces(2),SetMethod(),SetGroupName())</hypo>
</python-wrap>
</algorithm>

View File

@ -45,6 +45,13 @@ SMDS_LinearEdge::SMDS_LinearEdge(const SMDS_MeshNode * node1,
myNodes[1] = node2;
}
void SMDS_LinearEdge::Init(const SMDS_MeshNode * node1,
const SMDS_MeshNode * node2)
{
myNodes[0] = node1;
myNodes[1] = node2;
}
int SMDS_LinearEdge::NbNodes() const
{
return 2;

View File

@ -32,7 +32,8 @@
class SMDS_EXPORT SMDS_LinearEdge: public SMDS_CellOfNodes
{
public:
SMDS_LinearEdge(const SMDS_MeshNode * node1, const SMDS_MeshNode * node2);
SMDS_LinearEdge(const SMDS_MeshNode * node1=nullptr, const SMDS_MeshNode * node2=nullptr);
void Init( const SMDS_MeshNode * node1, const SMDS_MeshNode * node2);
virtual SMDSAbs_ElementType GetType() const { return SMDSAbs_Edge; }
virtual SMDSAbs_GeometryType GetGeomType() const { return SMDSGeom_EDGE; }

View File

@ -7279,6 +7279,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes,
{
const SMDS_MeshElement* elem = *eIt;
SMESHDS_SubMesh* sm = mesh->MeshElements( elem->getshapeId() );
bool marked = elem->isMarked();
bool keepElem = applyMerge( elem, newElemDefs, nodeNodeMap, /*noHoles=*/false );
if ( !keepElem )
@ -7315,6 +7316,8 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes,
sm->AddElement( newElem );
if ( elem != newElem )
ReplaceElemInGroups( elem, newElem, mesh );
if ( marked && newElem )
newElem->setIsMarked( true );
}
}
}

View File

@ -1161,6 +1161,18 @@ void SMESHDS_Mesh::UnSetNodeOnShape(const SMDS_MeshNode* aNode)
sm->RemoveNode(aNode);
}
//=======================================================================
//function : UnSetElementOnShape
//purpose :
//=======================================================================
void SMESHDS_Mesh::UnSetElementOnShape(const SMDS_MeshElement * anElement)
{
int shapeId = anElement->getshapeId();
if (shapeId > 0)
if ( SMESHDS_SubMesh* sm = MeshElements( shapeId ))
sm->RemoveElement(anElement);
}
//=======================================================================
//function : SetMeshElementOnShape
//purpose :

View File

@ -609,6 +609,7 @@ class SMESHDS_EXPORT SMESHDS_Mesh : public SMDS_Mesh
void SetNodeOnEdge (const SMDS_MeshNode * aNode, const TopoDS_Edge& S, double u=0.);
void SetNodeOnVertex(const SMDS_MeshNode * aNode, const TopoDS_Vertex & S);
void UnSetNodeOnShape(const SMDS_MeshNode * aNode);
void UnSetElementOnShape(const SMDS_MeshElement * anElt);
void SetMeshElementOnShape (const SMDS_MeshElement * anElt, const TopoDS_Shape & S);
void UnSetMeshElementOnShape(const SMDS_MeshElement * anElt, const TopoDS_Shape & S);
void SetNodeInVolume(const SMDS_MeshNode * aNode, int Index);

View File

@ -253,6 +253,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
void init(const SMDS_MeshElement* elem, double tolerance);
};
std::vector< ElementBox* > _elements;
//std::string _name;
typedef ObjectPool< ElementBox > TElementBoxPool;
@ -340,6 +341,15 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
if ( child->isLeaf() && child->_elements.capacity() > child->_elements.size() )
SMESHUtils::CompactVector( child->_elements );
// child->_name = _name + char('0' + j);
// if ( child->isLeaf() && child->_elements.size() )
// {
// cout << child->_name << " ";
// for ( size_t i = 0; i < child->_elements.size(); ++i )
// cout << child->_elements[i]->_element->GetID() << " ";
// cout << endl;
// }
}
}
@ -2564,3 +2574,111 @@ SMESH_ElementSearcher* SMESH_MeshAlgos::GetElementSearcher(SMDS_Mesh&
{
return new SMESH_ElementSearcherImpl( mesh, tolerance, elemIt );
}
//================================================================================
/*!
* \brief Intersect a ray with a convex volume
* \param [in] ray - the ray
* \param [in] rayLen - ray length
* \param [in] vol - the volume
* \param [out] tMin - return a ray parameter where the ray enters the volume
* \param [out] tMax - return a ray parameter where the ray exit the volume
* \param [out] iFacetMin - facet index where the ray enters the volume
* \param [out] iFacetMax - facet index where the ray exit the volume
* \return bool - true if the ray intersects the volume
*/
//================================================================================
bool SMESH_MeshAlgos::IntersectRayVolume( const gp_Ax1& ray,
const double rayLen,
const SMDS_MeshElement* vol,
double & tMin,
double & tMax,
int & iFacetMin,
int & iFacetMax)
{
/* Ray-Convex Polyhedron Intersection Test by Eric Haines, erich@eye.com
*
* This test checks the ray against each face of a polyhedron, checking whether
* the set of intersection points found for each ray-plane intersection
* overlaps the previous intersection results. If there is no overlap (i.e.
* no line segment along the ray that is inside the polyhedron), then the
* ray misses and returns false; else true.
*/
SMDS_VolumeTool vTool;
if ( !vTool.Set( vol ))
return false;
tMin = -Precision::Infinite() ;
tMax = rayLen ;
/* Test each plane in polyhedron */
for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
{
const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
gp_XYZ normal;
vTool.GetFaceNormal( iF,
normal.ChangeCoord(1),
normal.ChangeCoord(2),
normal.ChangeCoord(3) );
double D = - ( normal * SMESH_NodeXYZ( fNodes[0] ));
/* Compute intersection point T and sidedness */
double vd = ray.Direction().XYZ() * normal;
double vn = ray.Location().XYZ() * normal + D;
if ( vd == 0.0 ) {
/* ray is parallel to plane - check if ray origin is inside plane's
half-space */
if ( vn > 0.0 )
/* ray origin is outside half-space */
return false;
}
else
{
/* ray not parallel - get distance to plane */
double t = -vn / vd ;
if ( vd < 0.0 )
{
/* front face - T is a near point */
if ( t > tMax ) return false;
if ( t > tMin ) {
/* hit near face */
tMin = t ;
iFacetMin = iF;
}
}
else
{
/* back face - T is a far point */
if ( t < tMin ) return false;
if ( t < tMax ) {
/* hit far face */
tMax = t ;
iFacetMax = iF;
}
}
}
}
/* survived all tests */
/* Note: if ray originates on polyhedron, may want to change 0.0 to some
* epsilon to avoid intersecting the originating face.
*/
if ( tMin >= 0.0 ) {
/* outside, hitting front face */
return true;
}
else
{
if ( tMax < rayLen ) {
/* inside, hitting back face */
return true;
}
else
{
/* inside, but back face beyond tmax */
return false;
}
}
}

View File

@ -168,6 +168,13 @@ namespace SMESH_MeshAlgos
const gp_XY& t0, const gp_XY& t1, const gp_XY& t2,
double & bc0, double & bc1);
/*!
* \brief Intersect volume by a ray
*/
bool IntersectRayVolume( const gp_Ax1& ray, const double rayLen,
const SMDS_MeshElement* vol,
double & tMin, double & tMax,
int & iFacetMin, int & iFacetMax);
/*!
* Return a face having linked nodes n1 and n2 and which is
* - not in avoidSet,

View File

@ -202,6 +202,7 @@ struct SMESH_TNodeXYZ : public gp_XYZ
}
return false;
}
void SetXYZ( const gp_XYZ& p ) { SetCoord( p.X(), p.Y(), p.Z() ); }
const SMDS_MeshNode* Node() const { return _node; }
double Distance(const SMDS_MeshNode* n) const { return (SMESH_TNodeXYZ( n )-*this).Modulus(); }
double SquareDistance(const SMDS_MeshNode* n) const { return (SMESH_TNodeXYZ( n )-*this).SquareModulus(); }

View File

@ -120,6 +120,7 @@ SET(StdMeshers_HEADERS
StdMeshers_Projection_1D2D.hxx
StdMeshers_CartesianParameters3D.hxx
StdMeshers_Cartesian_3D.hxx
StdMeshers_Cartesian_VL.hxx
StdMeshers_QuadFromMedialAxis_1D2D.hxx
StdMeshers_PolygonPerFace_2D.hxx
StdMeshers_PolyhedronPerSolid_3D.hxx
@ -183,6 +184,7 @@ SET(StdMeshers_SOURCES
StdMeshers_Projection_1D2D.cxx
StdMeshers_CartesianParameters3D.cxx
StdMeshers_Cartesian_3D.cxx
StdMeshers_Cartesian_VL.cxx
StdMeshers_Adaptive1D.cxx
StdMeshers_QuadFromMedialAxis_1D2D.cxx
StdMeshers_PolygonPerFace_2D.cxx

View File

@ -24,21 +24,25 @@
//
#include "StdMeshers_Cartesian_3D.hxx"
#include "StdMeshers_CartesianParameters3D.hxx"
#include "ObjectPool.hxx"
#include "SMDS_MeshNode.hxx"
#include "SMDS_VolumeTool.hxx"
#include "SMESHDS_Mesh.hxx"
#include "SMESH_Block.hxx"
#include "SMESH_Comment.hxx"
#include "SMESH_ControlsDef.hxx"
#include "SMESH_Mesh.hxx"
#include "SMESH_MeshAlgos.hxx"
#include "SMESH_MeshEditor.hxx"
#include "SMESH_MesherHelper.hxx"
#include "SMESH_subMesh.hxx"
#include "SMESH_subMeshEventListener.hxx"
#include "StdMeshers_Cartesian_VL.hxx"
#include "StdMeshers_FaceSide.hxx"
#include "StdMeshers_ViscousLayers.hxx"
#include <ObjectPool.hxx>
#include <SMDS_LinearEdge.hxx>
#include <SMDS_MeshNode.hxx>
#include <SMDS_VolumeOfNodes.hxx>
#include <SMDS_VolumeTool.hxx>
#include <SMESHDS_Mesh.hxx>
#include <SMESH_Block.hxx>
#include <SMESH_Comment.hxx>
#include <SMESH_ControlsDef.hxx>
#include <SMESH_Mesh.hxx>
#include <SMESH_MeshAlgos.hxx>
#include <SMESH_MeshEditor.hxx>
#include <SMESH_MesherHelper.hxx>
#include <SMESH_subMesh.hxx>
#include <SMESH_subMeshEventListener.hxx>
#include <utilities.h>
#include <Utils_ExceptHandlers.hxx>
@ -130,7 +134,8 @@ StdMeshers_Cartesian_3D::StdMeshers_Cartesian_3D(int hypId, SMESH_Gen * gen)
{
_name = "Cartesian_3D";
_shapeType = (1 << TopAbs_SOLID); // 1 bit /shape type
_compatibleHypothesis.push_back("CartesianParameters3D");
_compatibleHypothesis.push_back( "CartesianParameters3D" );
_compatibleHypothesis.push_back( StdMeshers_ViscousLayers::GetHypType() );
_onlyUnaryInput = false; // to mesh all SOLIDs at once
_requireDiscreteBoundary = false; // 2D mesh not needed
@ -149,19 +154,26 @@ bool StdMeshers_Cartesian_3D::CheckHypothesis (SMESH_Mesh& aMesh,
{
aStatus = SMESH_Hypothesis::HYP_MISSING;
const list<const SMESHDS_Hypothesis*>& hyps = GetUsedHypothesis(aMesh, aShape);
const list<const SMESHDS_Hypothesis*>& hyps = GetUsedHypothesis(aMesh, aShape, /*skipAux=*/false);
list <const SMESHDS_Hypothesis* >::const_iterator h = hyps.begin();
if ( h == hyps.end())
{
return false;
}
_hyp = nullptr;
_hypViscousLayers = nullptr;
_isComputeOffset = false;
for ( ; h != hyps.end(); ++h )
{
if (( _hyp = dynamic_cast<const StdMeshers_CartesianParameters3D*>( *h )))
if ( !_hyp && ( _hyp = dynamic_cast<const StdMeshers_CartesianParameters3D*>( *h )))
{
aStatus = _hyp->IsDefined() ? HYP_OK : HYP_BAD_PARAMETER;
break;
}
else
{
_hypViscousLayers = dynamic_cast<const StdMeshers_ViscousLayers*>( *h );
}
}
@ -171,6 +183,8 @@ bool StdMeshers_Cartesian_3D::CheckHypothesis (SMESH_Mesh& aMesh,
namespace
{
typedef int TGeomID; // IDs of sub-shapes
typedef TopTools_ShapeMapHasher TShapeHasher; // non-oriented shape hasher
typedef std::array< int, 3 > TIJK;
const TGeomID theUndefID = 1e+9;
@ -408,6 +422,11 @@ namespace
{
_curInd[0] = i; _curInd[1] = j; _curInd[2] = k;
}
void SetLineIndex(size_t i)
{
_curInd[_iVar2] = i / _size[_iVar1];
_curInd[_iVar1] = i % _size[_iVar1];
}
void operator++()
{
if ( ++_curInd[_iVar1] == _size[_iVar1] )
@ -419,8 +438,10 @@ namespace
size_t LineIndex01 () const { return _curInd[_iVar1] + (_curInd[_iVar2] + 1 )* _size[_iVar1]; }
size_t LineIndex11 () const { return (_curInd[_iVar1] + 1 ) + (_curInd[_iVar2] + 1 )* _size[_iVar1]; }
void SetIndexOnLine (size_t i) { _curInd[ _iConst ] = i; }
bool IsValidIndexOnLine (size_t i) const { return i < _size[ _iConst ]; }
size_t NbLines() const { return _size[_iVar1] * _size[_iVar2]; }
};
struct FaceGridIntersector;
// --------------------------------------------------------------------------
/*!
* \brief Container of GridLine's
@ -460,11 +481,16 @@ namespace
{
return i + j*_coords[0].size() + k*_coords[0].size()*_coords[1].size();
}
size_t NodeIndex( const TIJK& ijk ) const
{
return NodeIndex( ijk[0], ijk[1], ijk[2] );
}
size_t NodeIndexDX() const { return 1; }
size_t NodeIndexDY() const { return _coords[0].size(); }
size_t NodeIndexDZ() const { return _coords[0].size() * _coords[1].size(); }
LineIndexer GetLineIndexer(size_t iDir) const;
size_t GetLineDir( const GridLine* line, size_t & index ) const;
E_IntersectPoint* Add( const E_IntersectPoint& ip )
{
@ -1355,6 +1381,20 @@ namespace
s[indices[iDir*3]], s[indices[iDir*3+1]], s[indices[iDir*3+2]]);
return li;
}
//================================================================================
/*
* Return direction [0,1,2] of a GridLine
*/
size_t Grid::GetLineDir( const GridLine* line, size_t & index ) const
{
for ( size_t iDir = 0; iDir < 3; ++iDir )
if ( &_lines[ iDir ][0] <= line && line <= &_lines[ iDir ].back() )
{
index = line - &_lines[ iDir ][0];
return iDir;
}
return -1;
}
//=============================================================================
/*
* Creates GridLine's of the grid
@ -1980,6 +2020,8 @@ namespace
}
}
#endif
return;
}
//=============================================================================
@ -2634,7 +2676,7 @@ namespace
if ( _nbFaceIntNodes + _eIntPoints.size() > 0 &&
_nbFaceIntNodes + _eIntPoints.size() + _nbCornerNodes > 3)
{
_intNodes.reserve( 3 * _nbBndNodes + _nbFaceIntNodes + _eIntPoints.size() );
_intNodes.reserve( 3 * ( _nbBndNodes + _nbFaceIntNodes + _eIntPoints.size() ));
// this method can be called in parallel, so use own helper
SMESH_MesherHelper helper( *_grid->_helper->GetMesh() );
@ -2706,7 +2748,7 @@ namespace
// 1) add this->_eIntPoints to _Face::_eIntNodes
// 2) fill _intNodes and _vIntNodes
//
const double tol2 = _grid->_tol * _grid->_tol;
const double tol2 = _grid->_tol * _grid->_tol * 4;
int facets[3], nbFacets, subEntity;
for ( int iF = 0; iF < 6; ++iF )
@ -6352,6 +6394,27 @@ namespace
bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh & theMesh,
const TopoDS_Shape & theShape)
{
if ( _hypViscousLayers )
{
const StdMeshers_ViscousLayers* hypViscousLayers = _hypViscousLayers;
_hypViscousLayers = nullptr;
StdMeshers_Cartesian_VL::ViscousBuilder builder( hypViscousLayers, theMesh, theShape );
std::string error;
TopoDS_Shape offsetShape = builder.MakeOffsetShape( theShape, theMesh, error );
if ( offsetShape.IsNull() )
throw SALOME_Exception( error );
SMESH_Mesh* offsetMesh = builder.MakeOffsetMesh();
this->_isComputeOffset = true;
if ( ! this->Compute( *offsetMesh, offsetShape ))
return false;
return builder.MakeViscousLayers( theMesh, theShape );
}
// The algorithm generates the mesh in following steps:
// 1) Intersection of grid lines with the geometry boundary.
@ -6379,6 +6442,11 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh & theMesh,
grid._toConsiderInternalFaces = _hyp->GetToConsiderInternalFaces();
grid._toUseThresholdForInternalFaces = _hyp->GetToUseThresholdForInternalFaces();
grid._sizeThreshold = _hyp->GetSizeThreshold();
if ( _isComputeOffset )
{
grid._toAddEdges = true;
grid._toCreateFaces = true;
}
grid.InitGeometry( theShape );
vector< TopoDS_Shape > faceVec;

View File

@ -37,8 +37,10 @@
* Issue 0021336
* Issue #16523: Treatment of internal faces
* Issue #17237: Body fitting on sub-mesh
* Issue #17015: Body fitting with Viscous Layers
*/
class StdMeshers_CartesianParameters3D;
class StdMeshers_ViscousLayers;
class STDMESHERS_EXPORT StdMeshers_Cartesian_3D : public SMESH_3D_Algo
{
@ -61,6 +63,8 @@ public:
void setSubmeshesComputed(SMESH_Mesh& aMesh, const TopoDS_Shape& theShape );
const StdMeshers_CartesianParameters3D* _hyp;
const StdMeshers_ViscousLayers* _hypViscousLayers;
bool _isComputeOffset;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,70 @@
// Copyright (C) 2007-2021 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
//
// 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
//
// File : StdMeshers_Cartesian_VL.hxx
// Created : Tue May 24 12:32:01 2022
// Author : Edward AGAPOV (eap)
#ifndef __StdMeshers_Cartesian_VL_HXX__
#define __StdMeshers_Cartesian_VL_HXX__
#include <BRepOffset_MakeOffset.hxx>
#include <set>
#include <map>
#include <vector>
class StdMeshers_ViscousLayers;
class SMESH_Mesh;
namespace StdMeshers_Cartesian_VL
{
class ViscousBuilder
{
public:
ViscousBuilder( const StdMeshers_ViscousLayers* hypViscousLayers,
const SMESH_Mesh & theMesh,
const TopoDS_Shape & theShape);
~ViscousBuilder();
TopoDS_Shape MakeOffsetShape(const TopoDS_Shape & theShape,
SMESH_Mesh & theMesh,
std::string & theError );
SMESH_Mesh* MakeOffsetMesh();
bool MakeViscousLayers( SMESH_Mesh & theMesh,
const TopoDS_Shape & theShape );
private:
TopoDS_Shape getOffsetSubShape( const TopoDS_Shape& S );
const StdMeshers_ViscousLayers* _hyp;
BRepOffset_MakeOffset _makeOffset;
SMESH_Mesh* _offsetMesh;
TopoDS_Shape _offsetShape;
std::set< int > _shapesWVL; // shapes with viscous layers
std::map< int, std::vector< int > > _edge2facesWOVL; // EDGE 2 FACEs w/o VL
};
}
#endif

View File

@ -642,13 +642,7 @@ namespace VISCOUS_3D
const double T = ( realThickness > 0 ) ? realThickness : GetTotalThickness();
const double f = GetStretchFactor();
const int N = GetNumberLayers();
const double fPowN = pow( f, N );
double h0;
if ( fPowN - 1 <= numeric_limits<double>::min() )
h0 = T / N;
else
h0 = T * ( f - 1 )/( fPowN - 1 );
return h0;
return StdMeshers_ViscousLayers::Get1stLayerThickness( T, f, N );
}
bool UseSurfaceNormal() const
@ -1452,7 +1446,17 @@ bool StdMeshers_ViscousLayers::IsShapeWithLayers(int shapeIndex) const
( std::find( _shapeIds.begin(), _shapeIds.end(), shapeIndex ) != _shapeIds.end() );
return IsToIgnoreShapes() ? !isIn : isIn;
}
// --------------------------------------------------------------------------------
double StdMeshers_ViscousLayers::Get1stLayerThickness( double T, double f, int N )
{
const double fPowN = pow( f, N );
double h0;
if ( fPowN - 1 <= numeric_limits<double>::min() )
h0 = T / N;
else
h0 = T * ( f - 1 )/( fPowN - 1 );
return h0;
}
// --------------------------------------------------------------------------------
SMDS_MeshGroup* StdMeshers_ViscousLayers::CreateGroup( const std::string& theName,
SMESH_Mesh& theMesh,

View File

@ -94,6 +94,11 @@ public:
const TopoDS_Shape& aShape,
SMESH_Hypothesis::Hypothesis_Status& aStatus);
// Compute thickness of the 1st layer
static double Get1stLayerThickness( double thickTotal,
double factor,
int nbLayers );
// Checks if viscous layers should be constructed on a shape
bool IsShapeWithLayers(int shapeIndex) const;