Замена имен переменных состояния в odb на python

В Abaqus у меня есть собственное описание материала (ВУМАТ). Этот VUMAT генерирует переменные состояния с именами SDV1, SDV2 и т. д. Эти переменные хранятся в двоичном файле .odb с другими выходными данными в abaqus. Поскольку у меня их огромное количество, я хотел бы дать им осмысленные имена, такие как S1, S2, E1, E2 и т. Д., Чтобы при просмотре .odb в программе просмотра Abaqus было ясно, какая переменная какая.

Теперь abaqus предоставляет интерфейс Python для чтения и записи в этот файл .odb. Но насколько я мог искать, я не мог найти способ переименовать эти переменные. Когда я пытаюсь изменить их, я получаю ошибку только для чтения.

Поэтому я попытался открыть .odb с помощью Notepad ++ и обнаружил, что если заменить все записи 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)

Но когда я открываю новый .odb в программе просмотра abaqus, я получаю следующее сообщение:

***ОШИБКА: файл базы данных Abaqus поврежден. Если этот файл был передан с другого компьютера с помощью FTP или аналогичного, убедитесь, что файл был скопирован с использованием двоичного режима, а не режима ASCII.

Более того, в настоящее время этот код также заменяет SDV20, как этого избежать и заменить только SDV2, а не части SDV20, SDV21 и т. д.?

Что мне не хватает? Я использую питон 2.7.

ИЗМЕНИТЬ:

Если ODB открыт в HEX-редакторе, можно увидеть следующий шаблон: Для 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. 3 для SDV1-SDV9 и 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. После этого текстовый файл можно было удалить. И все это без запроса вывода SDV.

Или можно запросить вывод SDV в файл .fil, а затем собрать его обратно в odb с помощью FieldOutput() и addData(). Но это очень хакерские решения, которые требуют большого количества операций записи на диск и большого количества строк кода для анализа выходных текстовых файлов.

Я оставляю этот тред без ответа, пока не будет опубликовано полное решение или я не разберусь сам (в этом случае я опубликую ответ заяц)

Спасибо за помощь!


person UN4    schedule 22.04.2016    source источник
comment
В вашем коде b'SDV2' и b'works' имеют разную длину. Я предполагаю, что это не сработает.   -  person gdlmx    schedule 23.04.2016
comment
Да, это правильно. Длины должны совпадать, чтобы он работал. Хотя мне не удалось увеличить длину, посмотрев на шаблон кодирования и попытавшись воспроизвести его вручную.   -  person UN4    schedule 25.04.2016


Ответы (2)


Ваш подход очень творческий, но есть «стандартный» способ достижения вашей цели с помощью 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. длина старого и нового названий ("СДВ2" ​​и "работ") не совпадает.
  2. раздел двоичных данных файла ODB может включать 4 последовательных байта, которые случайно совпадают с «SDV2». В этом случае ваш скрипт переопределяет эти байты и повреждает весь файл.

Редактировать1

  1. Поскольку Abaqus не предоставляет никакого метода для удаления существующих полей (по соображениям согласованности, как они сказали), если вы хотите предотвратить дублирование с помощью метода addData, необходимо создать новую ODB и скопировать туда поля. Затем вы можете удалить старый файл. Пользуемся этим методом год. Преимущество заключается в том, что вы можете создавать вектор или тензор из разных SDV для лучшей визуализации.

  2. Чтобы исправить возможную ошибку, о которой я упоминал ранее (несоответствие длины и непреднамеренная замена), вы можете использовать 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

Остальные коды следуют вашему сценарию. Я предполагаю, что вам просто нужно заменить только одно появление каждого имени в файле. В противном случае используйте метод finditer re.

person gdlmx    schedule 23.04.2016
comment
Если я правильно понимаю, стандартным способом создаются новые Field Variables. У меня уже есть 36 SDV, если я создам новые, это число удвоится. Я не могу удалить старые, поэтому размер моего файла odb сильно увеличится. Особенно для больших анализов. В настоящее время я просто заменяю имя своих SDV кодом, который я разместил в своем вопросе. Я просто должен быть уверен, что новая переменная имеет ту же длину, что и старая. Таким образом, я ограничен только 4 символами, что недостаточно. Но очень быстро и просто. Хотя было бы неплохо правильно закодировать имена новых переменных в файле odb. - person UN4; 25.04.2016
comment
Спасибо за разъяснение, не подумал копировать все в новый ODB. Теперь имеет смысл использовать метод addData! Предоставленный вами код по-прежнему повреждает odb, если длина newn больше, чем oldn. В любом случае я попытаюсь использовать метод addData, поскольку я мог бы использовать возможность создавать тензоры и векторы! - person UN4; 25.04.2016

Проблема в том, что у вас совпадает все, что начинается с 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)

Бьюсь об заклад, есть способ сделать это без повторения того, как вы предложили.

person sebisnow    schedule 22.04.2016
comment
Да, действительно, ваш способ заменяет именно то, что я хочу. Но программа просмотра Abaqus по-прежнему выдает сообщение об ошибке. Это очень странно, потому что если я делаю это вручную, все в порядке. Что чтение и запись в python сохраняет по-другому по сравнению с редактированием в Notepad++? - person UN4; 22.04.2016
comment
Для меня, хотя я определенно не эксперт, это звучит как проблема с кодировкой, но, поскольку у меня нет опыта работы с программой просмотра Abaqus, это только предположение. - person sebisnow; 22.04.2016
comment
По-видимому, она должна иметь ту же длину, что и исходная строка. В противном случае это не сработает. Я могу заменить дополнительные символы пробелами, если моя новая строка короче. Если моя новая строка окажется длиннее, я пока ничего не могу сделать. Хотя abaqus использует еще более длинные имена для некоторых переменных. Метод Notepad ++ сработал, потому что я попытался заменить «SDV10» на «works», и оба имеют одинаковое количество символов. Интересно, где хранится информация о длине char. - person UN4; 22.04.2016