添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
含蓄的木耳  ·  Blazor入门100天 : ...·  1 年前    · 
[WTF Abaqus] odb节点坐标序号问题&获取节点变形后位置

[WTF Abaqus] odb节点坐标序号问题&获取节点变形后位置

2 年前

结论写在前面:在visualization界面中处理odb的时候,用.fieldOutputs输出的顺序是由每个part的nodeLable按顺序叠起来的,其[0]号元素一定是ASSEMBLY的[1]号nodeLable(或者你的Part的名字比ASSEMBLY还靠前)。


之前有给大家介绍过

[WTF Abaqus]更加人性化的宏/脚本开头;获取当前模型名称并提示 - 空集先生的文章 - 知乎 zhuanlan.zhihu.com/p/84

这里给大家一个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']
then u.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,那么

  1. u.values[number]的number
  2. 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,