Fem: Add preference entry to set Netgen log verbosity

This commit is contained in:
marioalexis
2024-12-19 01:27:15 -03:00
parent 521c8db484
commit b81b38e9b1
6 changed files with 234 additions and 107 deletions

View File

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

View File

@@ -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">

View File

@@ -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

View File

@@ -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()

View File

@@ -0,0 +1 @@
from .dlg_settings_netgen import DlgSettingsNetgen

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