diff --git a/src/Mod/Fem/Gui/Resources/ui/DlgSettingsNetgen.ui b/src/Mod/Fem/Gui/Resources/ui/DlgSettingsNetgen.ui
index 95d00eb5dc..f579750f5d 100644
--- a/src/Mod/Fem/Gui/Resources/ui/DlgSettingsNetgen.ui
+++ b/src/Mod/Fem/Gui/Resources/ui/DlgSettingsNetgen.ui
@@ -42,6 +42,57 @@
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Python path
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+ Python executable for which Netgen Python bindings are installed.
+Leave blank to use default Python executable
+
+
+ NetgenPythonPath
+
+
+ Mod/Fem/Netgen
+
+
+
diff --git a/src/Mod/Fem/femmesh/netgentools.py b/src/Mod/Fem/femmesh/netgentools.py
index e83837535c..4548d983e3 100644
--- a/src/Mod/Fem/femmesh/netgentools.py
+++ b/src/Mod/Fem/femmesh/netgentools.py
@@ -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:
diff --git a/src/Mod/Fem/fempreferencepages/dlg_settings_netgen.py b/src/Mod/Fem/fempreferencepages/dlg_settings_netgen.py
index 695f7252c2..2a11d58f05 100644
--- a/src/Mod/Fem/fempreferencepages/dlg_settings_netgen.py
+++ b/src/Mod/Fem/fempreferencepages/dlg_settings_netgen.py
@@ -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)
+ )