NASTRAN的计算输入文件是BDF文件,输出文件一般是XDB,OP2或HDF5,也会有文本的F06可以输出。通常PATRAN可以进行这些文件的后处理,但PATRAN的后处理显示效果并不好,也没有slice,clip,半透明等显示效果,只能做一些基本的后处理显示,PARAVIEW对数据的后处理能力要强大得到,可以做出各类效果以达到深入观察结果分布和规律的效果。为此,将NASTRAN的计算结果在PARAVIEW中进行处理将会大大提高后处理的效果。
PARAVIEW支持读入BDF文件和f06文件。
其中BDF文件需要将后缀改为NAS后方可读入,但读入后是一个mesh数据,如果需要将后处理结果再导入则无法找到对应单元,因而这个BDF接口并不好用。
而NASTRAN生成的f06文件实际上并不能成功解析。
另外,python中有一个pyNastran库,这个库中的op2包中提供一个export_to_vtk模块可以根据bdf文件和op2文件生成vtk文件,但这个库的成功率并不高。
为方便使用,使用python基于vtk库和pyNastran库编写一个bdf转vtk文件的程序以生成一个可被paraview直接读入的vtk文件,之后再在paraview中借助ProgrammableFilter将需要后处理的结果添加进去
将bdf文件转换为vtk文件
import pyNastran.bdf.bdf as pb
import vtk
#读取bdf文件的节点号和坐标,单元号及连接的节点号
bdfModel = pb.read_bdf(r'D:\WORK\MSC_WORK\T02.bdf')
nodes = {}; elms = {}; nodesIndex = {}; elmsIndex = {}
i = 0
for nodeId in bdfModel.node_ids:
nodes[nodeId] = bdfModel.nodes[nodeId].xyz
nodesIndex[nodeId] = i
i += 1
i = 0
for elmId in bdfModel.element_ids:
elms[elmId] = bdfModel.elements[elmId].node_ids
elmsIndex[elmId] = i
i += 1
#创建VTK中的节点pts,单元拓扑连接信息Cell,节点号数据nidData,单元号数据eidData,并将这些数据全部写入VTK网格polyData中
pts = vtk.vtkPoints(); pts.Allocate(len(nodes))
polyData = vtk.vtkPolyData(); polyData.Allocate(len(elms))
nidData = vtk.vtkIntArray()
nidData.SetName("nId")
eidData = vtk.vtkIntArray()
eidData.SetName("eId")
for nid in nodes:
pts.InsertNextPoint(nodes[nid])
nidData.InsertNextValue(nid)
for elmId in elms:
if len(elms[elmId]) == 2:
nIndexs = []
for nid in elms[elmId]:
nIndexs.append(nodesIndex[nid])
polyData.InsertNextCell(vtk.VTK_LINE, 2, nIndexs)
eidData.InsertNextValue(elmId)
for elmId in elms:
if len(elms[elmId]) == 3:
nIndexs = []
for nid in elms[elmId]:
nIndexs.append(nodesIndex[nid])
polyData.InsertNextCell(vtk.VTK_TRIANGLE, 3, nIndexs)
eidData.InsertNextValue(elmId)
for elmId in elms:
if len(elms[elmId]) == 4:
nIndexs = []
for nid in elms[elmId]:
nIndexs.append(nodesIndex[nid])
polyData.InsertNextCell(vtk.VTK_QUAD, 4, nIndexs)
eidData.InsertNextValue(elmId)
polyData.SetPoints(pts)
polyData.GetPointData().AddArray(nidData)
polyData.GetCellData().AddArray(eidData)
#写出vtkPolyData到VTK文件中
writer = vtk.vtkPolyDataWriter()
writer.SetFileName(r"D:\WORK\PARA_WORK\T02.vtk")
writer.SetInputData(polyData)
writer.Write()
在这个过程中需要注意的是:
- 需要在VTK文件中记录节点和单元的ID号数据(此处数据名称分别使用nId和eId),因为后续导入结果时需要通过单元号或节点号来对应;
- VTK文件的对单元和单元数据的对应关系是通过其索引来实现的,这个索引并不是一个显式可指定的,基本上是其是文件中的顺序。
- 对于同一个VTK文件中有多种不同的单元类型时,如既有梁单元,也有三角形单元和四边形单元,那么VTK解析时会先排二节点的梁单元,再排三节点/四节点的三角形/四边形单元,即使你在VTK文件中手动把梁单元放在三角形/四边形单元后面也不会改变这个顺序。因而在上述程序中用了三个循环来依次写入三种不同类型的单元和相应的数据。
这个模型中既有梁单元,也有四边形单元,导入后显示的单元号效果如下图所示。
将结果数据导入PARAVIEW
在paraview中以上述导入的VTK为输入创建一个ProgrammableFilter过滤器,并编写一个Python脚本,该脚本将读取VTK文件中的单元号和节点号数据,并将其作为输入,然后根据单元号和节点号数据来读取相应的应力和位移数据,并将这些数据写入VTK文件中。
import re
#读取结果数据和相应的单元号
resData = {}
with open(r"D:\WORK\PARA_WORK\testElmData.txt", 'r') as finp:
for line in finp:
datas = re.split(r'\s+', line.strip())
resData[int(datas[0])] = float(datas[1])
#获取输入源单元索引及对应的单元号elmIds并将结果数据按索引顺序写入resVtkData中
elmIds = inputs[0].GetCellData().GetArray("eId")
elmCnt = elmIds.GetNumberOfTuples()
resVtkData = vtk.vtkDoubleArray()
resVtkData.SetName("VM")
for i in range(elmCnt):
elmId = elmIds.GetValue(i)
if elmId in resData:
resVtkData.InsertNextValue(resData[elmId])
else:
resVtkData.InsertNextValue(0.0)
#将结果数据resVtkData添加到输入
output.GetCellData().AddArray(resVtkData)
导入结果后效果