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) + )