[WTF Abaqus] odb节点坐标序号问题&获取节点变形后位置
结论写在前面:在visualization界面中处理odb的时候,用.fieldOutputs输出的顺序是由每个part的nodeLable按顺序叠起来的,其[0]号元素一定是ASSEMBLY的[1]号nodeLable(或者你的Part的名字比ASSEMBLY还靠前)。
之前有给大家介绍过
[WTF Abaqus]更加人性化的宏/脚本开头;获取当前模型名称并提示 - 空集先生的文章 - 知乎 https:// zhuanlan.zhihu.com/p/84 749135
这里给大家一个odb用的
viewportName = session.currentViewportName
odbname=session.viewports[viewportName].displayedObject.name
odb = session.odbs[odbname]
然后就可以直接使用odb来代指当前模型了(用来取某个part的节点之类的),还能使用viewportName来代指视口(用来切换当前显示的内容,包括pathXYdata也需要用到)
因为某个老铁经常做着从某一step某一帧提取某几个节点的坐标再放到excel里计算一堆公式得到结果再根据结果创建路径再提取路径的XYdata这样重复的操作……我就跟他一起研究了一下odb中用python进行提取节点坐标的方法。
在手动提取的时候我们都是使用查询(query)-距离-点选两个节点来获得距离。但rpy档里并没有录入query相关的指令,只有最终结果
#: 结点: Part-1.42
#: 1 2 3 大小
#: 基本坐标: 3.21734e+002, 3.21734e+002, -6.17900e+003, -
#: 缩放: 8.13296e+002, 8.13296e+002, 8.13296e+002, -
#: 变形后的坐标 (未缩放): 3.21767e+002, 3.21767e+002, -6.17911e+003, -
#: 变形后的坐标 (已缩放): 3.49214e+002, 3.49214e+002, -6.26671e+003, -
#: 位移 (未缩放): 3.37883e-002, 3.37883e-002, -1.07846e-001, 1.17957e-001
#: 结点: Part-1.1875
#: 1 2 3 大小
#: 基本坐标: 3.36819e+002, 3.36819e+002, -6.17900e+003, -
#: 缩放: 8.13296e+002, 8.13296e+002, 8.13296e+002, -
#: 变形后的坐标 (未缩放): 3.36855e+002, 3.36855e+002, -6.17909e+003, -
#: 变形后的坐标 (已缩放): 3.66439e+002, 3.66439e+002, -6.24951e+003, -
#: 位移 (未缩放): 3.64204e-002, 3.64204e-002, -8.67009e-002, 1.00846e-001
#: 待测距的结点: Part-1.42, Part-1.1875
#: 1 2 3 大小
#: 基本距离: 1.50850e+001, 1.50850e+001, 0.00000e+000, 2.13334e+001
#: 缩放: 8.13296e+002, 8.13296e+002, 8.13296e+002, -
#: 变形后的距离(未缩放): 1.50876e+001, 1.50876e+001, 2.09961e-002, 2.13371e+001
#: 变形后的距离(已缩放): 1.72256e+001, 1.72256e+001, 1.71968e+001, 2.98190e+001
#: 相对位移 (未缩放的): 2.63205e-003, 2.63205e-003, 2.11446e-002, 2.14698e-002
这就尴了™的尬,还想着给老铁装个逼一条语句搞定坐标,看来query是搞不定了
后来看我看到了这个帖子(我看的是纯机翻+搬运的,所以没找到原址 就不放了)
获取位移字段:
u = odb.steps ['Step-1']。frames [-1] .fieldOutputs ['U']
thenu.values
是所有节点值的列表:
u.values [i] .data - >(ux,uy,uz)数组
u.values [i] .nodeLabel - >节点标签
然后你抓住原来的位置,像这样:
instance.getNodeFromLabel(u.values [i] .nodeLabel).coordinates
您也可以直接获取变形坐标作为字段输出,但在运行分析时需要请求COORD
输出。
用于获取节点原始坐标:
odb.rootAssembly.instances[partName].getNodeFromLabel(xxxx).coordinates
用于获取位移表:
u = odb.steps[xxx].frames[xxxx].fieldOutputs['U']
u.values[xxxxx].data #获取第xxxxx个u的值(xxxxx为总节点编号)
u.values[xxxxx].nodeLabel #反查这个值对应的节点编号(总)
原始坐标+截止这步之前的XYZ位移=当前坐标
那我们就根据这个来扩展一下
- 首先简化一下odb.rootAssembly.instances[partName] -> currentPart
partName=getInput('Which part do you want to operate?',odb.rootAssembly.instances.keys()[1])
currentPart=odb.rootAssembly.instances[partName]
上述语句会询问你要处理哪个Part,需要注意因为我需要提取的节点都是来自同一个part才会这么写,如果你需要用到不同part的节点则需要一些修改。
odb.rootAssembly.instances.keys()[1]是获取odb里面的实体里所有名称的第2个(第一个通常是ASSEMBLY),这里用的是getInput的形式以免第2个部件不是想要取点的部件。
- 获取位移语句u = odb.steps[xxx].frames[xxxx].fieldOutputs['U']中有用到step名字,我们为了自动化一点也加个自动获取step名称
LastStepName=odb.steps.keys()[-1]
牢记.keys()指令,它可以显示每个项目的名称,举个例子
>>> print(odb.steps)
{'Static': 'OdbStep object'}
>>> print(odb.steps.keys())
['Static']
>>> odb.steps.keys()
['Static']
>>> odb.steps.keys()[-1]
'Static'
这里[-1]代表了odb.steps.keys()列表里的最后一个值,返回了最后一个step的字符串名称
- 以防出现什么问题,还是按操作习惯把当前视口输出变量设成了U1
session.viewports[viewportName].odbDisplay.setPrimaryVariable(
variableLabel='U', outputPosition=NODAL, refinement=(COMPONENT, 'U1'))
- 因为要做多个帧的,这里还是先给循环开个头
frameChooses=[50,100,150] # User Defin
for frameChoose in frameChooses:
后面语句从这写
- 获取u的数据表
u = odb.steps[LastStepName].frames[frameChoose].fieldOutputs['U']
这个时候不建议print(u.values)来看结构,因为节点贼叽霸多,可能会让odb卡死
建议print(u.values[0])、[1]这样的一个一个看
>>> print(u.values[0])
({'baseElementType': '', 'conjugateData': None, 'conjugateDataDouble': 'unknown', 'data': array([0.084111288189888, 0.141214072704315, 0.12014888972044], 'f'), 'dataDouble': 'unknown', 'elementLabel': None, 'face': None, 'instance': None, 'integrationPoint': None, 'inv3': None, 'localCoordSystem': None, 'localCoordSystemDouble': 'unknown', 'magnitude': 0.203597351908684, 'maxInPlanePrincipal': None, 'maxPrincipal': None, 'midPrincipal': None, 'minInPlanePrincipal': None, 'minPrincipal': None, 'mises': None, 'nodeLabel': 1, 'outOfPlanePrincipal': None, 'position': NODAL, 'precision': SINGLE_PRECISION, 'press': None, 'sectionPoint': None, 'tresca': None, 'type': VECTOR})
可以看到里面.data是一个array存放着我们想要的数据,.nodeLabel是1
>>> print(u.values[0].data)
[ 0.08411129 0.14121407 0.12014889]
>>> print(u.values[0].nodeLabel)
1
但是我们看看[1]的数据
>>> print(u.values[1])
({'baseElementType': '', 'conjugateData': None, 'conjugateDataDouble': 'unknown', 'data': array([-0.030674746260047, 0.0737588480114937, -0.0163534730672836], 'f'), 'dataDouble': 'unknown', 'elementLabel': None, 'face': None, 'instance': 'OdbInstance object', 'integrationPoint': None, 'inv3': None, 'localCoordSystem': None, 'localCoordSystemDouble': 'unknown', 'magnitude': 0.0815398320555687, 'maxInPlanePrincipal': None, 'maxPrincipal': None, 'midPrincipal': None, 'minInPlanePrincipal': None, 'minPrincipal': None, 'mises': None, 'nodeLabel': 1, 'outOfPlanePrincipal': None, 'position': NODAL, 'precision': SINGLE_PRECISION, 'press': None, 'sectionPoint': None, 'tresca': None, 'type': VECTOR})
>>> print(u.values[1].data)
[-0.03067475 0.07375885 -0.01635347]
>>> print(u.values[1].nodeLabel)
1
这™的,为什么[1]的nodeLabel也是1??
>>> print(u.values[2].nodeLabel)
2
>>> print(u.values[3].nodeLabel)
3
为什么后面就续上了??
这里就是说明了开头那句话,u里面的顺序是按part顺序排的
u.values[0] <-> Assembly的1号节点(一般来说全非独立网格只有1个节点)
u.values[1] <-> 第一个部件的1号节点
u.values[2] <-> 第一个部件的2号节点
……
u.values[x] <-> 某个部件的(x-前面节点总和)号节点
还是那个问题,用户使用查询query功能可以很清楚地得知这个节点在part上的编号,但是如果有多个part,那么
- u.values[number]的number
- part的第number个节点
这俩number就不是一个数!
这个例子中Part-1之前只有Assembly的1个节点,我们输出一下part-1的第一个节点看看
>>> odb.rootAssembly.instances[Part-1].getNodeFromLabel(1).coordinates
array([-445.477264404297, 445.477264404297, -5651.5], 'f')
(查询指令)
#: 结点: Part-1.1
#: 1 2 3 大小
#: 基本坐标: -4.45477e+002, 4.45477e+002, -5.65150e+003, -
#: 缩放: 8.13296e+002, 8.13296e+002, 8.13296e+002, -
#: 变形后的坐标 (未缩放): -4.45508e+002, 4.45551e+002, -5.65152e+003, -
#: 变形后的坐标 (已缩放): -4.70425e+002, 5.05465e+002, -5.66480e+003, -
#: 位移 (未缩放): -3.06747e-002, 7.37588e-002, -1.63535e-002, 8.15398e-002
可以看到Part-1的1号节点的基本坐标经query和经python指令得到的值是一样的
Part-1的1号节点在对应关系中应该是u.values[1].data,我们看一下是否一致
>>> u.values[1].data
array([-0.030674746260047, 0.0737588480114937, -0.0163534730672836], 'f')
可以看到python指令正确输出了位移
假如我有part1,part2,part3,分别有节点10,20,30个,想输出part3的第13个节点的基本坐标和位移应该用什么指令呢?
坐标:odb.rootAssembly.instances[Part3].getNodeFromLabel(13).coordinates
位移:u.values[-1+1+10+20+13].data
这里面-1是因为从0计数,+1是assembly的节点数,+10是part1的节点数,+20是part2的节点数,+13是part3的第13个节点。这样能理解吗?
刚刚用了很长一段文字说明fieldOutputs的结果和query查询节点的对应关系,还给出了获取给定节点坐标和位移的语句,那么后续只要坐标+位移就可以得到节点当前位置继而进行下一步操作了。
需要注意,6.14版本中可以数组直接相加Array1+Array2代表对项相加,但是6.12版本的尝试中发现不能直接相加,因此还是采用了(Array1[0]+Array2[0],Array1[1]+Array2[1],Array1[2]+Array2[2])的写法
到这里最关键的地方——获取节点变形后位置——就讲完了,后面就是计算出一个用于生产路径的点然后创建路径,输出pathXYdata了,这些内容因为会出现在.rpy档里,所以我就不细讲了,而且不同abaqus版本可能语句也略有不同,因此建议大家自行提取.rpy档
6.12:
session.Path(name='Path-'+str(i)+'_frame_'+str(frameChoose), type=POINT_LIST, expression=((Point1AfterCoor[0], Point1AfterCoor[1],
Point1AfterCoor[2]), (PointEndChangeCoor[0], PointEndChangeCoor[1], PointEndChangeCoor[2])))
pth = session.paths['Path-'+str(i)+'_frame_'+str(frameChoose)]
session.viewports[session.currentViewportName].odbDisplay.setFrame(
step=LastStepName, frame=frameChoose)
session.XYDataFromPath(name='Path-'+str(i)+'_frame_'+str(frameChoose), path=pth, includeIntersections=True,