【问题标题】:Accelerate a slow loop in Abaqus-python code for extracting strain data from .odb file加速 Abaqus-python 代码中的慢循环,以从 .odb 文件中提取应变数据
【发布时间】:2017-10-04 20:51:13
【问题描述】:

我有一个名为 plate2.odb 的 .odb 文件,我想从中提取应变数据。为此,我构建了下面的简单代码,该代码循环遍历每个元素的字段输出 E(应变)并将其保存到列表中。

from odbAccess import openOdb
import pickle as pickle

# import database
odbname = 'plate2'
path = './'
myodbpath = path + odbname + '.odb'
odb = openOdb(myodbpath)

# load the strain values into a list
E = []
for i in range(1000):
    E.append(odb.steps['Step-1'].frames[0].fieldOutputs['E'].values[i].data)   

# save the data
with open("mises.pickle", "wb") as input_file:
    pickle.dump(E, input_file)

odb.close()

问题在于将应变值加载到列表中的 for 循环需要很长时间(1000 个元素需要 35 秒)。以这个速度(0.035 次查询/秒),我需要 2 个小时才能为包含 200,000 个元素的模型提取数据。为什么这需要这么长时间?我怎样才能加速这个?

如果我在任何 Python 循环之外执行单个应变查询,则需要 0.04 秒,所以我知道这不是 Python 循环的问题。

【问题讨论】:

    标签: python abaqus


    【解决方案1】:

    我发现每次我想要应变时都必须重新打开 odb 字典中的子目录。因此,为了解决这个问题,我将 odb 对象保存为一个较小的对象。我的更新代码需要几分之一秒才能解决,如下所示。

    from odbAccess import openOdb
    import pickle as pickle
    
    # import database
    odbname = 'plate2'
    path = './'
    myodbpath = path + odbname + '.odb'
    odb = openOdb(myodbpath)
    
    # load the strain values into a list
    E = []
    EE = odb.steps['Step-1'].frames[0].fieldOutputs['E']
    for i in range(1000):
        E.append(EE.values[i].data)  
    
    # save the data
    with open("mises.pickle", "wb") as input_file:
        pickle.dump(E, input_file)
    
    odb.close()
    

    【讨论】:

    • 请注意,您可以使用列表理解 E=[v.data for v in EE.values] 更紧凑地编写此代码(也许也能获得一点性能提升)
    • 不错。顺便说一句,这种技术(在 Abaqus 脚本用户手册中的“创建对象以保存临时变量”下也提到过)可用于任何您希望避免重复重建对象序列的 Python 脚本。
    • 谢谢奥斯汀。这是一项很棒的技术。保存为泡菜后。下一步是如何打开和读取这个 pickle 文件。你可以发布你的例子。我对此很感兴趣。
    【解决方案2】:

    我会在这里使用 bulkDataBlocks。这比使用 value 方法快得多。也使用 Pickle 通常很慢而且没有必要。查看 FieldBulkData 对象的 C++ 手册 http://abaqus.software.polimi.it/v6.14/books/ker/default.htm。 Python 方法是相同的,但至少在 Abaqus 6.14 中没有记录在 Python-Scripting-Reference 中(从 6.13 开始提供)。

    例如:

    from odbAccess import openOdb
    import numpy as np
    
    # import database
    odbname = 'plate2'
    path = './'
    myodbpath = path + odbname + '.odb'
    odb = openOdb(myodbpath)
    
    # load the strain values into a numpy array
    EE = odb.steps['Step-1'].frames[0].fieldOutputs['E']
    
    # get a numpy array with your data 
    # Not using np.copy here may work also, but sometimes I encountered some weird bugs
    Strains=np.copy(EE.bulkDataBlocks[0].data)
    
    # save the data
    np.save('OutputPath',Strains)
    
    odb.close()
    

    请记住,如果您有多种元素类型,则可能会有多个 bulkDataBlock。

    【讨论】:

    • 我也遇到过bulkDataBlacks的奇怪表现,我看看np.copy有没有改善。
    • 我在使用 bulkDataBlocks 方法时没有遇到任何性能问题。它应该比 value 方法快得多。当我对 bulkDataBlocks 方法返回的 numpy 数组进行整形或切片时遇到了问题。但是通过复制数组,一切都应该没问题。
    • 我的意思是更多来自操纵bulkDataBlocks的随机结果。我没想过只是将块复制到内存中的其他地方。
    【解决方案3】:

    晚会有点晚,但我发现在这种情况下使用 operator.attrgetterfor 循环或列表理解要快得多

    所以而不是@AustinDowney

    E = []
    EE = odb.steps['Step-1'].frames[0].fieldOutputs['E']
    for i in range(1000):
        E.append(EE.values[i].data) 
    

    这样做:

    from operator import attrgetter
    EE = odb.steps['Step-1'].frames[0].fieldOutputs['E']
    E = map(attrgetter('data'), EE.values)
    

    这与列表理解的速度大致相同,但如果您有多个要同时提取的属性(例如 coordinateselementId),则效果会更好

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多