Ускорение медленного цикла в коде Abaqus-python для извлечения данных о деформации из файла .odb.

У меня есть файл .odb с именем plate2.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, который загружает значения деформации в список, занимает много времени (35 секунд для 1000 элементов). При такой скорости (0,035 запросов в секунду) мне потребовалось бы 2 часа, чтобы извлечь данные для моей модели с 200 000 элементов. Почему это так долго? Как я могу ускорить это?

Если я выполняю один запрос на растяжение вне любого цикла Python, это занимает 0,04 секунды, поэтому я знаю, что это не проблема с циклом Python.


person Austin Downey    schedule 04.10.2017    source источник


Ответы (3)


Я обнаружил, что мне приходилось заново открывать подкаталоги в словаре 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()
person Austin Downey    schedule 04.10.2017
comment
обратите внимание, что вы можете написать это еще более компактно, используя понимание списка E=[v.data for v in EE.values] (возможно, также небольшое увеличение производительности) - person agentp; 05.10.2017
comment
Хороший. Кстати, этот метод (также упомянутый в Руководстве пользователя сценариев Abaqus в разделе «Создание объектов для хранения временных переменных») можно использовать в любом сценарии Python, где вы хотели бы избежать повторных реконструкций последовательности объектов. - person Matt P; 05.10.2017
comment
Спасибо Остин. Это отличная техника. После сохранения как рассол. следующий шаг — как открыть и прочитать этот файл рассола. Можете ли вы опубликовать свой пример. Я очень заинтересован в этом. - person roudan; 22.08.2020

Я бы использовал bulkDataBlocks здесь. Это намного быстрее, чем использование метода значения. Также использование Pickle обычно медленное и не обязательное. Загляните в руководство по C++ http://abaqus.software.polimi.it/v6.14/books/ker/default.htm в объекте FieldBulkData. Метод 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.

person max9111    schedule 08.10.2017
comment
Я также столкнулся со странной производительностью bulkDataBlacks, я посмотрю, улучшит ли ситуацию np.copy. - person Daniel F; 25.10.2017
comment
Я не столкнулся с проблемами производительности при использовании метода bulkDataBlocks. Это должно быть намного быстрее, чем метод значения. Я столкнулся с проблемами, когда я изменил форму или нарезал массив numpy, возвращаемый методом bulkDataBlocks. А вот с копированием массива все должно быть ок. - person max9111; 25.10.2017
comment
Я имел в виду скорее случайные результаты манипулирования bulkDataBlocks. Я не думал просто копировать блоки в другое место в памяти. - person Daniel F; 26.10.2017

Немного опоздал на вечеринку, но я считаю, что использование operator.attrgetter намного быстрее, чем цикл for или понимание списка в этом случае

Так что вместо @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)

Это примерно такая же скорость, как понимание списка, но намного лучше, если у вас есть несколько атрибутов, которые вы хотите извлечь одновременно (скажем, coordinates или elementId).

person Daniel F    schedule 25.10.2017