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

用python替换odb中的状态变量名,python,string,binary,abaqus,Python,String,Binary,Abaqus,在Abaqus中,我有自己的材料描述(VUMAT)。此VUMAT生成名为SDV1、SDV2等的状态变量。这些变量与abaqus中的其他输出数据一起存储在binary.odb文件中。因为我有很多这样的变量,所以我想给它们起个有意义的名字,比如S1、S2、E1、E2等等。所以当在Abaqus查看器中查看.odb时,可以清楚地知道哪个变量是哪个变量 现在,abaqus提供了python接口来读取和写入该.odb文件。但就我所能搜索的范围而言,我无法找到一个方法来重命名这些变量。当我试图更改它们时,会出

在Abaqus中,我有自己的材料描述(VUMAT)。此VUMAT生成名为SDV1、SDV2等的状态变量。这些变量与abaqus中的其他输出数据一起存储在binary.odb文件中。因为我有很多这样的变量,所以我想给它们起个有意义的名字,比如S1、S2、E1、E2等等。所以当在Abaqus查看器中查看.odb时,可以清楚地知道哪个变量是哪个变量

现在,abaqus提供了python接口来读取和写入该.odb文件。但就我所能搜索的范围而言,我无法找到一个方法来重命名这些变量。当我试图更改它们时,会出现只读错误

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

但我想让这个过程自动化。因此,我编写了一个python脚本来读取初始的.odb,替换SDV并将alterned.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 viewer中打开新的.odb时,我得到以下消息:

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

此外,目前,该代码还替代了SDV20,如何避免这种情况并仅替换SDV2而不是SDV20、SDV21等的一部分

我错过了什么?我正在使用python 2.7

编辑:

如果在十六进制编辑器中打开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,后跟空值。SDV1至SDV9为3,其余为6。我尝试将SDV9部件更改为:

05 53 44 56 39 00 00 00 00 00 00 00
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
05 53 44 56 39 00 00 00 00 00 00 00
很好用。如果有人熟悉这一点,将不胜感激

EDIT2:

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

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

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

当然,我们可以更进一步,直接从子例程将想要的变量输出到一个单独的文本文件。然后使用该文本文件在odb内生成新的字段输出。文本文件可以在以后删除。所有这些都不需要SDV输出

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

我不回答这个问题,直到发布一个完整的解决方案,或者我自己解决(在这种情况下,我会发布一个答案)


谢谢你的帮助

问题是,您需要匹配以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)

我敢打赌,有一种方法可以做到这一点,而不必按照您提出的方式进行re。

您的方法非常有创意,但有一种“标准”方法可以使用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)
在您的代码中,我观察到两个可能的错误:

  • 新旧名称(“SDV2”和“works”)的长度不匹配
  • ODB文件的二进制数据部分可能包括4个意外匹配“SDV2”的后续字节。在这种情况下,脚本会覆盖这些字节并损坏整个文件
  • 编辑1
  • 由于Abaqus不提供任何删除现有字段的方法(如他们所说,出于一致性原因),如果您想使用
    addData
    方法防止重复,则需要创建一个新的ODB并将字段复制到那里。然后可以删除旧文件。我们已经使用这种方法一年了。好处是,您可以从不同的SDV创建向量或张量,以便更好地可视化

  • 要修复之前标注的可能错误(长度不匹配和意外替换),可以使用
    find
    而不是
    replace

  • 你可以试试这个代码

    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

    的方法是的,确实,你的方法完全取代了我想要的。但是,Abaqus查看器仍然会给出错误消息。这太奇怪了,因为如果我用手做的话就没事了。与在记事本++中编辑相比,python中的读写操作保存的内容有什么不同?对我来说,虽然我不是专家,但这听起来像是一个编码问题,但由于我没有使用Abaqus viewer的经验,这只是一个猜测。显然,它必须具有与初始字符串相同的长度。否则就不行了。如果新字符串较短,我可以用空格替换其他字符。如果我的新字符串更长,目前我无能为力。尽管abaqus对某些变量使用了更长的名称。记事本++方法之所以有效,是因为我尝试用“works”替换“SDV10”,并且两者的字符数相同。我想知道关于字符长度的信息存储在哪里。在您的代码
    b'SDV2'
    b'works'
    中有不同的