FEM: GMSH mesh tool, the GMSH tool class and a task panel
This commit is contained in:
parent
1327589045
commit
ae90dd0522
|
@ -87,6 +87,7 @@ SET(FemScripts_SRCS
|
||||||
_FemSolverZ88.py
|
_FemSolverZ88.py
|
||||||
_MechanicalMaterial.py
|
_MechanicalMaterial.py
|
||||||
_TaskPanelFemBeamSection.py
|
_TaskPanelFemBeamSection.py
|
||||||
|
_TaskPanelFemMeshGmsh.py
|
||||||
_TaskPanelFemShellThickness.py
|
_TaskPanelFemShellThickness.py
|
||||||
_TaskPanelFemSolverCalculix.py
|
_TaskPanelFemSolverCalculix.py
|
||||||
_TaskPanelMechanicalMaterial.py
|
_TaskPanelMechanicalMaterial.py
|
||||||
|
@ -110,6 +111,7 @@ SET(FemScripts_SRCS
|
||||||
FemBeamSection.py
|
FemBeamSection.py
|
||||||
FemCommands.py
|
FemCommands.py
|
||||||
FemConstraintSelfWeight.py
|
FemConstraintSelfWeight.py
|
||||||
|
FemGmshTools.py
|
||||||
FemInputWriter.py
|
FemInputWriter.py
|
||||||
FemInputWriterCcx.py
|
FemInputWriterCcx.py
|
||||||
FemInputWriterZ88.py
|
FemInputWriterZ88.py
|
||||||
|
@ -127,6 +129,7 @@ SET(FemScripts_SRCS
|
||||||
TestFem.py
|
TestFem.py
|
||||||
z88DispReader.py
|
z88DispReader.py
|
||||||
TaskPanelFemBeamSection.ui
|
TaskPanelFemBeamSection.ui
|
||||||
|
TaskPanelFemMeshGmsh.ui
|
||||||
TaskPanelFemShellThickness.ui
|
TaskPanelFemShellThickness.ui
|
||||||
TaskPanelFemSolverCalculix.ui
|
TaskPanelFemSolverCalculix.ui
|
||||||
TaskPanelMechanicalMaterial.ui
|
TaskPanelMechanicalMaterial.ui
|
||||||
|
|
|
@ -40,6 +40,10 @@ INSTALL(
|
||||||
_FemMeshGmsh.py
|
_FemMeshGmsh.py
|
||||||
_ViewProviderFemMeshGmsh.py
|
_ViewProviderFemMeshGmsh.py
|
||||||
_CommandMeshGmshFromShape.py
|
_CommandMeshGmshFromShape.py
|
||||||
|
_TaskPanelFemMeshGmsh.py
|
||||||
|
TaskPanelFemMeshGmsh.ui
|
||||||
|
|
||||||
|
FemGmshTools.py
|
||||||
|
|
||||||
FemBeamSection.py
|
FemBeamSection.py
|
||||||
_FemBeamSection.py
|
_FemBeamSection.py
|
||||||
|
|
258
src/Mod/Fem/FemGmshTools.py
Normal file
258
src/Mod/Fem/FemGmshTools.py
Normal file
|
@ -0,0 +1,258 @@
|
||||||
|
# ***************************************************************************
|
||||||
|
# * *
|
||||||
|
# * Copyright (c) 2016 - Bernd Hahnebach <bernd@bimstatik.org> *
|
||||||
|
# * *
|
||||||
|
# * This program is free software; you can redistribute it and/or modify *
|
||||||
|
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||||
|
# * as published by the Free Software Foundation; either version 2 of *
|
||||||
|
# * the License, or (at your option) any later version. *
|
||||||
|
# * for detail see the LICENCE text file. *
|
||||||
|
# * *
|
||||||
|
# * This program 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 Library General Public License for more details. *
|
||||||
|
# * *
|
||||||
|
# * You should have received a copy of the GNU Library General Public *
|
||||||
|
# * License along with this program; if not, write to the Free Software *
|
||||||
|
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
# * USA *
|
||||||
|
# * *
|
||||||
|
# ***************************************************************************
|
||||||
|
|
||||||
|
__title__ = "Tools for the work with GMSH mesher"
|
||||||
|
__author__ = "Bernd Hahnebach"
|
||||||
|
__url__ = "http://www.freecadweb.org"
|
||||||
|
|
||||||
|
## \addtogroup FEM
|
||||||
|
# @{
|
||||||
|
|
||||||
|
import FreeCAD
|
||||||
|
import Fem
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
from platform import system
|
||||||
|
|
||||||
|
|
||||||
|
# CONFIGURATION - EDIT THE FOLLOWING LINE TO MATCH YOUR GMSH BINARY
|
||||||
|
# gmsh_bin_linux = "/usr/bin/gmsh"
|
||||||
|
gmsh_bin_linux = "/usr/local/bin/gmsh"
|
||||||
|
gmsh_bin_windwos = "C:\\Daten\\gmsh-2.13.2-Windows\\gmsh.exe"
|
||||||
|
gmsh_bin_other = "/usr/bin/gmsh"
|
||||||
|
# END CONFIGURATION
|
||||||
|
|
||||||
|
|
||||||
|
class FemGmshTools():
|
||||||
|
def __init__(self, gmsh_mesh_obj, analysis=None):
|
||||||
|
self.mesh_obj = gmsh_mesh_obj
|
||||||
|
if analysis:
|
||||||
|
self.analysis = analysis
|
||||||
|
# group meshing turned on
|
||||||
|
else:
|
||||||
|
self.analysis = None
|
||||||
|
# group meshing turned off
|
||||||
|
|
||||||
|
# part to mesh
|
||||||
|
self.part_obj = self.mesh_obj.Part
|
||||||
|
|
||||||
|
# clmax, ElementSizeMax: float, 0.0 = 1e+22
|
||||||
|
self.clmax = self.mesh_obj.ElementSizeMax
|
||||||
|
if self.clmax == 0.0:
|
||||||
|
self.clmax = 1e+22
|
||||||
|
|
||||||
|
# clmin, ElementSizeMin: float
|
||||||
|
self.clmin = self.mesh_obj.ElementSizeMin
|
||||||
|
|
||||||
|
# order, ElementOrder: ['Auto', '1st', '2nd']
|
||||||
|
self.order = self.mesh_obj.ElementOrder
|
||||||
|
if self.order == '1st':
|
||||||
|
self.order = '1'
|
||||||
|
elif self.order == 'Auto' or self.order == '2nd':
|
||||||
|
self.order = '2'
|
||||||
|
else:
|
||||||
|
print('Error in order')
|
||||||
|
|
||||||
|
# dimension, ElementDimension: ['Auto', '1D', '2D', '3D']
|
||||||
|
self.dimension = self.mesh_obj.ElementDimension
|
||||||
|
|
||||||
|
def create_mesh(self):
|
||||||
|
print("\nWe gone start GMSH FEM mesh run!")
|
||||||
|
print(' Part to mesh: Name --> ' + self.part_obj.Name + ', Label --> ' + self.part_obj.Label + ', ShapeType --> ' + self.part_obj.Shape.ShapeType)
|
||||||
|
print(' ElementSizeMax: ' + str(self.clmax))
|
||||||
|
print(' ElementSizeMin: ' + str(self.clmin))
|
||||||
|
print(' ElementOrder: ' + self.order)
|
||||||
|
self.get_dimension()
|
||||||
|
self.get_tmp_file_paths()
|
||||||
|
self.get_gmsh_command()
|
||||||
|
self.get_group_data()
|
||||||
|
self.write_part_file()
|
||||||
|
self.write_geo()
|
||||||
|
error = self.run_gmsh_with_geo()
|
||||||
|
self.read_and_set_new_mesh()
|
||||||
|
return error
|
||||||
|
|
||||||
|
def get_dimension(self):
|
||||||
|
# Dimension
|
||||||
|
# GMSH uses the hightest availabe.
|
||||||
|
# A use case for not auto would be a surface (2D) mesh of a solid or other 3d shape
|
||||||
|
if self.dimension == 'Auto':
|
||||||
|
shty = self.part_obj.Shape.ShapeType
|
||||||
|
if shty == 'Solid' or shty == 'CompSolid':
|
||||||
|
# print('Found: ' + shty)
|
||||||
|
self.dimension = '3'
|
||||||
|
elif shty == 'Face' or shty == 'Shell':
|
||||||
|
# print('Found: ' + shty)
|
||||||
|
self.dimension = '2'
|
||||||
|
elif shty == 'Edge' or shty == 'Wire':
|
||||||
|
# print('Found: ' + shty)
|
||||||
|
self.dimension = '1'
|
||||||
|
elif shty == 'Vertex':
|
||||||
|
# print('Found: ' + shty)
|
||||||
|
FreeCAD.Console.PrintError("You can not mesh a Vertex.\n")
|
||||||
|
self.dimension = '0'
|
||||||
|
elif shty == 'Compound':
|
||||||
|
print('Found: ' + shty)
|
||||||
|
print('I do not know what is inside your Compound. Dimension was set to 3 anyway.')
|
||||||
|
# TODO check contents of Compound
|
||||||
|
# use dimension 3 on any shape works for 2D and 1d meshes as well !
|
||||||
|
# but not in combination with sewfaces or connectfaces
|
||||||
|
self.dimension = '3'
|
||||||
|
else:
|
||||||
|
self.dimension = '0'
|
||||||
|
FreeCAD.Console.PrintError('Could not retrive Dimension from shape type. Please choose dimension.')
|
||||||
|
elif self.dimension == '3D':
|
||||||
|
self.dimension = '3'
|
||||||
|
elif self.dimension == '2D':
|
||||||
|
self.dimension = '2'
|
||||||
|
elif self.dimension == '1D':
|
||||||
|
self.dimension = '1'
|
||||||
|
else:
|
||||||
|
print('Error in dimension')
|
||||||
|
print(' ElementDimension: ' + self.dimension)
|
||||||
|
|
||||||
|
def get_tmp_file_paths(self):
|
||||||
|
if system() == "Linux":
|
||||||
|
path_sep = "/"
|
||||||
|
elif system() == "Windows":
|
||||||
|
path_sep = "\\"
|
||||||
|
else:
|
||||||
|
path_sep = "/"
|
||||||
|
tmpdir = tempfile.gettempdir()
|
||||||
|
# geometry file
|
||||||
|
self.temp_file_geometry = tmpdir + path_sep + self.part_obj.Name + '_Geometry.brep'
|
||||||
|
print(' ' + self.temp_file_geometry)
|
||||||
|
# mesh file
|
||||||
|
self.mesh_name = self.part_obj.Name + '_Mesh_TmpGmsh'
|
||||||
|
self.temp_file_mesh = tmpdir + path_sep + self.mesh_name + '.unv'
|
||||||
|
print(' ' + self.temp_file_mesh)
|
||||||
|
# GMSH input file
|
||||||
|
self.temp_file_geo = tmpdir + path_sep + 'shape2mesh.geo'
|
||||||
|
print(' ' + self.temp_file_geo)
|
||||||
|
|
||||||
|
def get_gmsh_command(self):
|
||||||
|
if system() == "Linux":
|
||||||
|
self.gmsh_bin = gmsh_bin_linux
|
||||||
|
elif system() == "Windows":
|
||||||
|
self.gmsh_bin = gmsh_bin_windwos
|
||||||
|
else:
|
||||||
|
self.gmsh_bin = gmsh_bin_other
|
||||||
|
self.gmsh_command = self.gmsh_bin + ' - ' + self.temp_file_geo # gmsh - /tmp/shape2mesh.geo
|
||||||
|
print(' ' + self.gmsh_command)
|
||||||
|
|
||||||
|
def get_group_data(self):
|
||||||
|
if self.analysis:
|
||||||
|
print(' Group meshing.')
|
||||||
|
import FemMeshTools
|
||||||
|
self.group_elements = FemMeshTools.get_analysis_group_elements(self.analysis, self.part_obj)
|
||||||
|
print(self.group_elements)
|
||||||
|
else:
|
||||||
|
print(' NO group meshing.')
|
||||||
|
|
||||||
|
def write_part_file(self):
|
||||||
|
self.part_obj.Shape.exportBrep(self.temp_file_geometry)
|
||||||
|
|
||||||
|
def write_geo(self):
|
||||||
|
geo = open(self.temp_file_geo, "w")
|
||||||
|
geo.write('Merge "' + self.temp_file_geometry + '";\n')
|
||||||
|
geo.write("\n")
|
||||||
|
if self.analysis and self.group_elements:
|
||||||
|
print(' We gone have found elements to make mesh groups for!')
|
||||||
|
geo.write("// group data\n")
|
||||||
|
# we use the element name of FreeCAD which starts with 1 (example: 'Face1'), same as GMSH
|
||||||
|
for group in self.group_elements:
|
||||||
|
gdata = self.group_elements[group]
|
||||||
|
# print(gdata)
|
||||||
|
# geo.write("// " + group + "\n")
|
||||||
|
ele_nr = ''
|
||||||
|
if gdata[0].startswith('Solid'):
|
||||||
|
physical_type = 'Volume'
|
||||||
|
for ele in gdata:
|
||||||
|
ele_nr += (ele.lstrip('Solid') + ', ')
|
||||||
|
elif gdata[0].startswith('Face'):
|
||||||
|
physical_type = 'Surface'
|
||||||
|
for ele in gdata:
|
||||||
|
ele_nr += (ele.lstrip('Face') + ', ')
|
||||||
|
elif gdata[0].startswith('Edge') or gdata[0].startswith('Vertex'):
|
||||||
|
geo.write("// " + group + " group data not written. Edges or Vertexes group data not supported.\n")
|
||||||
|
print(' Groups for Edges or Vertexes reference shapes not handeled yet.')
|
||||||
|
if ele_nr:
|
||||||
|
ele_nr = ele_nr.rstrip(', ')
|
||||||
|
# print(ele_nr)
|
||||||
|
geo.write('Physical ' + physical_type + '("' + group + '") = {' + ele_nr + '};\n')
|
||||||
|
geo.write("\n")
|
||||||
|
geo.write("Mesh.CharacteristicLengthMax = " + str(self.clmax) + ";\n")
|
||||||
|
geo.write("Mesh.CharacteristicLengthMin = " + str(self.clmin) + ";\n")
|
||||||
|
geo.write("Mesh.ElementOrder = " + self.order + ";\n")
|
||||||
|
geo.write("//Mesh.HighOrderOptimize = 1;\n") # but does not really work, in GUI it does
|
||||||
|
geo.write("Mesh.Algorithm3D = 1;\n")
|
||||||
|
geo.write("Mesh.Algorithm = 2;\n")
|
||||||
|
geo.write("Mesh " + self.dimension + ";\n")
|
||||||
|
geo.write("Mesh.Format = 2;\n") # unv
|
||||||
|
if self.analysis and self.group_elements:
|
||||||
|
geo.write("// For each group save not only the elements but the nodes too.;\n")
|
||||||
|
geo.write("Mesh.SaveGroupsOfNodes = 1;\n")
|
||||||
|
geo.write("// Needed for Group meshing too, because for one material there is no group defined;\n") # belongs to Mesh.SaveAll but anly needed if there are groups
|
||||||
|
geo.write("// Ignore Physical definitions and save all elements;\n")
|
||||||
|
geo.write("Mesh.SaveAll = 1;\n")
|
||||||
|
geo.write("\n")
|
||||||
|
geo.write('Save "' + self.temp_file_mesh + '";\n')
|
||||||
|
geo.write("\n\n")
|
||||||
|
geo.write("//////////////////////////////////////////////////////////////////////\n")
|
||||||
|
geo.write("// GMSH documentation:\n")
|
||||||
|
geo.write("// http://gmsh.info/doc/texinfo/gmsh.html#Mesh\n")
|
||||||
|
geo.write("//\n")
|
||||||
|
geo.write("// We do not check if something went wrong, like negative jacobians etc. You can run GMSH manually yourself: \n")
|
||||||
|
geo.write("//\n")
|
||||||
|
geo.write("// to see full GMSH log, run in bash:\n")
|
||||||
|
geo.write("// " + self.gmsh_bin + " - " + self.temp_file_geo + "\n")
|
||||||
|
geo.write("//\n")
|
||||||
|
geo.write("// to run GMSH and keep file in GMSH GUI (with log), run in bash:\n")
|
||||||
|
geo.write("// " + self.gmsh_bin + " " + self.temp_file_geo + "\n")
|
||||||
|
geo.close
|
||||||
|
|
||||||
|
def run_gmsh_with_geo(self):
|
||||||
|
self.error = False
|
||||||
|
comandlist = [self.gmsh_bin, '-', self.temp_file_geo]
|
||||||
|
# print(comandlist)
|
||||||
|
try:
|
||||||
|
p = subprocess.Popen(comandlist, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
output, error = p.communicate()
|
||||||
|
# print(output) # stdout is still cut at some point but the warnings are in stderr and thus printed :-)
|
||||||
|
# print(error)
|
||||||
|
except:
|
||||||
|
error = 'Error executing: {}\n'.format(self.gmsh_command)
|
||||||
|
FreeCAD.Console.PrintError(error)
|
||||||
|
self.error = True
|
||||||
|
return error
|
||||||
|
|
||||||
|
def read_and_set_new_mesh(self):
|
||||||
|
if not self.error:
|
||||||
|
fem_mesh = Fem.read(self.temp_file_mesh)
|
||||||
|
self.mesh_obj.FemMesh = fem_mesh
|
||||||
|
print(' The Part should have a pretty new FEM mesh!')
|
||||||
|
else:
|
||||||
|
print('No mesh was created.')
|
||||||
|
del self.temp_file_geometry
|
||||||
|
del self.temp_file_mesh
|
||||||
|
|
||||||
|
# @}
|
203
src/Mod/Fem/TaskPanelFemMeshGmsh.ui
Normal file
203
src/Mod/Fem/TaskPanelFemMeshGmsh.ui
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>GmshMesh</class>
|
||||||
|
<widget class="QWidget" name="GmshMesh">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>413</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>FEM Mesh by GMSH </string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="gb01_mesh_params">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>1677215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>FEM Mesh Parameter</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="formLayout_1">
|
||||||
|
<property name="fieldGrowthPolicy">
|
||||||
|
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||||
|
</property>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="l_dimension">
|
||||||
|
<property name="text">
|
||||||
|
<string>Mesh element dimension:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QComboBox" name="cb_dimension"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="l_order">
|
||||||
|
<property name="text">
|
||||||
|
<string>Mesh element order:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QComboBox" name="cb_order"/>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="l_max">
|
||||||
|
<property name="text">
|
||||||
|
<string>Max element size (0.0 = Auto):</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="Gui::InputField" name="if_max">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>80</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>0.0</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep" stdset="0">
|
||||||
|
<double>1.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="maximum" stdset="0">
|
||||||
|
<double>1000000000.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="unit" stdset="0">
|
||||||
|
<string notr="true">mm</string>
|
||||||
|
</property>
|
||||||
|
<property name="decimals" stdset="0">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="value" stdset="0">
|
||||||
|
<double>0.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="l_min">
|
||||||
|
<property name="text">
|
||||||
|
<string>Min element size (0.0 = Auto):</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="Gui::InputField" name="if_min">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>80</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>0.0</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep" stdset="0">
|
||||||
|
<double>1.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="maximum" stdset="0">
|
||||||
|
<double>1000000000.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="unit" stdset="0">
|
||||||
|
<string notr="true">mm</string>
|
||||||
|
</property>
|
||||||
|
<property name="decimals" stdset="0">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="value" stdset="0">
|
||||||
|
<double>0.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="gb03_run_gmsh">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>1677215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>GMSH</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="formLayout_2">
|
||||||
|
<property name="fieldGrowthPolicy">
|
||||||
|
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<layout class="QGridLayout" name="gl_actions">
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="l_time">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Time:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QTextEdit" name="te_output">
|
||||||
|
<property name="lineWrapMode">
|
||||||
|
<enum>QTextEdit::NoWrap</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>Gui::InputField</class>
|
||||||
|
<extends>QLineEdit</extends>
|
||||||
|
<header>Gui/InputField.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
170
src/Mod/Fem/_TaskPanelFemMeshGmsh.py
Normal file
170
src/Mod/Fem/_TaskPanelFemMeshGmsh.py
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
# ***************************************************************************
|
||||||
|
# * *
|
||||||
|
# * Copyright (c) 2016 - Bernd Hahnebach <bernd@bimstatik.org> *
|
||||||
|
# * *
|
||||||
|
# * This program is free software; you can redistribute it and/or modify *
|
||||||
|
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||||
|
# * as published by the Free Software Foundation; either version 2 of *
|
||||||
|
# * the License, or (at your option) any later version. *
|
||||||
|
# * for detail see the LICENCE text file. *
|
||||||
|
# * *
|
||||||
|
# * This program 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 Library General Public License for more details. *
|
||||||
|
# * *
|
||||||
|
# * You should have received a copy of the GNU Library General Public *
|
||||||
|
# * License along with this program; if not, write to the Free Software *
|
||||||
|
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||||
|
# * USA *
|
||||||
|
# * *
|
||||||
|
# ***************************************************************************
|
||||||
|
|
||||||
|
__title__ = "_TaskPanelFemMeshGmsh"
|
||||||
|
__author__ = "Bernd Hahnebach"
|
||||||
|
__url__ = "http://www.freecadweb.org"
|
||||||
|
|
||||||
|
## @package TaskPanelFemMeshGmsh
|
||||||
|
# \ingroup FEM
|
||||||
|
|
||||||
|
import FreeCAD
|
||||||
|
import time
|
||||||
|
import _FemMeshGmsh
|
||||||
|
import FreeCADGui
|
||||||
|
from PySide import QtGui
|
||||||
|
from PySide import QtCore
|
||||||
|
from PySide.QtCore import Qt
|
||||||
|
from PySide.QtGui import QApplication
|
||||||
|
|
||||||
|
|
||||||
|
class _TaskPanelFemMeshGmsh:
|
||||||
|
'''The TaskPanel for editing References property of FemMeshGmsh objects and creation of new FEM mesh'''
|
||||||
|
def __init__(self, obj):
|
||||||
|
self.mesh_obj = obj
|
||||||
|
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/TaskPanelFemMeshGmsh.ui")
|
||||||
|
|
||||||
|
self.Timer = QtCore.QTimer()
|
||||||
|
self.Timer.start(100) # 100 milli seconds
|
||||||
|
self.gmsh_runs = False
|
||||||
|
self.console_message_gmsh = ''
|
||||||
|
|
||||||
|
QtCore.QObject.connect(self.form.if_max, QtCore.SIGNAL("valueChanged(double)"), self.max_changed)
|
||||||
|
QtCore.QObject.connect(self.form.if_min, QtCore.SIGNAL("valueChanged(double)"), self.min_changed)
|
||||||
|
QtCore.QObject.connect(self.form.cb_dimension, QtCore.SIGNAL("activated(int)"), self.choose_dimension)
|
||||||
|
QtCore.QObject.connect(self.form.cb_order, QtCore.SIGNAL("activated(int)"), self.choose_order)
|
||||||
|
QtCore.QObject.connect(self.Timer, QtCore.SIGNAL("timeout()"), self.update_timer_text)
|
||||||
|
|
||||||
|
self.form.cb_dimension.addItems(_FemMeshGmsh._FemMeshGmsh.known_element_dimensions)
|
||||||
|
self.form.cb_order.addItems(_FemMeshGmsh._FemMeshGmsh.known_element_orders)
|
||||||
|
|
||||||
|
self.get_mesh_params()
|
||||||
|
self.get_active_analysis()
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def getStandardButtons(self):
|
||||||
|
return int(QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Close)
|
||||||
|
# show a apply and a close button
|
||||||
|
# def reject() is called on close button
|
||||||
|
# def clicked(self, button) is needed, to access the apply button
|
||||||
|
# def accept() in no longer needed, since there is no OK button
|
||||||
|
|
||||||
|
def reject(self):
|
||||||
|
FreeCADGui.ActiveDocument.resetEdit()
|
||||||
|
FreeCAD.ActiveDocument.recompute()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def clicked(self, button):
|
||||||
|
if button == QtGui.QDialogButtonBox.Apply:
|
||||||
|
self.run_gmsh()
|
||||||
|
|
||||||
|
def get_mesh_params(self):
|
||||||
|
self.clmax = self.mesh_obj.ElementSizeMax
|
||||||
|
self.clmin = self.mesh_obj.ElementSizeMin
|
||||||
|
self.order = self.mesh_obj.ElementOrder
|
||||||
|
self.dimension = self.mesh_obj.ElementDimension
|
||||||
|
|
||||||
|
def set_mesh_params(self):
|
||||||
|
self.mesh_obj.ElementSizeMax = self.clmax
|
||||||
|
self.mesh_obj.ElementSizeMin = self.clmin
|
||||||
|
self.mesh_obj.ElementOrder = self.order
|
||||||
|
self.mesh_obj.ElementDimension = self.dimension
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
'fills the widgets'
|
||||||
|
self.form.if_max.setText("{} mm".format(self.clmax))
|
||||||
|
self.form.if_min.setText("{} mm".format(self.clmin))
|
||||||
|
index_dimension = self.form.cb_dimension.findText(self.dimension)
|
||||||
|
self.form.cb_dimension.setCurrentIndex(index_dimension)
|
||||||
|
index_order = self.form.cb_order.findText(self.order)
|
||||||
|
self.form.cb_order.setCurrentIndex(index_order)
|
||||||
|
|
||||||
|
def console_log(self, message="", color="#000000"):
|
||||||
|
self.console_message_gmsh = self.console_message_gmsh + '<font color="#0000FF">{0:4.1f}:</font> <font color="{1}">{2}</font><br>'.\
|
||||||
|
format(time.time() - self.Start, color, message.encode('utf-8', 'replace'))
|
||||||
|
self.form.te_output.setText(self.console_message_gmsh)
|
||||||
|
self.form.te_output.moveCursor(QtGui.QTextCursor.End)
|
||||||
|
|
||||||
|
def update_timer_text(self):
|
||||||
|
# print('timer1')
|
||||||
|
if self.gmsh_runs:
|
||||||
|
print('timer2')
|
||||||
|
# print('Time: {0:4.1f}: '.format(time.time() - self.Start))
|
||||||
|
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
|
||||||
|
|
||||||
|
def max_changed(self, value):
|
||||||
|
self.clmax = float(value)
|
||||||
|
|
||||||
|
def min_changed(self, value):
|
||||||
|
self.clmin = float(value)
|
||||||
|
|
||||||
|
def choose_dimension(self, index):
|
||||||
|
if index < 0:
|
||||||
|
return
|
||||||
|
self.form.cb_dimension.setCurrentIndex(index)
|
||||||
|
self.dimension = str(self.form.cb_dimension.itemText(index)) # form returns unicode
|
||||||
|
|
||||||
|
def choose_order(self, index):
|
||||||
|
if index < 0:
|
||||||
|
return
|
||||||
|
self.form.cb_order.setCurrentIndex(index)
|
||||||
|
self.order = str(self.form.cb_order.itemText(index)) # form returns unicode
|
||||||
|
|
||||||
|
def run_gmsh(self):
|
||||||
|
QApplication.setOverrideCursor(Qt.WaitCursor)
|
||||||
|
self.Start = time.time()
|
||||||
|
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
|
||||||
|
self.console_message_gmsh = ''
|
||||||
|
self.gmsh_runs = True
|
||||||
|
self.console_log("We gone start ...")
|
||||||
|
self.get_active_analysis()
|
||||||
|
self.set_mesh_params()
|
||||||
|
import FemGmshTools
|
||||||
|
gmsh_mesh = FemGmshTools.FemGmshTools(self.obj, self.analysis)
|
||||||
|
self.console_log("Start GMSH ...")
|
||||||
|
error = gmsh_mesh.create_mesh()
|
||||||
|
if error:
|
||||||
|
print(error)
|
||||||
|
self.console_log('GMSH had warnings ...')
|
||||||
|
self.console_log(error, '#FF0000')
|
||||||
|
else:
|
||||||
|
self.console_log('Clean run of GMSH')
|
||||||
|
self.console_log("GMSH done!")
|
||||||
|
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
|
||||||
|
self.Timer.stop()
|
||||||
|
self.update()
|
||||||
|
QApplication.restoreOverrideCursor()
|
||||||
|
|
||||||
|
def get_active_analysis(self):
|
||||||
|
import FemGui
|
||||||
|
self.analysis = FemGui.getActiveAnalysis()
|
||||||
|
if self.analysis:
|
||||||
|
for m in FemGui.getActiveAnalysis().Member:
|
||||||
|
if m.Name == self.mesh_obj.Name:
|
||||||
|
print(self.analysis.Name)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
# print('Mesh is not member of active analysis, means no group meshing')
|
||||||
|
self.analysis = None # no group meshing
|
||||||
|
else:
|
||||||
|
# print('No active analyis, means no group meshing')
|
||||||
|
self.analysis = None # no group meshing
|
|
@ -72,8 +72,7 @@ class _ViewProviderFemMeshGmsh:
|
||||||
if FemGui.getActiveAnalysis().Document is FreeCAD.ActiveDocument:
|
if FemGui.getActiveAnalysis().Document is FreeCAD.ActiveDocument:
|
||||||
if self.Object in FemGui.getActiveAnalysis().Member:
|
if self.Object in FemGui.getActiveAnalysis().Member:
|
||||||
if not gui_doc.getInEdit():
|
if not gui_doc.getInEdit():
|
||||||
FreeCAD.Console.PrintError('TaskPanel test not yet implemented\n')
|
gui_doc.setEdit(vobj.Object.Name)
|
||||||
# gui_doc.setEdit(vobj.Object.Name)
|
|
||||||
else:
|
else:
|
||||||
FreeCAD.Console.PrintError('Activate the analysis this mesh belongs to!\n')
|
FreeCAD.Console.PrintError('Activate the analysis this mesh belongs to!\n')
|
||||||
else:
|
else:
|
||||||
|
@ -84,8 +83,7 @@ class _ViewProviderFemMeshGmsh:
|
||||||
if m == self.Object:
|
if m == self.Object:
|
||||||
FemGui.setActiveAnalysis(o)
|
FemGui.setActiveAnalysis(o)
|
||||||
print('Analysis the Mesh belongs too was activated.')
|
print('Analysis the Mesh belongs too was activated.')
|
||||||
FreeCAD.Console.PrintError('TaskPanel test not yet implemented\n')
|
gui_doc.setEdit(vobj.Object.Name)
|
||||||
# gui_doc.setEdit(vobj.Object.Name)
|
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
FreeCAD.Console.PrintError('Active Analysis is not in active Document!\n')
|
FreeCAD.Console.PrintError('Active Analysis is not in active Document!\n')
|
||||||
|
@ -97,8 +95,7 @@ class _ViewProviderFemMeshGmsh:
|
||||||
if m == self.Object:
|
if m == self.Object:
|
||||||
FemGui.setActiveAnalysis(o)
|
FemGui.setActiveAnalysis(o)
|
||||||
print('Analysis the Mesh belongs too was activated.')
|
print('Analysis the Mesh belongs too was activated.')
|
||||||
FreeCAD.Console.PrintError('TaskPanel test not yet implemented\n')
|
gui_doc.setEdit(vobj.Object.Name)
|
||||||
# gui_doc.setEdit(vobj.Object.Name)
|
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
print('Mesh GMSH object does not belong to an analysis. Group meshing will is deactivated.')
|
print('Mesh GMSH object does not belong to an analysis. Group meshing will is deactivated.')
|
||||||
|
|
Loading…
Reference in New Issue
Block a user