Fem: Add preference entry to set Netgen log verbosity
This commit is contained in:
@@ -646,6 +646,11 @@ SET(FemGuiViewProvider_SRCS
|
||||
femviewprovider/view_solver_ccxtools.py
|
||||
)
|
||||
|
||||
SET(FemGuiPreferencePages_SRCS
|
||||
fempreferencepages/__init__.py
|
||||
fempreferencepages/dlg_settings_netgen.py
|
||||
)
|
||||
|
||||
SET(FemAllGuiScripts
|
||||
${FemGuiBaseModules_SRCS}
|
||||
${FemGuiObjects_SRCS}
|
||||
@@ -653,6 +658,7 @@ SET(FemAllGuiScripts
|
||||
${FemGuiTests_SRCS}
|
||||
${FemGuiUtils_SRCS}
|
||||
${FemGuiViewProvider_SRCS}
|
||||
${FemGuiPreferencePages_SRCS}
|
||||
)
|
||||
|
||||
if(BUILD_GUI)
|
||||
@@ -669,4 +675,5 @@ if(BUILD_GUI)
|
||||
INSTALL(FILES ${FemGuiTests_SRCS} DESTINATION Mod/Fem/femtest/gui/)
|
||||
INSTALL(FILES ${FemGuiUtils_SRCS} DESTINATION Mod/Fem/femguiutils/)
|
||||
INSTALL(FILES ${FemGuiViewProvider_SRCS} DESTINATION Mod/Fem/femviewprovider/)
|
||||
INSTALL(FILES ${FemGuiPreferencePages_SRCS} DESTINATION Mod/Fem/fempreferencepages/)
|
||||
endif(BUILD_GUI)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Gui::Dialog::DlgSettingsNetgen</class>
|
||||
<widget class="QWidget" name="Gui::Dialog::DlgSettingsNetgen">
|
||||
<class>FemGui::DlgSettingsNetgen</class>
|
||||
<widget class="QWidget" name="FemGui::DlgSettingsNetgen">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
@@ -45,6 +45,45 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_options">
|
||||
<property name="title">
|
||||
<string>Options</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="hbl_otions">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gl_options">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lbl_log_level">
|
||||
<property name="text">
|
||||
<string>Log verbosity</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="Gui::PrefComboBox" name="cb_log_verbosity">
|
||||
<property name="toolTip">
|
||||
<string>Level of verbosity printed on the task panel</string>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToContents</enum>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>LogVerbosity</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Fem/Netgen</cstring>
|
||||
</property>
|
||||
<property name="prefType" stdset="0">
|
||||
<number></number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_1">
|
||||
<property name="orientation">
|
||||
|
||||
@@ -71,8 +71,9 @@ class FemWorkbench(Workbench):
|
||||
import Fem
|
||||
import FemGui
|
||||
import femcommands.commands
|
||||
import fempreferencepages
|
||||
|
||||
FreeCADGui.addPreferencePage(":/ui/DlgSettingsNetgen.ui", "FEM")
|
||||
FreeCADGui.addPreferencePage(fempreferencepages.DlgSettingsNetgen, "FEM")
|
||||
|
||||
# dummy usage to get flake8 and lgtm quiet
|
||||
False if Fem.__name__ else True
|
||||
|
||||
@@ -33,6 +33,7 @@ from PySide.QtCore import QProcess
|
||||
|
||||
import FreeCAD
|
||||
import Fem
|
||||
from freecad import utils
|
||||
|
||||
try:
|
||||
from netgen import occ, meshing, config as ng_config
|
||||
@@ -95,16 +96,12 @@ class NetgenTools:
|
||||
geom_trans.Placement = global_pla
|
||||
self.brep_file = self.tmpdir + "/shape.brep"
|
||||
self.result_file = self.tmpdir + "/result.npy"
|
||||
self.script_file = self.tmpdir + "/code.py"
|
||||
geom_trans.exportBrep(self.brep_file)
|
||||
|
||||
code = """
|
||||
from femmesh.netgentools import NetgenTools
|
||||
|
||||
NetgenTools.run_netgen(**{params})
|
||||
"""
|
||||
|
||||
def prepare(self):
|
||||
self.write_geom()
|
||||
grp = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Netgen")
|
||||
self.mesh_params = {
|
||||
"brep_file": self.brep_file,
|
||||
"threads": self.obj.Threads,
|
||||
@@ -114,117 +111,138 @@ NetgenTools.run_netgen(**{params})
|
||||
"second_order_linear": self.obj.SecondOrderLinear,
|
||||
"result_file": self.result_file,
|
||||
"mesh_region": self.get_mesh_region(),
|
||||
"verbosity": grp.GetInt("LogVerbosity", 2),
|
||||
}
|
||||
|
||||
with open(self.script_file, "w") as file:
|
||||
file.write(
|
||||
self.code.format(
|
||||
kwds=self.mesh_params,
|
||||
order_face=NetgenTools.order_face,
|
||||
order_volume=NetgenTools.order_volume,
|
||||
)
|
||||
)
|
||||
|
||||
def compute(self):
|
||||
code_str = self.code.format(params=self.mesh_params)
|
||||
self.process.start(sys.executable, ["-c", code_str])
|
||||
self.process.start(utils.get_python_exe(), [self.script_file])
|
||||
|
||||
return self.process
|
||||
|
||||
@staticmethod
|
||||
def run_netgen(
|
||||
brep_file,
|
||||
threads,
|
||||
heal,
|
||||
params,
|
||||
second_order,
|
||||
second_order_linear,
|
||||
result_file,
|
||||
mesh_region,
|
||||
):
|
||||
geom = occ.OCCGeometry(brep_file)
|
||||
ngcore.SetNumThreads(threads)
|
||||
code = """
|
||||
from netgen import occ, meshing
|
||||
import pyngcore as ngcore
|
||||
import numpy as np
|
||||
|
||||
shape = geom.shape
|
||||
for items, l in mesh_region:
|
||||
for t, n in items:
|
||||
if t == "Vertex":
|
||||
shape.vertices.vertices[n - 1].maxh = l
|
||||
elif t == "Edge":
|
||||
shape.edges.edges[n - 1].maxh = l
|
||||
elif t == "Face":
|
||||
shape.faces.faces[n - 1].maxh = l
|
||||
elif t == "Solid":
|
||||
shape.solids.solids[n - 1].maxh = l
|
||||
order_face = {order_face}
|
||||
order_volume = {order_volume}
|
||||
|
||||
with ngcore.TaskManager():
|
||||
geom = occ.OCCGeometry(shape)
|
||||
if heal:
|
||||
geom.Heal()
|
||||
mesh = geom.GenerateMesh(mp=meshing.MeshingParameters(**params))
|
||||
def run_netgen(
|
||||
brep_file,
|
||||
threads,
|
||||
heal,
|
||||
params,
|
||||
second_order,
|
||||
second_order_linear,
|
||||
result_file,
|
||||
mesh_region,
|
||||
verbosity,
|
||||
):
|
||||
geom = occ.OCCGeometry(brep_file)
|
||||
ngcore.SetNumThreads(threads)
|
||||
|
||||
result = {
|
||||
"coords": [],
|
||||
"Edges": [[], []],
|
||||
"Faces": [[], []],
|
||||
"Volumes": [[], []],
|
||||
}
|
||||
groups = {"Edges": [], "Faces": [], "Solids": []}
|
||||
shape = geom.shape
|
||||
for items, l in mesh_region:
|
||||
for t, n in items:
|
||||
if t == "Vertex":
|
||||
shape.vertices.vertices[n - 1].maxh = l
|
||||
elif t == "Edge":
|
||||
shape.edges.edges[n - 1].maxh = l
|
||||
elif t == "Face":
|
||||
shape.faces.faces[n - 1].maxh = l
|
||||
elif t == "Solid":
|
||||
shape.solids.solids[n - 1].maxh = l
|
||||
|
||||
# save empty data if last step is geometry analysis
|
||||
if params["perfstepsend"] == NetgenTools.meshing_step["AnalyzeGeometry"]:
|
||||
np.save(result_file, [result, groups])
|
||||
return None
|
||||
with ngcore.TaskManager():
|
||||
meshing.SetMessageImportance(verbosity)
|
||||
geom = occ.OCCGeometry(shape)
|
||||
if heal:
|
||||
geom.Heal()
|
||||
mesh = geom.GenerateMesh(mp=meshing.MeshingParameters(**params))
|
||||
|
||||
if second_order:
|
||||
if second_order_linear:
|
||||
mesh.SetGeometry(None)
|
||||
mesh.SecondOrder()
|
||||
|
||||
coords = mesh.Coordinates()
|
||||
|
||||
edges = mesh.Elements1D().NumPy()
|
||||
faces = mesh.Elements2D().NumPy()
|
||||
volumes = mesh.Elements3D().NumPy()
|
||||
|
||||
nod_edges = edges["nodes"]
|
||||
nod_faces = faces["nodes"]
|
||||
nod_volumes = volumes["nodes"]
|
||||
|
||||
np_edges = (nod_edges != 0).sum(axis=1).tolist()
|
||||
np_faces = faces["np"].tolist()
|
||||
np_volumes = volumes["np"].tolist()
|
||||
|
||||
# set smesh node order
|
||||
for i in range(faces.size):
|
||||
nod_faces[i] = nod_faces[i][NetgenTools.order_face[np_faces[i]]]
|
||||
|
||||
for i in range(volumes.size):
|
||||
nod_volumes[i] = nod_volumes[i][NetgenTools.order_volume[np_volumes[i]]]
|
||||
|
||||
flat_edges = nod_edges[nod_edges != 0].tolist()
|
||||
flat_faces = nod_faces[nod_faces != 0].tolist()
|
||||
flat_volumes = nod_volumes[nod_volumes != 0].tolist()
|
||||
|
||||
result = {
|
||||
"coords": coords,
|
||||
"Edges": [flat_edges, np_edges],
|
||||
"Faces": [flat_faces, np_faces],
|
||||
"Volumes": [flat_volumes, np_volumes],
|
||||
}
|
||||
|
||||
# create groups
|
||||
nb_edges = edges.size
|
||||
nb_faces = faces.size
|
||||
nb_volumes = volumes.size
|
||||
|
||||
idx_edges = edges["index"]
|
||||
idx_faces = faces["index"]
|
||||
idx_volumes = volumes["index"]
|
||||
|
||||
for i in np.unique(idx_edges):
|
||||
edge_i = (np.nonzero(idx_edges == i)[0] + 1).tolist()
|
||||
groups["Edges"].append([i, edge_i])
|
||||
for i in np.unique(idx_faces):
|
||||
face_i = (np.nonzero(idx_faces == i)[0] + nb_edges + 1).tolist()
|
||||
groups["Faces"].append([i, face_i])
|
||||
|
||||
for i in np.unique(idx_volumes):
|
||||
volume_i = (np.nonzero(idx_volumes == i)[0] + nb_edges + nb_faces + 1).tolist()
|
||||
groups["Solids"].append([i, volume_i])
|
||||
result = {{
|
||||
"coords": [],
|
||||
"Edges": [[], []],
|
||||
"Faces": [[], []],
|
||||
"Volumes": [[], []],
|
||||
}}
|
||||
groups = {{"Edges": [], "Faces": [], "Solids": []}}
|
||||
|
||||
# save empty data if last step is geometry analysis
|
||||
if params["perfstepsend"] == 1:
|
||||
np.save(result_file, [result, groups])
|
||||
return None
|
||||
|
||||
if second_order:
|
||||
if second_order_linear:
|
||||
mesh.SetGeometry(None)
|
||||
mesh.SecondOrder()
|
||||
|
||||
coords = mesh.Coordinates()
|
||||
|
||||
edges = mesh.Elements1D().NumPy()
|
||||
faces = mesh.Elements2D().NumPy()
|
||||
volumes = mesh.Elements3D().NumPy()
|
||||
|
||||
nod_edges = edges["nodes"]
|
||||
nod_faces = faces["nodes"]
|
||||
nod_volumes = volumes["nodes"]
|
||||
|
||||
np_edges = (nod_edges != 0).sum(axis=1).tolist()
|
||||
np_faces = faces["np"].tolist()
|
||||
np_volumes = volumes["np"].tolist()
|
||||
|
||||
# set smesh node order
|
||||
for i in range(faces.size):
|
||||
nod_faces[i] = nod_faces[i][order_face[np_faces[i]]]
|
||||
|
||||
for i in range(volumes.size):
|
||||
nod_volumes[i] = nod_volumes[i][order_volume[np_volumes[i]]]
|
||||
|
||||
flat_edges = nod_edges[nod_edges != 0].tolist()
|
||||
flat_faces = nod_faces[nod_faces != 0].tolist()
|
||||
flat_volumes = nod_volumes[nod_volumes != 0].tolist()
|
||||
|
||||
result = {{
|
||||
"coords": coords,
|
||||
"Edges": [flat_edges, np_edges],
|
||||
"Faces": [flat_faces, np_faces],
|
||||
"Volumes": [flat_volumes, np_volumes],
|
||||
}}
|
||||
|
||||
# create groups
|
||||
nb_edges = edges.size
|
||||
nb_faces = faces.size
|
||||
nb_volumes = volumes.size
|
||||
|
||||
idx_edges = edges["index"]
|
||||
idx_faces = faces["index"]
|
||||
idx_volumes = volumes["index"]
|
||||
|
||||
for i in np.unique(idx_edges):
|
||||
edge_i = (np.nonzero(idx_edges == i)[0] + 1).tolist()
|
||||
groups["Edges"].append([i, edge_i])
|
||||
for i in np.unique(idx_faces):
|
||||
face_i = (np.nonzero(idx_faces == i)[0] + nb_edges + 1).tolist()
|
||||
groups["Faces"].append([i, face_i])
|
||||
|
||||
for i in np.unique(idx_volumes):
|
||||
volume_i = (np.nonzero(idx_volumes == i)[0] + nb_edges + nb_faces + 1).tolist()
|
||||
groups["Solids"].append([i, volume_i])
|
||||
|
||||
np.save(result_file, [result, groups])
|
||||
|
||||
run_netgen(**{kwds})
|
||||
"""
|
||||
|
||||
def fem_mesh_from_result(self):
|
||||
fem_mesh = Fem.FemMesh()
|
||||
|
||||
1
src/Mod/Fem/fempreferencepages/__init__.py
Normal file
1
src/Mod/Fem/fempreferencepages/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .dlg_settings_netgen import DlgSettingsNetgen
|
||||
61
src/Mod/Fem/fempreferencepages/dlg_settings_netgen.py
Normal file
61
src/Mod/Fem/fempreferencepages/dlg_settings_netgen.py
Normal file
@@ -0,0 +1,61 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2024 Mario Passaglia <mpassaglia[at]cbc.uba.ar> *
|
||||
# * *
|
||||
# * This file is part of FreeCAD. *
|
||||
# * *
|
||||
# * FreeCAD 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. *
|
||||
# * *
|
||||
# * FreeCAD 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 FreeCAD. If not, see *
|
||||
# * <https://www.gnu.org/licenses/>. *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
__title__ = "Netgen preference page class"
|
||||
__author__ = "Mario Passaglia"
|
||||
__url__ = "https://www.freecad.org"
|
||||
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
|
||||
|
||||
class DlgSettingsNetgen:
|
||||
|
||||
def __init__(self):
|
||||
self.form = FreeCADGui.PySideUic.loadUi(":ui/DlgSettingsNetgen.ui")
|
||||
self.grp = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Netgen")
|
||||
|
||||
def loadSettings(self):
|
||||
self.form.ckb_legacy.setChecked(self.grp.GetBool("UseLegacyNetgen", True))
|
||||
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())
|
||||
|
||||
def populate_log_verbosity(self):
|
||||
values = {
|
||||
"None": 0,
|
||||
"Least": 1,
|
||||
"Little": 2,
|
||||
"Moderate": 3,
|
||||
"Much": 4,
|
||||
"Most": 5,
|
||||
}
|
||||
|
||||
for v in values:
|
||||
self.form.cb_log_verbosity.addItem(v, values[v])
|
||||
|
||||
current = self.grp.GetInt("LogVerbosity", 2)
|
||||
index = self.form.cb_log_verbosity.findData(current)
|
||||
self.form.cb_log_verbosity.setCurrentIndex(index)
|
||||
Reference in New Issue
Block a user