【VTK+有限元后处理】可视化结果云图

构建vtkUnstructuredGrid对象

为了读取不同格式的有限元计算结果文件,我们先写一个FEDataModel类来管理有限元的几何拓扑和属性信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
class FEDataModel:
"""有限元数据模型类"""

def __init__(self):
self.nodes = [] # 节点几何坐标
self.elements = [] # 单元拓扑信息
self.scalars = {} # 节点标量属性
self.vectors = {} # 节点向量属性
self.ugrid = vtk.vtkUnstructuredGrid() # 用于VTK可视化的数据模型
self.ugrid.Allocate(100)

def read_inp(self, filename):
with open(filename) as f:
node_flag, element_flag = False, False
for line in f.readlines():
line = line.replace('\n', '').replace(' ', '')
if '*ELEMENT' in line:
node_flag, element_flag = False, True
continue
elif '*NODE' in line:
node_flag, element_flag = True, False
continue
elif '*' in line:
node_flag, element_flag = False, False
continue
if node_flag:
self.nodes.append(list(map(lambda x: float(x), line.split(',')))[1:])
elif element_flag:
self.elements.append(list(map(lambda x: int(x) - 1, line.split(',')))[1:])
# print(len(self.nodes), len(self.elements))

nodes = vtk.vtkPoints()
for i in range(0, len(self.nodes)):
nodes.InsertPoint(i, self.nodes[i])

for i in range(0, len(self.elements)):
if len(self.elements[i]) == 4: # 四面体单元
self.ugrid.InsertNextCell(vtk.VTK_TETRA, 4, self.elements[i])
elif len(self.elements[i]) == 6: # 六面体单元
self.ugrid.InsertNextCell(vtk.VTK_POLYGON, 6, self.elements[i])
elif len(self.elements[i]) == 3: # 三角面片单元
self.ugrid.InsertNextCell(vtk.VTK_TRIANGLE, 3, self.elements[i])
else:
print("FEDataModel构建中遇到错误单元类型!")
self.ugrid.SetPoints(nodes)

def read_ntl(self, filename):
with open(filename) as f:
lines = f.readlines()
attribute_name = ''.join(lines[0].split(' ')[1:-1])
scalar = []
for line in lines[4:]:
line = line.replace('\n', '').split(' ')
scalar.append(float(line[-1]))
self.scalars[attribute_name] = scalar
# print(attribute_name + ' scalar number: ' + str(len(scalar)))

# 存储标量值
scalars = vtk.vtkFloatArray()
scalars.SetName(attribute_name)
for i in range(0, len(scalar)):
scalars.InsertTuple1(i, scalar[i])
# 设定每个节点的标量值
self.ugrid.GetPointData().SetScalars(scalars)

def display(self):
renderer = vtk.vtkRenderer()
renWin = vtk.vtkRenderWindow()
renWin.AddRenderer(renderer)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)

colors = vtk.vtkNamedColors()
ugridMapper = vtk.vtkDataSetMapper()
ugridMapper.SetInputData(self.ugrid)

ugridActor = vtk.vtkActor()
ugridActor.SetMapper(ugridMapper)
ugridActor.GetProperty().SetColor(colors.GetColor3d("Peacock"))
ugridActor.GetProperty().EdgeVisibilityOn()

renderer.AddActor(ugridActor)
renderer.SetBackground(colors.GetColor3d("Beige"))

renderer.ResetCamera()
renderer.GetActiveCamera().Elevation(60.0)
renderer.GetActiveCamera().Azimuth(30.0)
renderer.GetActiveCamera().Dolly(1.2)
renWin.SetSize(640, 480)
# Interact with the data.
renWin.Render()
iren.Start()

这个类的作用是,方便我们读取并构建用于在VTK中显示的vtkUnstructuredGrid类对象。vtkUnstructuredGrid类是VTK中的非结构化网格类,可用于有限元分析、计算几何和几何建模这类领域。

vtkUnstructuredGrid类详情参见:VTK笔记-使用vtkUnstructuredGrid类构建非结构化数据

其中read_inp成员函数和read_ntl成员函数分别用于读取从ProCAST软件中导出的inp文件(存储有限元的几何拓扑数据)和ntl文件(存储有限元的节点属性数据,如温度、应力等)。

存储vtkUnstructuredGrid对象

为了能一次性读取有限元模型整体数据,我们可以将其保存为vtk格式的文件。

1
2
3
4
5
writer = vtk.vtkUnstructuredGridWriter()
writer.SetFileName(save_fn)
writer.SetInputData(self.FEModel.ugrid)
writer.Write()
writer.Update()

下一次只需读取对应的vtk文件即可。

1
2
3
4
reader = vtk.vtkUnstructuredGridReader()
reader.SetFileName(read_fn)
reader.Update()
self.FEModel.ugrid = reader.GetOutput()

云图可视化

可视化节点属性数据(标量场),关键代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def drawScalarField(self, scalar_mapper, scalarRange, title):
# 定义颜色映射表
lut = vtk.vtkLookupTable()
lut.SetHueRange(0.67, 0.0) # 色调范围从红色到蓝色
# lut.SetAlphaRange(1.0, 1.0) # 透明度范围
# lut.SetValueRange(1.0, 1.0)
# lut.SetSaturationRange(1.0, 1.0) # 颜色饱和度
# lut.SetNumberOfTableValues(256)
lut.SetNumberOfColors(256) # 颜色个数
# lut.SetRange(scalarRange)
lut.Build()

scalar_mapper.SetScalarRange(scalarRange)
scalar_mapper.SetLookupTable(lut)
scalar_actor = vtk.vtkActor()
scalar_actor.SetMapper(scalar_mapper)
self.renderer.AddActor(scalar_actor)
# 色标带
scalarBar = vtk.vtkScalarBarActor()
scalarBar.SetLookupTable(scalar_mapper.GetLookupTable()) # 将颜色查找表传入窗口中的色标带
scalarBar.SetTitle(title)
scalarBar.SetNumberOfLabels(5)
self.renderer.AddActor2D(scalarBar)

结果展示

![GIF 2022-11-18 23-13-41](D:\OneDrive\桌面\GIF 2022-11-18 23-13-41.gif)