Merge pull request #15624 from marioalexis84/fem-mesh_shape_object

Fem: Improve FemMeshShape objects
This commit is contained in:
Chris Hennes
2024-07-29 11:13:43 -05:00
committed by GitHub
70 changed files with 505 additions and 548 deletions

View File

@@ -161,6 +161,8 @@ PyMOD_INIT_FUNC(Fem)
Fem::FemMesh ::init();
Fem::FemMeshObject ::init();
Fem::FemMeshObjectPython ::init();
Fem::FemMeshShapeBaseObject ::init();
Fem::FemMeshShapeBaseObjectPython ::init();
Fem::FemMeshShapeObject ::init();
Fem::FemMeshShapeNetgenObject ::init();
Fem::PropertyFemMesh ::init();

View File

@@ -82,39 +82,35 @@ using namespace Fem;
using namespace Base;
using namespace boost;
#if SMESH_VERSION_MAJOR < 9
static int StatCount = 0;
#endif
SMESH_Gen* FemMesh::_mesh_gen = nullptr;
TYPESYSTEM_SOURCE(Fem::FemMesh, Base::Persistence)
FemMesh::FemMesh()
: myMesh(nullptr)
, myStudyId(0)
{
// Base::Console().Log("FemMesh::FemMesh():%p (id=%i)\n",this,StatCount);
// create a mesh always with new StudyId to avoid overlapping destruction
#if SMESH_VERSION_MAJOR >= 9
myMesh = getGenerator()->CreateMesh(false);
#else
myMesh = getGenerator()->CreateMesh(StatCount++, false);
myMesh = getGenerator()->CreateMesh(myStudyId, false);
#endif
}
FemMesh::FemMesh(const FemMesh& mesh)
: myMesh(nullptr)
, myStudyId(0)
{
#if SMESH_VERSION_MAJOR >= 9
myMesh = getGenerator()->CreateMesh(false);
#else
myMesh = getGenerator()->CreateMesh(StatCount++, false);
myMesh = getGenerator()->CreateMesh(myStudyId, false);
#endif
copyMeshData(mesh);
}
FemMesh::~FemMesh()
{
// Base::Console().Log("FemMesh::~FemMesh():%p\n",this);
try {
TopoDS_Shape aNull;
myMesh->ShapeToMesh(aNull);
@@ -132,7 +128,7 @@ FemMesh& FemMesh::operator=(const FemMesh& mesh)
#if SMESH_VERSION_MAJOR >= 9
myMesh = getGenerator()->CreateMesh(true);
#else
myMesh = getGenerator()->CreateMesh(0, true);
myMesh = getGenerator()->CreateMesh(myStudyId, true);
#endif
copyMeshData(mesh);
}
@@ -537,75 +533,41 @@ void FemMesh::addHypothesis(const TopoDS_Shape& aSubShape, SMESH_HypothesisPtr h
void FemMesh::setStandardHypotheses()
{
if (!hypoth.empty()) {
TopoDS_Shape shape = getSMesh()->GetShapeToMesh();
if (shape.IsNull()) {
return;
}
#if SMESH_VERSION_MAJOR >= 9
int hyp = 0;
SMESH_HypothesisPtr len(new StdMeshers_MaxLength(hyp++, getGenerator()));
auto len = createHypothesis<StdMeshers_MaxLength>(hyp++);
static_cast<StdMeshers_MaxLength*>(len.get())->SetLength(1.0);
hypoth.push_back(len);
addHypothesis(shape, len);
SMESH_HypothesisPtr loc(new StdMeshers_LocalLength(hyp++, getGenerator()));
auto loc = createHypothesis<StdMeshers_LocalLength>(hyp++);
static_cast<StdMeshers_LocalLength*>(loc.get())->SetLength(1.0);
hypoth.push_back(loc);
addHypothesis(shape, loc);
SMESH_HypothesisPtr area(new StdMeshers_MaxElementArea(hyp++, getGenerator()));
auto area = createHypothesis<StdMeshers_MaxElementArea>(hyp++);
static_cast<StdMeshers_MaxElementArea*>(area.get())->SetMaxArea(1.0);
hypoth.push_back(area);
addHypothesis(shape, area);
SMESH_HypothesisPtr segm(new StdMeshers_NumberOfSegments(hyp++, getGenerator()));
auto segm = createHypothesis<StdMeshers_NumberOfSegments>(hyp++);
static_cast<StdMeshers_NumberOfSegments*>(segm.get())->SetNumberOfSegments(1);
hypoth.push_back(segm);
addHypothesis(shape, segm);
SMESH_HypothesisPtr defl(new StdMeshers_Deflection1D(hyp++, getGenerator()));
auto defl = createHypothesis<StdMeshers_Deflection1D>(hyp++);
static_cast<StdMeshers_Deflection1D*>(defl.get())->SetDeflection(0.01);
hypoth.push_back(defl);
addHypothesis(shape, defl);
SMESH_HypothesisPtr reg(new StdMeshers_Regular_1D(hyp++, getGenerator()));
hypoth.push_back(reg);
auto reg = createHypothesis<StdMeshers_Regular_1D>(hyp++);
addHypothesis(shape, reg);
SMESH_HypothesisPtr qdp(new StdMeshers_QuadranglePreference(hyp++, getGenerator()));
hypoth.push_back(qdp);
auto qdp = createHypothesis<StdMeshers_QuadranglePreference>(hyp++);
addHypothesis(shape, qdp);
SMESH_HypothesisPtr q2d(new StdMeshers_Quadrangle_2D(hyp++, getGenerator()));
hypoth.push_back(q2d);
#else
int hyp = 0;
SMESH_HypothesisPtr len(new StdMeshers_MaxLength(hyp++, 1, getGenerator()));
static_cast<StdMeshers_MaxLength*>(len.get())->SetLength(1.0);
hypoth.push_back(len);
SMESH_HypothesisPtr loc(new StdMeshers_LocalLength(hyp++, 1, getGenerator()));
static_cast<StdMeshers_LocalLength*>(loc.get())->SetLength(1.0);
hypoth.push_back(loc);
SMESH_HypothesisPtr area(new StdMeshers_MaxElementArea(hyp++, 1, getGenerator()));
static_cast<StdMeshers_MaxElementArea*>(area.get())->SetMaxArea(1.0);
hypoth.push_back(area);
SMESH_HypothesisPtr segm(new StdMeshers_NumberOfSegments(hyp++, 1, getGenerator()));
static_cast<StdMeshers_NumberOfSegments*>(segm.get())->SetNumberOfSegments(1);
hypoth.push_back(segm);
SMESH_HypothesisPtr defl(new StdMeshers_Deflection1D(hyp++, 1, getGenerator()));
static_cast<StdMeshers_Deflection1D*>(defl.get())->SetDeflection(0.01);
hypoth.push_back(defl);
SMESH_HypothesisPtr reg(new StdMeshers_Regular_1D(hyp++, 1, getGenerator()));
hypoth.push_back(reg);
SMESH_HypothesisPtr qdp(new StdMeshers_QuadranglePreference(hyp++, 1, getGenerator()));
hypoth.push_back(qdp);
SMESH_HypothesisPtr q2d(new StdMeshers_Quadrangle_2D(hyp++, 1, getGenerator()));
hypoth.push_back(q2d);
#endif
// Apply hypothesis
for (int i = 0; i < hyp; i++) {
myMesh->AddHypothesis(myMesh->GetShapeToMesh(), i);
}
auto q2d = createHypothesis<StdMeshers_Quadrangle_2D>(hyp++);
addHypothesis(shape, q2d);
}
void FemMesh::compute()

View File

@@ -95,6 +95,9 @@ public:
static SMESH_Gen* getGenerator();
void addHypothesis(const TopoDS_Shape& aSubShape, SMESH_HypothesisPtr hyp);
void setStandardHypotheses();
template<typename T>
SMESH_HypothesisPtr createHypothesis(int hypId);
void compute();
// from base class
@@ -220,11 +223,26 @@ private:
/// positioning matrix
Base::Matrix4D _Mtrx;
SMESH_Mesh* myMesh;
const int myStudyId;
std::list<SMESH_HypothesisPtr> hypoth;
static SMESH_Gen* _mesh_gen;
};
template<typename T>
inline SMESH_HypothesisPtr FemMesh::createHypothesis(int hypId)
{
SMESH_Gen* myGen = getGenerator();
#if SMESH_VERSION_MAJOR >= 9
SMESH_HypothesisPtr hypo(new T(hypId, myGen));
#else
// use own StudyContextStruct
SMESH_HypothesisPtr hypo(new T(hypId, myStudyId, myGen));
#endif
return hypo;
}
} // namespace Fem

View File

@@ -45,7 +45,7 @@
using namespace Fem;
using namespace App;
PROPERTY_SOURCE(Fem::FemMeshShapeNetgenObject, Fem::FemMeshShapeObject)
PROPERTY_SOURCE(Fem::FemMeshShapeNetgenObject, Fem::FemMeshShapeBaseObject)
const char* FinenessEnums[] =
{"VeryCoarse", "Coarse", "Moderate", "Fine", "VeryFine", "UserDefined", nullptr};
@@ -93,7 +93,7 @@ App::DocumentObjectExecReturn* FemMeshShapeNetgenObject::execute()
#if SMESH_VERSION_MAJOR >= 9
NETGENPlugin_Hypothesis* tet = new NETGENPlugin_Hypothesis(0, newMesh.getGenerator());
#else
NETGENPlugin_Hypothesis* tet = new NETGENPlugin_Hypothesis(0, 1, newMesh.getGenerator());
NETGENPlugin_Hypothesis* tet = new NETGENPlugin_Hypothesis(0, 0, newMesh.getGenerator());
#endif
tet->SetMaxSize(MaxSize.getValue());
tet->SetMinSize(MinSize.getValue());

View File

@@ -29,7 +29,7 @@
namespace Fem
{
class FemExport FemMeshShapeNetgenObject: public FemMeshShapeObject
class FemExport FemMeshShapeNetgenObject: public FemMeshShapeBaseObject
{
PROPERTY_HEADER_WITH_OVERRIDE(Fem::FemMeshShapeNetgenObject);

View File

@@ -21,32 +21,13 @@
***************************************************************************/
#include "PreCompiled.h"
#include <SMESH_Version.h>
#ifndef _PreComp_
#include <BRepBuilderAPI_Copy.hxx>
#include <BRepTools.hxx>
#include <Python.h>
#include <SMESH_Gen.hxx>
#include <SMESH_Mesh.hxx>
#include <StdMeshers_Deflection1D.hxx>
#include <StdMeshers_Hexa_3D.hxx>
#include <StdMeshers_LocalLength.hxx>
#include <StdMeshers_MaxElementArea.hxx>
#include <StdMeshers_MaxLength.hxx>
#include <StdMeshers_NumberOfSegments.hxx>
#include <StdMeshers_ProjectionSource1D.hxx>
#include <StdMeshers_ProjectionSource2D.hxx>
#include <StdMeshers_ProjectionSource3D.hxx>
#include <StdMeshers_QuadranglePreference.hxx>
#include <StdMeshers_Quadrangle_2D.hxx>
#include <StdMeshers_RadialPrism_3D.hxx>
#include <StdMeshers_Regular_1D.hxx>
#include <StdMeshers_SegmentAroundVertex_0D.hxx>
#include <StdMeshers_StartEndLength.hxx>
#endif
#include <App/DocumentObjectPy.h>
#include <App/FeaturePythonPyImp.h>
#include <App/GeoFeaturePy.h>
#include <Mod/Part/App/PartFeature.h>
#include "FemMesh.h"
@@ -56,10 +37,9 @@
using namespace Fem;
using namespace App;
PROPERTY_SOURCE(Fem::FemMeshShapeObject, Fem::FemMeshObject)
PROPERTY_SOURCE(Fem::FemMeshShapeBaseObject, Fem::FemMeshObject)
FemMeshShapeObject::FemMeshShapeObject()
FemMeshShapeBaseObject::FemMeshShapeBaseObject()
{
ADD_PROPERTY_TYPE(
Shape,
@@ -67,8 +47,18 @@ FemMeshShapeObject::FemMeshShapeObject()
"FEM Mesh",
Prop_None,
"Geometry object, the mesh is made from. The geometry object has to have a Shape.");
Shape.setScope(LinkScope::Global);
}
FemMeshShapeBaseObject::~FemMeshShapeBaseObject() = default;
// ------------------------------------------------------------------------
PROPERTY_SOURCE(Fem::FemMeshShapeObject, Fem::FemMeshShapeBaseObject)
FemMeshShapeObject::FemMeshShapeObject() = default;
FemMeshShapeObject::~FemMeshShapeObject() = default;
App::DocumentObjectExecReturn* FemMeshShapeObject::execute()
@@ -76,83 +66,43 @@ App::DocumentObjectExecReturn* FemMeshShapeObject::execute()
Fem::FemMesh newMesh;
Part::Feature* feat = Shape.getValue<Part::Feature*>();
TopoDS_Shape shape = feat->Shape.getValue();
newMesh.getSMesh()->ShapeToMesh(shape);
SMESH_Gen* myGen = newMesh.getGenerator();
newMesh.setStandardHypotheses();
int hyp = 0;
#if 1 // Surface quad mesh
#if SMESH_VERSION_MAJOR >= 9
SMESH_HypothesisPtr len(new StdMeshers_MaxLength(hyp++, myGen));
static_cast<StdMeshers_MaxLength*>(len.get())->SetLength(1.0);
newMesh.addHypothesis(shape, len);
SMESH_HypothesisPtr loc(new StdMeshers_LocalLength(hyp++, myGen));
static_cast<StdMeshers_LocalLength*>(loc.get())->SetLength(1.0);
newMesh.addHypothesis(shape, loc);
SMESH_HypothesisPtr area(new StdMeshers_MaxElementArea(hyp++, myGen));
static_cast<StdMeshers_MaxElementArea*>(area.get())->SetMaxArea(1.0);
newMesh.addHypothesis(shape, area);
SMESH_HypothesisPtr segm(new StdMeshers_NumberOfSegments(hyp++, myGen));
static_cast<StdMeshers_NumberOfSegments*>(segm.get())->SetNumberOfSegments(1);
newMesh.addHypothesis(shape, segm);
SMESH_HypothesisPtr defl(new StdMeshers_Deflection1D(hyp++, myGen));
static_cast<StdMeshers_Deflection1D*>(defl.get())->SetDeflection(0.01);
newMesh.addHypothesis(shape, defl);
SMESH_HypothesisPtr reg(new StdMeshers_Regular_1D(hyp++, myGen));
newMesh.addHypothesis(shape, reg);
SMESH_HypothesisPtr qdp(new StdMeshers_QuadranglePreference(hyp++, myGen));
newMesh.addHypothesis(shape, qdp);
SMESH_HypothesisPtr q2d(new StdMeshers_Quadrangle_2D(hyp++, myGen));
newMesh.addHypothesis(shape, q2d);
#else
SMESH_HypothesisPtr len(new StdMeshers_MaxLength(hyp++, 1, myGen));
static_cast<StdMeshers_MaxLength*>(len.get())->SetLength(1.0);
newMesh.addHypothesis(shape, len);
SMESH_HypothesisPtr loc(new StdMeshers_LocalLength(hyp++, 1, myGen));
static_cast<StdMeshers_LocalLength*>(loc.get())->SetLength(1.0);
newMesh.addHypothesis(shape, loc);
SMESH_HypothesisPtr area(new StdMeshers_MaxElementArea(hyp++, 1, myGen));
static_cast<StdMeshers_MaxElementArea*>(area.get())->SetMaxArea(1.0);
newMesh.addHypothesis(shape, area);
SMESH_HypothesisPtr segm(new StdMeshers_NumberOfSegments(hyp++, 1, myGen));
static_cast<StdMeshers_NumberOfSegments*>(segm.get())->SetNumberOfSegments(1);
newMesh.addHypothesis(shape, segm);
SMESH_HypothesisPtr defl(new StdMeshers_Deflection1D(hyp++, 1, myGen));
static_cast<StdMeshers_Deflection1D*>(defl.get())->SetDeflection(0.01);
newMesh.addHypothesis(shape, defl);
SMESH_HypothesisPtr reg(new StdMeshers_Regular_1D(hyp++, 1, myGen));
newMesh.addHypothesis(shape, reg);
SMESH_HypothesisPtr qdp(new StdMeshers_QuadranglePreference(hyp++, 1, myGen));
newMesh.addHypothesis(shape, qdp);
SMESH_HypothesisPtr q2d(new StdMeshers_Quadrangle_2D(hyp++, 1, myGen));
newMesh.addHypothesis(shape, q2d);
#endif
// create mesh
newMesh.compute();
#endif
// set the value to the object
FemMesh.setValue(newMesh);
return App::DocumentObject::StdReturn;
}
// Python feature ---------------------------------------------------------
namespace App
{
PROPERTY_SOURCE_TEMPLATE(Fem::FemMeshShapeBaseObjectPython, Fem::FemMeshShapeBaseObject)
template<>
const char* Fem::FemMeshShapeBaseObjectPython::getViewProviderName() const
{
return "FemGui::ViewProviderFemMeshShapeBasePython";
}
template<>
PyObject* Fem::FemMeshShapeBaseObjectPython::getPyObject()
{
if (PythonObject.is(Py::_None())) {
// ref counter is set to 1
PythonObject = Py::asObject(new App::FeaturePythonPyT<App::GeoFeaturePy>(this));
}
return Py::new_reference_to(PythonObject);
}
// explicit template instantiation
template class FemExport FeaturePythonT<Fem::FemMeshShapeBaseObject>;
} // namespace App

View File

@@ -29,7 +29,26 @@
namespace Fem
{
class FemExport FemMeshShapeObject: public FemMeshObject
class FemExport FemMeshShapeBaseObject: public FemMeshObject
{
PROPERTY_HEADER_WITH_OVERRIDE(Fem::FemMeshShapeBaseObject);
public:
/// Constructor
FemMeshShapeBaseObject();
~FemMeshShapeBaseObject() override;
App::PropertyLink Shape;
/// returns the type name of the ViewProvider
const char* getViewProviderName() const override
{
return "FemGui::ViewProviderFemMeshShapeBase";
}
};
class FemExport FemMeshShapeObject: public FemMeshShapeBaseObject
{
PROPERTY_HEADER_WITH_OVERRIDE(Fem::FemMeshShapeObject);
@@ -48,13 +67,13 @@ public:
// virtual short mustExecute(void) const;
// virtual PyObject *getPyObject(void);
App::PropertyLink Shape;
protected:
/// get called by the container when a property has changed
// virtual void onChanged (const App::Property* prop);
};
using FemMeshShapeBaseObjectPython = App::FeaturePythonT<FemMeshShapeBaseObject>;
} // namespace Fem

View File

@@ -138,6 +138,8 @@ PyMOD_INIT_FUNC(FemGui)
FemGui::ViewProviderFemMesh ::init();
FemGui::ViewProviderFemMeshPython ::init();
FemGui::ViewProviderFemMeshShapeBase ::init();
FemGui::ViewProviderFemMeshShapeBasePython ::init();
FemGui::ViewProviderFemMeshShape ::init();
FemGui::ViewProviderFemMeshShapeNetgen ::init();
FemGui::PropertyFemMeshItem ::init();

View File

@@ -27,8 +27,30 @@
using namespace FemGui;
PROPERTY_SOURCE(FemGui::ViewProviderFemMeshShape, FemGui::ViewProviderFemMesh)
PROPERTY_SOURCE(FemGui::ViewProviderFemMeshShapeBase, FemGui::ViewProviderFemMesh)
ViewProviderFemMeshShapeBase::ViewProviderFemMeshShapeBase() = default;
ViewProviderFemMeshShapeBase::~ViewProviderFemMeshShapeBase() = default;
// ------------------------------------------------------------------------
PROPERTY_SOURCE(FemGui::ViewProviderFemMeshShape, FemGui::ViewProviderFemMeshShapeBase)
ViewProviderFemMeshShape::ViewProviderFemMeshShape() = default;
ViewProviderFemMeshShape::~ViewProviderFemMeshShape() = default;
// Python feature ---------------------------------------------------------
namespace Gui
{
PROPERTY_SOURCE_TEMPLATE(FemGui::ViewProviderFemMeshShapeBasePython,
FemGui::ViewProviderFemMeshShapeBase)
// explicit template instantiation
template class FemGuiExport ViewProviderPythonFeatureT<ViewProviderFemMeshShapeBase>;
} // namespace Gui

View File

@@ -24,12 +24,28 @@
#ifndef FEM_ViewProviderFemMeshShape_H
#define FEM_ViewProviderFemMeshShape_H
#include <Gui/ViewProviderPythonFeature.h>
#include "ViewProviderFemMesh.h"
namespace FemGui
{
class FemGuiExport ViewProviderFemMeshShape: public ViewProviderFemMesh
class FemGuiExport ViewProviderFemMeshShapeBase: public ViewProviderFemMesh
{
PROPERTY_HEADER_WITH_OVERRIDE(FemGui::ViewProviderFemMeshShapeBase);
public:
/// constructor.
ViewProviderFemMeshShapeBase();
/// destructor.
~ViewProviderFemMeshShapeBase() override;
};
class FemGuiExport ViewProviderFemMeshShape: public ViewProviderFemMeshShapeBase
{
PROPERTY_HEADER_WITH_OVERRIDE(FemGui::ViewProviderFemMeshShape);
@@ -41,6 +57,9 @@ public:
~ViewProviderFemMeshShape() override;
};
using ViewProviderFemMeshShapeBasePython =
Gui::ViewProviderPythonFeatureT<ViewProviderFemMeshShapeBase>;
} // namespace FemGui

View File

@@ -490,7 +490,7 @@ def makeMeshBoundaryLayer(doc, base_mesh, name="MeshBoundaryLayer"):
def makeMeshGmsh(doc, name="MeshGmsh"):
"""makeMeshGmsh(document, [name]):
makes a Gmsh FEM mesh object"""
obj = doc.addObject("Fem::FemMeshObjectPython", name)
obj = doc.addObject("Fem::FemMeshShapeBaseObjectPython", name)
from femobjects import mesh_gmsh
mesh_gmsh.MeshGmsh(obj)

View File

@@ -762,10 +762,18 @@ class _MeshGmshFromShape(CommandManager):
"ObjectsFem.makeMeshGmsh(FreeCAD.ActiveDocument, '" + mesh_obj_name + "')"
)
FreeCADGui.doCommand(
"FreeCAD.ActiveDocument.ActiveObject.Part = FreeCAD.ActiveDocument.{}".format(
"FreeCAD.ActiveDocument.ActiveObject.Shape = FreeCAD.ActiveDocument.{}".format(
self.selobj.Name
)
)
FreeCADGui.doCommand("FreeCAD.ActiveDocument.ActiveObject.ElementOrder = '2nd'")
# SecondOrderLinear gives much better meshes in the regard of
# nonpositive jacobians but on curved faces the constraint nodes
# will no longer found thus standard will be False
# https://forum.freecad.org/viewtopic.php?t=41738
# https://forum.freecad.org/viewtopic.php?f=18&t=45260&start=20#p389494
FreeCADGui.doCommand("FreeCAD.ActiveDocument.ActiveObject.SecondOrderLinear = False")
# Gmsh mesh object could be added without an active analysis
# but if there is an active analysis move it in there
import FemGui

View File

@@ -73,9 +73,10 @@ def setup_boxanalysisbase(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.CharacteristicLengthMin = "8.0 mm"
femmesh_obj.ElementOrder = "2nd"
doc.recompute()
return doc

View File

@@ -186,7 +186,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.CharacteristicLengthMax = "50.0 mm"
femmesh_obj.ElementDimension = "2D"

View File

@@ -159,7 +159,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.CharacteristicLengthMax = "300.0 mm"
femmesh_obj.ElementDimension = "2D"

View File

@@ -139,7 +139,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
doc.recompute()
return doc

View File

@@ -130,7 +130,7 @@ def setup_cantilever_base_edge(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.ElementDimension = "1D"
femmesh_obj.CharacteristicLengthMax = "1750.0 mm"

View File

@@ -115,7 +115,7 @@ def setup_cantilever_base_face(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.ElementDimension = "2D"
femmesh_obj.CharacteristicLengthMax = "500.0 mm"

View File

@@ -102,7 +102,7 @@ def setup_cantilever_base_solid(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
doc.recompute()

View File

@@ -92,7 +92,7 @@ def setup(doc=None, solvertype="ccxtools"):
femmesh_obj.FemMesh = new_fem_mesh
# set mesh obj parameter
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.ElementDimension = "2D"
femmesh_obj.ElementOrder = "1st"

View File

@@ -92,7 +92,7 @@ def setup(doc=None, solvertype="ccxtools"):
femmesh_obj.FemMesh = new_fem_mesh
# set mesh obj parameter
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.ElementDimension = "2D"
femmesh_obj.ElementOrder = "1st"

View File

@@ -92,7 +92,7 @@ def setup(doc=None, solvertype="ccxtools"):
femmesh_obj.FemMesh = new_fem_mesh
# set mesh obj parameter
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.ElementDimension = "1D"
femmesh_obj.ElementOrder = "1st"

View File

@@ -82,7 +82,7 @@ def setup(doc=None, solvertype="ccxtools"):
# clear mesh and set meshing parameter
femmesh_obj.FemMesh = Fem.FemMesh()
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.ElementDimension = "3D"
femmesh_obj.ElementOrder = "1st"

View File

@@ -92,7 +92,7 @@ def setup(doc=None, solvertype="ccxtools"):
femmesh_obj.FemMesh = new_fem_mesh
# set mesh obj parameter
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.ElementDimension = "2D"
femmesh_obj.ElementOrder = "1st"

View File

@@ -191,7 +191,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.CharacteristicLengthMax = "5.0 mm"

View File

@@ -210,7 +210,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
doc.recompute()

View File

@@ -197,7 +197,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
doc.recompute()

View File

@@ -272,7 +272,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
doc.recompute()

View File

@@ -140,7 +140,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
doc.recompute()

View File

@@ -169,7 +169,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
doc.recompute()

View File

@@ -184,7 +184,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.CharacteristicLengthMax = "7 mm"

View File

@@ -173,7 +173,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
doc.recompute()

View File

@@ -137,7 +137,7 @@ def setup(doc=None, solvertype="elmer"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.CharacteristicLengthMax = "40.80 mm"

View File

@@ -192,7 +192,7 @@ def setup(doc=None, solvertype="elmer"):
# mesh
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.Part = body
femmesh_obj.Shape = body
femmesh_obj.CharacteristicLengthMax = "1.25 mm"
femmesh_obj.ElementOrder = "1st"
femmesh_obj.ViewObject.Visibility = False

View File

@@ -165,7 +165,7 @@ def setup(doc=None, solvertype="elmer"):
# mesh
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.CharacteristicLengthMax = "600 mm"
femmesh_obj.ViewObject.Visibility = False

View File

@@ -228,7 +228,7 @@ def setup(doc=None, solvertype="elmer"):
# mesh
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.CharacteristicLengthMax = "500 mm"
femmesh_obj.ViewObject.Visibility = False

View File

@@ -252,7 +252,7 @@ def setup(doc=None, solvertype="elmer"):
# mesh
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.Part = BooleanFragments
femmesh_obj.Shape = BooleanFragments
femmesh_obj.ElementOrder = "1st"
femmesh_obj.CharacteristicLengthMax = "4 mm"
femmesh_obj.ViewObject.Visibility = False

View File

@@ -260,7 +260,7 @@ def setup(doc=None, solvertype="elmer"):
# mesh
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.Part = BooleanFragments
femmesh_obj.Shape = BooleanFragments
femmesh_obj.ElementOrder = "1st"
femmesh_obj.CharacteristicLengthMax = "4 mm"
femmesh_obj.ViewObject.Visibility = False

View File

@@ -258,7 +258,7 @@ def setup(doc=None, solvertype="elmer"):
# mesh
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.Part = BooleanFragments
femmesh_obj.Shape = BooleanFragments
femmesh_obj.ElementOrder = "1st"
femmesh_obj.CharacteristicLengthMax = "4 mm"
femmesh_obj.ViewObject.Visibility = False

View File

@@ -153,7 +153,7 @@ def setup(doc=None, solvertype="elmer"):
# mesh
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.Part = cube
femmesh_obj.Shape = cube
femmesh_obj.CharacteristicLengthMax = "1 mm"
femmesh_obj.ViewObject.Visibility = False

View File

@@ -258,7 +258,7 @@ def setup(doc=None, solvertype="elmer"):
# mesh
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.Part = BooleanFragments
femmesh_obj.Shape = BooleanFragments
femmesh_obj.CharacteristicLengthMax = "3 mm"
femmesh_obj.ViewObject.Visibility = False

View File

@@ -201,7 +201,7 @@ def setup(doc=None, solvertype="elmer"):
# mesh
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.Part = BooleanFragments
femmesh_obj.Shape = BooleanFragments
femmesh_obj.ElementOrder = "1st"
femmesh_obj.CharacteristicLengthMax = "0.5 mm"
femmesh_obj.ViewObject.Visibility = False

View File

@@ -260,7 +260,7 @@ def setup(doc=None, solvertype="elmer"):
# mesh
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.Part = BooleanFragments
femmesh_obj.Shape = BooleanFragments
femmesh_obj.CharacteristicLengthMax = "100.0 mm"
femmesh_obj.ViewObject.Visibility = False

View File

@@ -150,7 +150,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.CharacteristicLengthMax = "25.0 mm"

View File

@@ -201,7 +201,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
doc.recompute()

View File

@@ -194,7 +194,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
doc.recompute()

View File

@@ -170,7 +170,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
doc.recompute()

View File

@@ -178,7 +178,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
doc.recompute()

View File

@@ -188,7 +188,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.CharacteristicLengthMax = "1.0 mm"
femmesh_obj.ElementDimension = "2D"

View File

@@ -176,7 +176,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
doc.recompute()

View File

@@ -178,7 +178,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
doc.recompute()

View File

@@ -448,7 +448,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
doc.recompute()

View File

@@ -215,7 +215,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
doc.recompute()

View File

@@ -461,7 +461,7 @@ def setup(doc=None, solvertype="ccxtools"):
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.Shape = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.ElementDimension = "1D"
# four elements for each bar

View File

@@ -57,7 +57,7 @@ class GmshTools:
self.analysis = None
# part to mesh
self.part_obj = self.mesh_obj.Part
self.part_obj = self.mesh_obj.Shape
# clmax, CharacteristicLengthMax: float, 0.0 = 1e+22
self.clmax = Units.Quantity(self.mesh_obj.CharacteristicLengthMax).Value
@@ -101,6 +101,8 @@ class GmshTools:
self.algorithm2D = "8"
elif algo2D == "Packing Parallelograms":
self.algorithm2D = "9"
elif algo2D == "Quasi-structured Quad":
self.algorithm2D = "11"
else:
self.algorithm2D = "2"
@@ -839,7 +841,7 @@ class GmshTools:
)
geo.write(
"// 2D mesh algorithm (1=MeshAdapt, 2=Automatic, "
"5=Delaunay, 6=Frontal, 7=BAMG, 8=DelQuad, 9=Packing Parallelograms)\n"
"5=Delaunay, 6=Frontal, 7=BAMG, 8=DelQuad, 9=Packing Parallelograms, 11=Quasi-structured Quad)\n"
)
if len(self.bl_setting_list) and self.dimension == 3:
geo.write("Mesh.Algorithm = " + "DelQuad" + ";\n") # Frontal/DelQuad are tested
@@ -982,7 +984,7 @@ doc.recompute()
box_obj.ViewObject.Visibility = False
femmesh_obj = ObjectsFem.makeMeshGmsh(doc, box_obj.Name + "_Mesh")
femmesh_obj.Part = box_obj
femmesh_obj.Shape = box_obj
doc.recompute()
from femmesh.gmshtools import GmshTools as gt
@@ -1009,7 +1011,7 @@ for len in max_mesh_sizes:
quantity_len = "{}".format(len)
print("\n\n Start length = {}".format(quantity_len))
femmesh_obj = ObjectsFem.makeMeshGmsh(doc, box_obj.Name + "_Mesh")
femmesh_obj.Part = box_obj
femmesh_obj.Shape = box_obj
femmesh_obj.CharacteristicLengthMax = "{}".format(quantity_len)
femmesh_obj.CharacteristicLengthMin = "{}".format(quantity_len)
doc.recompute()

View File

@@ -64,8 +64,6 @@ class MeshSetsGetter:
if self.mesh_object:
if hasattr(self.mesh_object, "Shape"):
self.theshape = self.mesh_object.Shape
elif hasattr(self.mesh_object, "Part"):
self.theshape = self.mesh_object.Part
else:
FreeCAD.Console.PrintWarning(
"A finite mesh without a link to a Shape was given. "

View File

@@ -31,6 +31,8 @@ __url__ = "https://www.freecad.org"
from . import base_fempythonobject
_PropHelper = base_fempythonobject._PropHelper
class MeshGmsh(base_fempythonobject.BaseFemPythonObject):
"""
@@ -40,295 +42,271 @@ class MeshGmsh(base_fempythonobject.BaseFemPythonObject):
Type = "Fem::FemMeshGmsh"
# they will be used from the task panel too, thus they need to be outside of the __init__
known_element_dimensions = ["From Shape", "1D", "2D", "3D"]
known_element_orders = ["1st", "2nd"]
known_mesh_algorithm_2D = [
"Automatic",
"MeshAdapt",
"Delaunay",
"Frontal",
"BAMG",
"DelQuad",
"Packing Parallelograms",
]
known_mesh_algorithm_3D = [
"Automatic",
"Delaunay",
"New Delaunay",
"Frontal",
"MMG3D",
"R-tree",
"HXT",
]
known_mesh_RecombinationAlgorithms = [
"Simple",
"Blossom",
"Simple full-quad",
"Blossom full-quad",
]
known_mesh_HighOrderOptimizers = [
"None",
"Optimization",
"Elastic+Optimization",
"Elastic",
"Fast curving",
]
known_mesh_SubdivisionAlgorithms = ["None", "All Quadrangles", "All Hexahedra", "Barycentric"]
def __init__(self, obj):
super().__init__(obj)
self.add_properties(obj)
for prop in self._get_properties():
prop.add_to_object(obj)
def _get_properties(self):
prop = []
prop.append(
_PropHelper(
type="App::PropertyLinkList",
name="MeshBoundaryLayerList",
group="Base",
doc="Mesh boundaries need inflation layers",
value=[],
)
)
prop.append(
_PropHelper(
type="App::PropertyLinkList",
name="MeshRegionList",
group="Base",
doc="Mesh refinments of the mesh",
value=[],
)
)
prop.append(
_PropHelper(
type="App::PropertyLinkList",
name="MeshGroupList",
group="Base",
doc="Mesh groups of the mesh",
value=[],
)
)
prop.append(
_PropHelper(
type="App::PropertyLength",
name="CharacteristicLengthMax",
group="FEM Gmsh Mesh Params",
doc="Max mesh element size (0.0 means infinity)",
value=0.0, # will be 1e+22
)
)
prop.append(
_PropHelper(
type="App::PropertyLength",
name="CharacteristicLengthMin",
group="FEM Gmsh Mesh Params",
doc="Min mesh element size",
value=0.0,
)
)
prop.append(
_PropHelper(
type="App::PropertyEnumeration",
name="ElementDimension",
group="FEM Gmsh Mesh Params",
doc="Dimension of mesh elements ('From Shape': according ShapeType of part to mesh)",
value=["From Shape", "1D", "2D", "3D"],
)
)
prop.append(
_PropHelper(
type="App::PropertyEnumeration",
name="ElementOrder",
group="FEM Gmsh Mesh Params",
doc="Order of mesh elements",
value=["1st", "2nd"],
)
)
prop.append(
_PropHelper(
type="App::PropertyBool",
name="OptimizeStd",
group="FEM Gmsh Mesh Params",
doc="Optimize tetrahedral elements",
value=True,
)
)
prop.append(
_PropHelper(
type="App::PropertyBool",
name="OptimizeNetgen",
group="FEM Gmsh Mesh Params",
doc="Optimize tetra elements by use of Netgen",
value=False,
)
)
prop.append(
_PropHelper(
type="App::PropertyEnumeration",
name="HighOrderOptimize",
group="FEM Gmsh Mesh Params",
doc="Optimization of high order meshes",
value=[
"None",
"Optimization",
"Elastic+Optimization",
"Elastic",
"Fast curving",
],
)
)
prop.append(
_PropHelper(
type="App::PropertyBool",
name="RecombineAll",
group="FEM Gmsh Mesh Params",
doc="Apply recombination algorithm to all surfaces",
value=False,
)
)
prop.append(
_PropHelper(
type="App::PropertyBool",
name="Recombine3DAll",
group="FEM Gmsh Mesh Params",
doc="Apply recombination algorithm to all volumes",
value=False,
)
)
prop.append(
_PropHelper(
type="App::PropertyEnumeration",
name="RecombinationAlgorithm",
group="FEM Gmsh Mesh Params",
doc="Recombination algorithm",
value=[
"Simple",
"Blossom",
"Simple full-quad",
"Blossom full-quad",
],
)
)
prop.append(
_PropHelper(
type="App::PropertyBool",
name="CoherenceMesh",
group="FEM Gmsh Mesh Params",
doc="Removes all duplicate mesh vertices",
value=True,
)
)
prop.append(
_PropHelper(
type="App::PropertyFloat",
name="GeometryTolerance",
group="FEM Gmsh Mesh Params",
doc="Geometrical Tolerance (0.0 means GMSH std = 1e-08)",
value=1e-06,
)
)
prop.append(
_PropHelper(
type="App::PropertyBool",
name="SecondOrderLinear",
group="FEM Gmsh Mesh Params",
doc="Second order nodes are created by linear interpolation",
value=False,
)
)
prop.append(
_PropHelper(
type="App::PropertyIntegerConstraint",
name="MeshSizeFromCurvature",
group="FEM Gmsh Mesh Params",
doc="Number of elements per 2*pi radians, 0 to deactivate",
value=(12, 0, 10000, 1),
)
)
prop.append(
_PropHelper(
type="App::PropertyEnumeration",
name="Algorithm2D",
group="FEM Gmsh Mesh Params",
doc="Mesh algorithm 2D",
value=[
"Automatic",
"MeshAdapt",
"Delaunay",
"Frontal",
"BAMG",
"DelQuad",
"Packing Parallelograms",
"Quasi-structured Quad",
],
)
)
prop.append(
_PropHelper(
type="App::PropertyEnumeration",
name="Algorithm3D",
group="FEM Gmsh Mesh Params",
doc="Mesh algorithm 3D",
value=[
"Automatic",
"Delaunay",
"New Delaunay",
"Frontal",
"MMG3D",
"R-tree",
"HXT",
],
)
)
prop.append(
_PropHelper(
type="App::PropertyBool",
name="GroupsOfNodes",
group="FEM Gmsh Mesh Params",
doc="For each group create not only the elements but the nodes too",
value=False,
)
)
prop.append(
_PropHelper(
type="App::PropertyEnumeration",
name="SubdivisionAlgorithm",
group="FEM Gmsh Mesh Params",
doc="Mesh subdivision algorithm",
value=["None", "All Quadrangles", "All Hexahedra", "Barycentric"],
)
)
return prop
def onDocumentRestored(self, obj):
# update old project with new properties
for prop in self._get_properties():
try:
obj.getPropertyByName(prop.name)
if prop.name == "Algorithm2D":
# refresh the list of known 2D algorithms
obj.Algorithm2D = prop.value
elif prop.name == "Algorithm3D":
# refresh the list of known 3D algorithms
obj.Algorithm3D = prop.value
elif prop.name == "HighOrderOptimize":
# HighOrderOptimize was once App::PropertyBool, so check this
if type(obj.HighOrderOptimize) is bool:
value = obj.HighOrderOptimize
obj.setPropertyStatus("HighOrderOptimize", "-LockDynamic")
obj.removeProperty("HighOrderOptimize")
prop.add_to_object(obj)
obj.HighOrderOptimize = "Optimization" if value else "None"
except:
prop.add_to_object(obj)
# HighOrderOptimize
# was once App::PropertyBool, so check this
high_order_optimizer = ""
if obj.HighOrderOptimize is True:
high_order_optimizer = "Optimization"
elif obj.HighOrderOptimize is False:
high_order_optimizer = "None"
obj.removeProperty("HighOrderOptimize")
# add new HighOrderOptimize property
self.add_properties(obj)
# write the stored high_order_optimizer
if high_order_optimizer:
obj.HighOrderOptimize = high_order_optimizer
# Algorithm3D
# refresh the list of known 3D algorithms for existing meshes
# since some algos are meanwhile deprecated and new algos are available
obj.Algorithm3D = MeshGmsh.known_mesh_algorithm_3D
def add_properties(self, obj):
# this method is called from onDocumentRestored
# thus only add and or set a attribute
# if the attribute does not exist
if not hasattr(obj, "MeshBoundaryLayerList"):
obj.addProperty(
"App::PropertyLinkList",
"MeshBoundaryLayerList",
"Base",
"Mesh boundaries need inflation layers",
# migrate old Part property to Shape property
try:
value_part = obj.getPropertyByName("Part")
obj.setPropertyStatus("Part", "-LockDynamic")
obj.removeProperty("Part")
# old object is Fem::FemMeshObjectPython (does not have Shape property with global scope)
prop = _PropHelper(
type="App::PropertyLinkGlobal",
name="Shape",
group="FEM Mesh",
doc="Geometry object, the mesh is made from. The geometry object has to have a Shape",
value=value_part,
)
obj.setPropertyStatus("MeshBoundaryLayerList", "LockDynamic")
obj.MeshBoundaryLayerList = []
if not hasattr(obj, "MeshRegionList"):
obj.addProperty(
"App::PropertyLinkList", "MeshRegionList", "Base", "Mesh refinments of the mesh"
)
obj.setPropertyStatus("MeshRegionList", "LockDynamic")
obj.MeshRegionList = []
if not hasattr(obj, "MeshGroupList"):
obj.addProperty(
"App::PropertyLinkList", "MeshGroupList", "Base", "Mesh groups of the mesh"
)
obj.setPropertyStatus("MeshGroupList", "LockDynamic")
obj.MeshGroupList = []
if not hasattr(obj, "Part"):
obj.addProperty(
"App::PropertyLink",
"Part",
"FEM Mesh",
"Geometry object, the mesh is made from. The geometry object has to have a Shape.",
)
obj.setPropertyStatus("Part", "LockDynamic")
obj.Part = None
if not hasattr(obj, "CharacteristicLengthMax"):
obj.addProperty(
"App::PropertyLength",
"CharacteristicLengthMax",
"FEM Gmsh Mesh Params",
"Max mesh element size (0.0 = infinity)",
)
obj.setPropertyStatus("CharacteristicLengthMax", "LockDynamic")
obj.CharacteristicLengthMax = 0.0 # will be 1e+22
if not hasattr(obj, "CharacteristicLengthMin"):
obj.addProperty(
"App::PropertyLength",
"CharacteristicLengthMin",
"FEM Gmsh Mesh Params",
"Min mesh element size",
)
obj.setPropertyStatus("CharacteristicLengthMin", "LockDynamic")
obj.CharacteristicLengthMin = 0.0
if not hasattr(obj, "ElementDimension"):
obj.addProperty(
"App::PropertyEnumeration",
"ElementDimension",
"FEM Gmsh Mesh Params",
"Dimension of mesh elements (Auto = according ShapeType of part to mesh)",
)
obj.setPropertyStatus("ElementDimension", "LockDynamic")
obj.ElementDimension = MeshGmsh.known_element_dimensions
obj.ElementDimension = "From Shape" # according ShapeType of Part to mesh
if not hasattr(obj, "ElementOrder"):
obj.addProperty(
"App::PropertyEnumeration",
"ElementOrder",
"FEM Gmsh Mesh Params",
"Order of mesh elements",
)
obj.setPropertyStatus("ElementOrder", "LockDynamic")
obj.ElementOrder = MeshGmsh.known_element_orders
obj.ElementOrder = "2nd"
if not hasattr(obj, "OptimizeStd"):
obj.addProperty(
"App::PropertyBool",
"OptimizeStd",
"FEM Gmsh Mesh Params",
"Optimize tetrahedral elements",
)
obj.setPropertyStatus("OptimizeStd", "LockDynamic")
obj.OptimizeStd = True
if not hasattr(obj, "OptimizeNetgen"):
obj.addProperty(
"App::PropertyBool",
"OptimizeNetgen",
"FEM Gmsh Mesh Params",
"Optimize tetra elements by use of Netgen",
)
obj.setPropertyStatus("OptimizeNetgen", "LockDynamic")
obj.OptimizeNetgen = False
if not hasattr(obj, "HighOrderOptimize"):
obj.addProperty(
"App::PropertyEnumeration",
"HighOrderOptimize",
"FEM Gmsh Mesh Params",
"Optimization of high order meshes",
)
obj.setPropertyStatus("HighOrderOptimize", "LockDynamic")
obj.HighOrderOptimize = MeshGmsh.known_mesh_HighOrderOptimizers
obj.HighOrderOptimize = "None"
if not hasattr(obj, "RecombineAll"):
obj.addProperty(
"App::PropertyBool",
"RecombineAll",
"FEM Gmsh Mesh Params",
"Apply recombination algorithm to all surfaces",
)
obj.setPropertyStatus("RecombineAll", "LockDynamic")
obj.RecombineAll = False
if not hasattr(obj, "Recombine3DAll"):
obj.addProperty(
"App::PropertyBool",
"Recombine3DAll",
"FEM Gmsh Mesh Params",
"Apply recombination algorithm to all volumes",
)
obj.setPropertyStatus("Recombine3DAll", "LockDynamic")
obj.Recombine3DAll = False
if not hasattr(obj, "RecombinationAlgorithm"):
obj.addProperty(
"App::PropertyEnumeration",
"RecombinationAlgorithm",
"FEM Gmsh Mesh Params",
"Recombination algorithm",
)
obj.setPropertyStatus("RecombinationAlgorithm", "LockDynamic")
obj.RecombinationAlgorithm = MeshGmsh.known_mesh_RecombinationAlgorithms
obj.RecombinationAlgorithm = "Simple"
if not hasattr(obj, "CoherenceMesh"):
obj.addProperty(
"App::PropertyBool",
"CoherenceMesh",
"FEM Gmsh Mesh Params",
"Removes all duplicate mesh vertices",
)
obj.setPropertyStatus("CoherenceMesh", "LockDynamic")
obj.CoherenceMesh = True
if not hasattr(obj, "GeometryTolerance"):
obj.addProperty(
"App::PropertyFloat",
"GeometryTolerance",
"FEM Gmsh Mesh Params",
"Geometrical Tolerance (0.0 = GMSH std = 1e-08)",
)
obj.setPropertyStatus("GeometryTolerance", "LockDynamic")
obj.GeometryTolerance = 1e-06
if not hasattr(obj, "SecondOrderLinear"):
obj.addProperty(
"App::PropertyBool",
"SecondOrderLinear",
"FEM Gmsh Mesh Params",
"Second order nodes are created by linear interpolation",
)
obj.setPropertyStatus("SecondOrderLinear", "LockDynamic")
obj.SecondOrderLinear = False
# gives much better meshes in the regard of nonpositive jacobians
# but
# on curved faces the constraint nodes will no longer found
# thus standard will be False
# https://forum.freecad.org/viewtopic.php?t=41738
# https://forum.freecad.org/viewtopic.php?f=18&t=45260&start=20#p389494
if not hasattr(obj, "MeshSizeFromCurvature"):
obj.addProperty(
"App::PropertyIntegerConstraint",
"MeshSizeFromCurvature",
"FEM Gmsh Mesh Params",
"number of elements per 2*pi radians, 0 to deactivate",
)
obj.setPropertyStatus("MeshSizeFromCurvature", "LockDynamic")
obj.MeshSizeFromCurvature = (12, 0, 10000, 1)
if not hasattr(obj, "Algorithm2D"):
obj.addProperty(
"App::PropertyEnumeration",
"Algorithm2D",
"FEM Gmsh Mesh Params",
"mesh algorithm 2D",
)
obj.setPropertyStatus("Algorithm2D", "LockDynamic")
obj.Algorithm2D = MeshGmsh.known_mesh_algorithm_2D
obj.Algorithm2D = "Automatic"
if not hasattr(obj, "Algorithm3D"):
obj.addProperty(
"App::PropertyEnumeration",
"Algorithm3D",
"FEM Gmsh Mesh Params",
"mesh algorithm 3D",
)
obj.setPropertyStatus("Algorithm3D", "LockDynamic")
obj.Algorithm3D = MeshGmsh.known_mesh_algorithm_3D
obj.Algorithm3D = "Automatic"
if not hasattr(obj, "GroupsOfNodes"):
obj.addProperty(
"App::PropertyBool",
"GroupsOfNodes",
"FEM Gmsh Mesh Params",
"For each group create not only the elements but the nodes too.",
)
obj.setPropertyStatus("GroupsOfNodes", "LockDynamic")
obj.GroupsOfNodes = False
if not hasattr(obj, "SubdivisionAlgorithm"):
obj.addProperty(
"App::PropertyEnumeration",
"SubdivisionAlgorithm",
"FEM Gmsh Mesh Params",
"Mesh subdivision algorithm",
)
obj.setPropertyStatus("SubdivisionAlgorithm", "LockDynamic")
obj.SubdivisionAlgorithm = MeshGmsh.known_mesh_SubdivisionAlgorithms
obj.SubdivisionAlgorithm = "None"
prop.add_to_object(obj)
except:
pass

View File

@@ -85,7 +85,7 @@ class _TaskPanel:
self.form = [self.refWidget, propWidget]
analysis = obj.getParentGroup()
self._mesh = membertools.get_single_member(analysis, "Fem::FemMeshObject")
self._part = self._mesh.Part if self._mesh is not None else None
self._part = self._mesh.Shape if self._mesh is not None else None
self._partVisible = None
self._meshVisible = None

View File

@@ -758,24 +758,24 @@ class Writer:
obj = self.getSingleMember("Fem::FemMeshObject")
bodyCount = 0
prefix = ""
if obj.Part.Shape.Solids:
if obj.Shape.Shape.Solids:
prefix = "Solid"
bodyCount = len(obj.Part.Shape.Solids)
elif obj.Part.Shape.Faces:
bodyCount = len(obj.Shape.Shape.Solids)
elif obj.Shape.Shape.Faces:
prefix = "Face"
bodyCount = len(obj.Part.Shape.Faces)
elif obj.Part.Shape.Edges:
bodyCount = len(obj.Shape.Shape.Faces)
elif obj.Shape.Shape.Edges:
prefix = "Edge"
bodyCount = len(obj.Part.Shape.Edges)
bodyCount = len(obj.Shape.Shape.Edges)
return [prefix + str(i + 1) for i in range(bodyCount)]
def getMeshDimension(self):
obj = self.getSingleMember("Fem::FemMeshObject")
if obj.Part.Shape.Solids:
if obj.Shape.Shape.Solids:
return 3
if obj.Part.Shape.Faces:
if obj.Shape.Shape.Faces:
return 2
if obj.Part.Shape.Edges:
if obj.Shape.Shape.Edges:
return 1
return None

View File

@@ -36,7 +36,6 @@ import FreeCADGui
from femguiutils import selection_widgets
from femtools import femutils
from femtools import membertools
@@ -84,7 +83,7 @@ class _TaskPanel:
if analysis is not None:
self._mesh = membertools.get_single_member(analysis, "Fem::FemMeshObject")
if self._mesh is not None:
self._part = femutils.get_part_to_mesh(self._mesh)
self._part = self._mesh.Shape
self._partVisible = None
self._meshVisible = None

View File

@@ -34,7 +34,6 @@ import FreeCADGui
from femguiutils import selection_widgets
from femtools import femutils
from femtools import membertools
@@ -63,7 +62,7 @@ class _TaskPanel:
if analysis is not None:
self._mesh = membertools.get_single_member(analysis, "Fem::FemMeshObject")
if self._mesh is not None:
self._part = femutils.get_part_to_mesh(self._mesh)
self._part = self._mesh.Shape
self._partVisible = None
self._meshVisible = None

View File

@@ -37,7 +37,6 @@ import FreeCAD
import FreeCADGui
from femguiutils import selection_widgets
from femtools import femutils
from femtools import membertools
@@ -66,7 +65,7 @@ class _TaskPanel:
if analysis is not None:
self._mesh = membertools.get_single_member(analysis, "Fem::FemMeshObject")
if self._mesh is not None:
self._part = femutils.get_part_to_mesh(self._mesh)
self._part = self._mesh.Shape
self._partVisible = None
self._meshVisible = None

View File

@@ -36,7 +36,6 @@ import FreeCAD
import FreeCADGui
from femguiutils import selection_widgets
from femtools import femutils
from femtools import membertools
@@ -64,7 +63,7 @@ class _TaskPanel:
if analysis is not None:
self._mesh = membertools.get_single_member(analysis, "Fem::FemMeshObject")
if self._mesh is not None:
self._part = femutils.get_part_to_mesh(self._mesh)
self._part = self._mesh.Shape
self._partVisible = None
self._meshVisible = None

View File

@@ -36,7 +36,6 @@ import FreeCAD
import FreeCADGui
from femguiutils import selection_widgets
from femtools import femutils
from femtools import membertools
@@ -64,7 +63,7 @@ class _TaskPanel:
if analysis is not None:
self._mesh = membertools.get_single_member(analysis, "Fem::FemMeshObject")
if self._mesh is not None:
self._part = femutils.get_part_to_mesh(self._mesh)
self._part = self._mesh.Shape
self._partVisible = None
self._meshVisible = None

View File

@@ -33,7 +33,6 @@ import FreeCAD
import FreeCADGui
from femguiutils import selection_widgets
from femtools import femutils
from femtools import membertools
@@ -62,7 +61,7 @@ class _TaskPanel:
if analysis is not None:
self._mesh = membertools.get_single_member(analysis, "Fem::FemMeshObject")
if self._mesh is not None:
self._part = femutils.get_part_to_mesh(self._mesh)
self._part = self._mesh.Shape
self._partVisible = None
self._meshVisible = None

View File

@@ -34,7 +34,6 @@ import FreeCADGui
from femguiutils import selection_widgets
from femtools import femutils
from femtools import membertools
@@ -63,7 +62,7 @@ class _TaskPanel:
if analysis is not None:
self._mesh = membertools.get_single_member(analysis, "Fem::FemMeshObject")
if self._mesh is not None:
self._part = femutils.get_part_to_mesh(self._mesh)
self._part = self._mesh.Shape
self._partVisible = None
self._meshVisible = None

View File

@@ -41,7 +41,6 @@ import FreeCAD
import FreeCADGui
import FemGui
from femobjects import mesh_gmsh
from femtools.femutils import is_of_type
from femtools.femutils import getOutputWinColor
@@ -80,9 +79,9 @@ class _TaskPanel:
self.form.pb_get_gmsh_version, QtCore.SIGNAL("clicked()"), self.get_gmsh_version
)
self.form.cb_dimension.addItems(mesh_gmsh.MeshGmsh.known_element_dimensions)
self.form.cb_dimension.addItems(self.mesh_obj.getEnumerationsOfProperty("ElementDimension"))
self.form.cb_order.addItems(mesh_gmsh.MeshGmsh.known_element_orders)
self.form.cb_order.addItems(self.mesh_obj.getEnumerationsOfProperty("ElementOrder"))
self.get_mesh_params()
self.get_active_analysis()
@@ -195,7 +194,7 @@ class _TaskPanel:
gmsh_mesh = gmshtools.GmshTools(self.mesh_obj, self.analysis)
QApplication.setOverrideCursor(Qt.WaitCursor)
part = self.mesh_obj.Part
part = self.mesh_obj.Shape
if (
self.mesh_obj.MeshRegionList
and part.Shape.ShapeType == "Compound"

View File

@@ -125,6 +125,7 @@ class TestObjectExistance(unittest.TestCase):
"Fem::FemAnalysisPython",
"Fem::FemMeshObject",
"Fem::FemMeshObjectPython",
"Fem::FemMeshShapeBaseObjectPython",
"Fem::FemMeshShapeNetgenObject",
"Fem::FemMeshShapeObject",
"Fem::FemResultObject",

View File

@@ -721,7 +721,7 @@ class TestObjectType(unittest.TestCase):
# FemMeshGmsh
mesh_gmsh = ObjectsFem.makeMeshGmsh(doc)
self.assertTrue(is_derived_from(mesh_gmsh, "App::DocumentObject"))
self.assertTrue(is_derived_from(mesh_gmsh, "Fem::FemMeshObjectPython"))
self.assertTrue(is_derived_from(mesh_gmsh, "Fem::FemMeshShapeBaseObjectPython"))
self.assertTrue(is_derived_from(mesh_gmsh, "Fem::FemMeshGmsh"))
# MeshBoundaryLayer
@@ -965,7 +965,7 @@ class TestObjectType(unittest.TestCase):
ObjectsFem.makeMaterialReinforced(doc).isDerivedFrom("App::MaterialObjectPython")
)
mesh = ObjectsFem.makeMeshGmsh(doc)
self.assertTrue(mesh.isDerivedFrom("Fem::FemMeshObjectPython"))
self.assertTrue(mesh.isDerivedFrom("Fem::FemMeshShapeBaseObjectPython"))
self.assertTrue(
ObjectsFem.makeMeshBoundaryLayer(doc, mesh).isDerivedFrom("Fem::FeaturePython")
)

View File

@@ -244,23 +244,6 @@ def make_dir(specific_path):
# ************************************************************************************************
# other
def get_part_to_mesh(mesh_obj):
"""
gmsh mesh object: the Attribute is Part
netgen mesh object: the Attribute is Shape
other mesh objects: do not have a Attribute which holds the part to mesh
"""
if is_derived_from(mesh_obj, "Fem::FemMeshGmsh"):
return mesh_obj.Part
elif is_derived_from(mesh_obj, "Fem::FemMeshShapeNetgenObject"):
return mesh_obj.Shape
else:
return None
# TODO: the Attributes should be named with the same name
# should it be Shape or Part?
# IMHO Part since the Attributes references the document object and not a Shape
def getBoundBoxOfAllDocumentShapes(doc):
"""Calculate bounding box containing all objects inside *doc*.