Fem: Use Netgen bindings entirely in external program

This commit is contained in:
marioalexis
2025-09-03 13:38:07 -03:00
committed by Chris Hennes
parent f18cff3b27
commit cd0502a155
3 changed files with 112 additions and 28 deletions

View File

@@ -42,6 +42,57 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="l_netgen_python_path">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Python path</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Gui::PrefFileChooser" name="fc_netgen_python_path" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="sizeIncrement">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Python executable for which Netgen Python bindings are installed.
Leave blank to use default Python executable</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>NetgenPythonPath</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Fem/Netgen</cstring>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@@ -35,12 +35,6 @@ import FreeCAD
import Fem
from freecad import utils
try:
from netgen import occ, meshing, config as ng_config
import pyngcore as ngcore
except ModuleNotFoundError:
FreeCAD.Console.PrintError("To use FemMesh Netgen objects, install the Netgen Python bindings")
class NetgenTools:
@@ -76,6 +70,7 @@ class NetgenTools:
}
name = "Netgen"
__param_grp = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Netgen")
def __init__(self, obj):
self.obj = obj
@@ -84,7 +79,6 @@ class NetgenTools:
self.tmpdir = ""
self.process = QProcess()
self.mesh_params = {}
self.param_grp = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Netgen")
def write_geom(self):
if not self.tmpdir:
@@ -104,7 +98,7 @@ class NetgenTools:
self.write_geom()
self.mesh_params = {
"brep_file": self.brep_file,
"threads": self.param_grp.GetInt("NumOfThreads", QThread.idealThreadCount()),
"threads": self.__param_grp.GetInt("NumOfThreads", QThread.idealThreadCount()),
"heal": self.obj.HealShape,
"glue": self.obj.Glue,
"params": self.get_meshing_parameters(),
@@ -112,7 +106,7 @@ class NetgenTools:
"second_order_linear": self.obj.SecondOrderLinear,
"result_file": self.result_file,
"mesh_region": self.get_mesh_region(),
"verbosity": self.param_grp.GetInt("LogVerbosity", 2),
"verbosity": self.__param_grp.GetInt("LogVerbosity", 2),
"zrefine": self.obj.ZRefine,
"zrefine_size": self.obj.ZRefineSize,
"zrefine_direction": tuple(self.obj.ZRefineDirection),
@@ -128,14 +122,23 @@ class NetgenTools:
)
def compute(self):
self.process.start(utils.get_python_exe(), [self.script_file])
self.process.start(self._get_python_exe(), [self.script_file])
return self.process
code = """
from netgen import occ, meshing
import pyngcore as ngcore
import numpy as np
# report Python executable and meshing script
import sys
print("Python interpreter:", sys.executable, flush=True)
print("Meshing script:", *sys.argv, flush=True)
try:
import pyngcore as ngcore
from netgen import occ, meshing
import numpy as np
except ModuleNotFoundError:
sys.exit("To use FemMesh Netgen, install numpy and Netgen Python bindings")
order_face = {order_face}
order_volume = {order_volume}
@@ -339,7 +342,7 @@ run_netgen(**{kwds})
"inverttets": self.obj.InvertTets,
"inverttrigs": self.obj.InvertTrigs,
"parallel_meshing": self.obj.ParallelMeshing,
"nthreads": self.param_grp.GetInt("NumOfThreads", QThread.idealThreadCount()),
"nthreads": self.__param_grp.GetInt("NumOfThreads", QThread.idealThreadCount()),
"closeedgefac": self.obj.CloseEdgeFactor,
}
@@ -399,19 +402,29 @@ run_netgen(**{kwds})
result.append((sub_sh, l))
return result
@staticmethod
def _get_python_exe():
path = NetgenTools.__param_grp.GetString("NetgenPythonPath", "")
if not path:
path = utils.get_python_exe()
return path
@staticmethod
def version():
result = "{}: {}\n" + "{}: {}\n" + "{}: {}\n" + "{}: {}"
return result.format(
"Netgen",
ng_config.version,
"Python",
ng_config.PYTHON_VERSION,
"OpenCASCADE",
occ.occ_version,
"Use MPI",
ng_config.USE_MPI,
)
script = """
try:
from netgen import config
print("Netgen:", config.version, flush=True)
except:
pass
"""
p = QProcess()
p.start(NetgenTools._get_python_exe(), ["-c", script])
p.waitForFinished()
info = p.readAll().data().decode()
return info
def __del__(self):
if self.tmpdir:

View File

@@ -25,27 +25,41 @@ __title__ = "Netgen preference page class"
__author__ = "Mario Passaglia"
__url__ = "https://www.freecad.org"
from PySide.QtCore import QThread
from PySide import QtCore
from PySide import QtGui
import FreeCAD
import FreeCADGui
class DlgSettingsNetgen:
class DlgSettingsNetgen(QtGui.QWidget):
def __init__(self):
self.form = FreeCADGui.PySideUic.loadUi(":ui/DlgSettingsNetgen.ui")
self.grp = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Netgen")
QtCore.QObject.connect(
self.form.fc_netgen_python_path,
QtCore.SIGNAL("fileNameSelected(QString)"),
self.netgen_python_path_selected,
)
def loadSettings(self):
self.form.ckb_legacy.setChecked(self.grp.GetBool("UseLegacyNetgen", True))
self.form.sb_threads.setValue(self.grp.GetInt("NumOfThreads", QThread.idealThreadCount()))
self.form.sb_threads.setValue(
self.grp.GetInt("NumOfThreads", QtCore.QThread.idealThreadCount())
)
self.form.fc_netgen_python_path.setProperty(
"fileName", self.grp.GetString("NetgenPythonPath", "")
)
self.populate_log_verbosity()
def saveSettings(self):
self.grp.SetBool("UseLegacyNetgen", self.form.ckb_legacy.isChecked())
self.grp.SetInt("LogVerbosity", self.form.cb_log_verbosity.currentData())
self.grp.SetInt("NumOfThreads", self.form.sb_threads.value())
self.grp.SetString("NetgenPythonPath", self.form.fc_netgen_python_path.property("fileName"))
def populate_log_verbosity(self):
values = {
@@ -63,3 +77,9 @@ class DlgSettingsNetgen:
current = self.grp.GetInt("LogVerbosity", 2)
index = self.form.cb_log_verbosity.findData(current)
self.form.cb_log_verbosity.setCurrentIndex(index)
def netgen_python_path_selected(self, path):
if path and not QtCore.QStandardPaths.findExecutable(path):
QtGui.QMessageBox.critical(
None, "Netgen", self.tr("Executable '{}' not found").format(path)
)