用python替换odb中的状态变量名

时间:2016-04-22 09:21:14

标签: python string binary abaqus

在Abaqus中,我有自己的材料描述(VUMAT)。此VUMAT生成名为SDV1,SDV2等的状态变量。这些变量存储在二进制.odb文件中,其他输出数据存储在abaqus中。因为我有大量的这些我想给他们有意义的名字,如S1,S2,E1,E2等所以当在Abaqus观察器中查看.odb时,很清楚哪个变量是哪个。

现在,abaqus提供了python接口来读取和写入该.odb文件。但就我可以搜索而言,我无法找到重命名那些变量。当我尝试更改它们时,我得到只读错误。

因此,我尝试用Notepad ++打开.odb并发现如果手动将该文件中的所有SDV条目替换为我想要的并保存它。名称也会在Abaqus Viewer中更改。那太好了!

但我想自动化这个过程。所以我编写了一个python脚本来读取最初的.odb,替换SDV并将更改后的.odb保存为不同的文件。

import sys
with open('User.odb','rb') as f:
    content = f.read()
    if b"SDV2" in content:
        print('Found')
        content = content.replace(b'SDV2',b'works')
with open('User.temp.odb','wb') as fw:
    fw.write(content)

但是当我在abaqus查看器中打开新的.odb时,我收到以下消息:

  

***错误:Abaqus数据库文件已损坏。如果此文件是使用FTP或同等文件从另一台计算机传输的,请确保   使用二进制模式而不是ASCII模式复制文件。

而且,目前这个代码还取代了SDV20,如何避免这种情况,只更换SDV2而不是SDV20,SDV21等部分?

我缺少什么?我正在使用python 2.7。

修改

如果在HEX编辑器中打开ODB,可以看到以下模式: 对于SDV9,然后是SDV10:

04 53 44 56 39 00 00 00 05 53 44 56 31 30 00 00 00 00 00 00  

可以观察到编码以字符数开始。 04表示SDV9,05表示SDV10,后跟NULL值。 SDV1至SDV9为3,其余为6。我尝试将SDV9部分改为:

05 53 44 56 39 00 00 00 00 00 00 00

它给了我同样的错误,同时将SDV10部分改为:

05 53 44 56 39 00 00 00 00 00 00 00

完美无缺。如果有人熟悉这一点,我们将不胜感激。

EDIT2:

我的代码不起作用,因为新变量应该与旧变量的长度完全相同。如果长度匹配则没有问题。较短的变量可以在它们后面有空格以获得所需的字符长度。

通过使用SSchneid建议的代码,我能够匹配准确的SDV以进行替换,而不包括较长的部分。

添加涉及FieldOutput()和addData()的字段变量的标准方法不是一个很好的解决方案,因为它复制了现有的具有不同名称的SDV。对于非常大的分析,它大大增加了odb的大小。除非有办法删除旧的。

当然,我们可以通过直接从子程序将所需变量输出到单独的文本文件来进一步发展。然后通过使用该文本文件在odb内生成新的Field输出。之后可以删除文本文件。而这一切都没有请求SDV输出。

或者可以向.fil文件请求SDV输出,然后可以使用FieldOutput()和addData()将其组合回odb。但这些是非常hacky的解决方案,需要大量写入磁盘和许多行代码来解析输出文本文件。

我要离开这个步骤,直到找到一个完整的解决方案或者我自己想出来(在这种情况下我会发布一个答案兔子)

感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

问题是,您匹配以SDV2开头的所有内容。这意味着无论如何,开头SDV2的所有内容都将返回正数。

在我看来,解决匹配问题的最佳方法是使用带有re:

的正则表达式
import re
import sys
with open('User.odb','rb') as f:
    content = f.read()
    content = re.sub('\\bSDV2\\b', 'works', content)
with open('User.temp.odb','wb') as fw:
    fw.write(content)

我打赌有一种方法可以不用你提出的方式来做到这一点。

答案 1 :(得分:1)

您的方法非常有创意,但有一个"标准"使用Abaqus Python API实现目标的方法:

frame.FieldOutput(name='works', description='this is a vector', type=VECTOR).addData(position=INTEGRATION_POINT, instance=grout_instance, labels=elementLabels, data=elementData)

在您的代码中,我发现了两个可能的错误:

  1. 旧名称和新名称的长度(' SDV2''工作')不匹配。
  2. ODB文件的二进制数据部分可能包括4个意外匹配的SDV2'的后续字节。在这种情况下,您的脚本会覆盖这些字节并破坏整个文件。
  3. EDIT1

    1. 由于Abaqus没有提供删除现有字段的任何方法(出于他们所说的一致性原因),如果您希望使用addData方法防止重复,则需要创建一个新的ODB并复制那里的字段。然后你可以删除旧文件。我们已经使用这种方法一年了。好处是你可以从不同的SDV创建矢量或张量,以便更好地进行视觉化。

    2. 要修复我之前调整的可能错误(长度不匹配和意外替换),您可以使用find代替replace

    3. 您可以尝试此代码

      content = bytearray(content)
      old2new={b'SDV2':b'work'} # add more renaming patterns as you need
      for oldn, newn in old2new.items():
        i = content.find(oldn) 
        # or using regex pattern:
        # re.search(oldn, content).start()
        content[i:i+len(newn)] = newn
      

      其他代码遵循您的脚本。我假设您只需要替换文件中每个名称的一个出现。否则,请使用re的{​​{3}}方法。