Рассматривается задача оптимизации диаметра основания столба рекламного щита, нагруженного ветровой нагрузкой.
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c4af65603318ec0c1b7_1.png)
Свойства материала (для простоты) берутся из библиотеки Фидесис следующими:
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c49b345c386b1ae094c_2.png)
Что минимально необходимо для использования:
- Python v.3.8
- Библиотека vtk – для чтения результатов
- Библиотека numpy – для преобразования результатов
- Библиотеки sys и os – для работы с путями к файлам
- Библиотеки cubit и fidesys – для препроцессинга данных
Подготовка:
- Скачать Python 3.8 с сайта python.org и установить.
- Скачать Fidesys 4.1 с сайта cae-fidesys.com и установить.
- Открыть командную строку Windows (cmd.exe) и прописать в ней:
- pip3 install vtk (затем нажать Enter и дать установиться)
- pip3 install numpy (затем нажать Enter и дать установиться)
Далее необходимо создать модель и подготовить ее для расчета.
Создаем сам щит.
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c4a5194da9be426d0db_3.png)
Перемещаем его.
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c4a75527749c38210ad_4.png)
Создаем столб в виде усеченного конуса.
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c4a1836e0196b19d412_5.png)
Перемещаем его.
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c4a221804a3905ab44a_6.png)
Создаем общие поверхности для того, чтобы сетка совместилась.
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c4b2e180e9f70865285_7.png)
Строим простую тетраэдральную сетку.
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c4cc351776506a348c9_8.png)
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c4b30a08a2524c65c9f_9.png)
Если всё было сделано правильно, до вы должны увидеть такую модель:
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c4b75527771fc821156_9-1.png)
Создаем материал путем добавления материала из базы данных.
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c4cb345c386b1ae0bc7_10.png)
Создаем блок из всех объемов, чтобы передать им свойства модели.
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c4d7552778ad082129f_11.png)
Присваиваем свойства блоку.
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c4cd4c87531543c29b9_12.png)
Создаем граничные условия основанию столба.
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c4d051bce2520b679d0_13.png)
Задаем ветровую нагрузку
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c4d30a08a5901c65cf7_14.png)
Добавляем действие гравитации.
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c4d62d4ced376c1c8f6_15.png)
Задаем настройки расчета.
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c4db345c35449ae0c71_16.png)
В итоге получится следующий скрипт, который можно будет увидеть во вкладке "История" командной строки:
reset
brick x 20 y 0.5 z 10
move Volume 1 x 0 y 0 z 30 include_merged
create frustum height 25 radius 0.25 top 0.25
move Volume 2 x 0 y 0 z 12.5 include_merged
undo group begin
imprint volume all
merge volume all
undo group end
volume all scheme tetmesh
mesh volume all
create material 1 from 'Углеродистая сталь'
set duplicate block elements off
block 1 add volume all
block 'Block 1' material 1 cs 1 element solid order 1
create displacement on surface 8 dof all fix
create distributed force on surface 3 force value 230 moment value 0 direction 0 1 0 specific
create gravity global
modify gravity 1 dof 3 value -9.81
analysis type static elasticity dim3
Затем его необходимо скопировать для преобразования в синтаксис Питона.
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c8ef656036be0c112e8_17.png)
Далее открываем редактор журнала и вставляем в пустое окно текст скрипта.
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c8eb089d3383e4707d9_18.png)
Затем преобразуем в синтаксис Питона.
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c8e1836e044051a2a95_19.png)
Получим следующий скрипт:
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4c8e0f3532967a9b8e84_20.png)
Далее необходимо создать новый файл Python.
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/62f2993dd4253a26f41bb46c_21.png)
И скопировать в открывшееся пустое окно следующий скрипт:
import vtk # Библиотека работы с выходными данными
from vtk.util.numpy_support import vtk_to_numpy # Модуль для преобразования результатов
import sys # Cистемная библиотека
import os # Cистемная библиотека
fidesys_path = r'C:\Program Files\Fidesys\CAE-Fidesys-4.1' # Расположение Фидесиса
base_dir = os.path.dirname(os.path.abspath(__file__)) # Директория где лежит скрипт
pvd_file = os.path.join(base_dir, '1.pvd') # Файл ссылок на результаты
prep_path = os.path.join(fidesys_path, 'preprocessor', 'bin') # Директория, где препроцессор
os.environ['PATH'] += prep_path # Добавление пути к препроцессору в PATH
sys.path.append(prep_path) # Добавление пути к препроцессору в PATH
import cubit # Библиотека препроцессинга
import fidesys # Библиотека Фидесиса
cubit.init([""]) # Инициализация препроцессора
fc = fidesys.FidesysComponent() # Создание обязательного компонента Фидесис fc
fc.initApplication(prep_path)
fc.start_up_no_args() # Запуск обязательного компонента Фидесис fc
r = 0.25 # Начальный радиус основания
print("Начальный диаметра ", 2*r)
isOptimized = False # Изначально False - начальная конструкция не оптимизирована
prohod = 1 # Начальное значение счетчика проходов(итераций)
while isOptimized == False:
print("Проход № ",prohod) # Пишем в консоль какой проход
overstressed = [] # Создаем пустой массив для заполнения перенапряженными узлами
#--------- Сюда вставляется геометрический скрипт с настройками расчета ----------
output_pvd_path = os.path.join(base_dir + "\\" + "1.pvd")
print("strarting calculation to " + output_pvd_path)
fidesys.cmd("calculation start path '" + output_pvd_path + "'")
print(" ")
print("Расчет успешно завершен!")
print(" ")
reader = vtk.vtkXMLUnstructuredGridReader() #Подключаем читалку
print("Читаем результаты из ",str(base_dir)+r"\1\case1_step01_substep0001.vtu") # Пишет откуда берем результаты
filename = os.path.join(str(base_dir)+r"\1\case1_step01_substep0001.vtu") # Указываем путь к файлу
reader.SetFileName(filename) # Подключаем путь к читалке и читаем
reader.Update() # Needed because of GetScalarRange
grid = reader.GetOutput() # Забираем выходные данные
point_data = grid.GetPointData() # Забираем данные для точек
arrayOfStress = vtk_to_numpy(point_data.GetArray("Stress")) # Считываем напряжения из массива результатов
node_id = vtk_to_numpy(point_data.GetArray("Node ID")) # Считываем номера узлов из массива результатов
print("Начинаем поиск перенапряженных узлов")
print(" ")
for point in range(len(arrayOfStress)):
if arrayOfStress[point][6] > 106e6: # Проверяем напряжения по Мизесу в узлах
overstressed.append(node_id[point]) # Заполняем массив номерами перенапряженных узлов
if len(overstressed) == 0: # Проверяется размер массива перенапряженных узлов, если он 0 то
isOptimized = True # приравниваем переменную isOptimized=True, чтобы выйти из цикла
print("Конструкция оптимизирована!")
else:
print("Перенапряженных узлов: ",len(overstressed)) # Выводим информацию о количестве перенапряженных узлов
print(" ")
r = r + 0.05 # Увеличиваем радиус на 0.05
prohod = prohod + 1 # Увеличиваем значение счетчика проходов
fc.deleteApplication() #Удаляем из памяти выполненную задачу
print(" ")
print("Готово! Оптимальный диаметр не менее ", 2*r)
Затем необходимо вставить вместо текста#--------- Сюда вставляется геометрический скрипт с настройками расчета ----------непосредственно тот преобразованный текст модели, который мы получили ранее, затем делаем вставку "+str(r)+" вместо первого 0.25 в строчку fidesys.cmd("create frustum height 25 radius "+str(r)+"top 0.25"), чтобы у нас перебиралось значение нижнего радиуса конуса, после чего в итоге получится следующий скрипт:
import vtk # Библиотека работы с выходными данными
from vtk.util.numpy_support import vtk_to_numpy # Модуль для преобразования результатов
import sys # Cистемная библиотека
import os # Cистемная библиотека
fidesys_path = r'C:\Program Files\Fidesys\CAE-Fidesys-4.1' # Расположение Фидесиса
base_dir = os.path.dirname(os.path.abspath(__file__)) # Директория где лежит скрипт
pvd_file = os.path.join(base_dir, '1.pvd') # Файл ссылок на результаты
prep_path = os.path.join(fidesys_path, 'preprocessor', 'bin') # Директория, где препроцессор
os.environ['PATH'] += prep_path # Добавление пути к препроцессору в PATH
sys.path.append(prep_path) # Добавление пути к препроцессору в PATH
import cubit # Библиотека препроцессинга
import fidesys # Библиотека Фидесиса
cubit.init([""]) # Инициализация препроцессора
fc = fidesys.FidesysComponent() # Создание обязательного компонента Фидесис fc
fc.initApplication(prep_path)
fc.start_up_no_args() # Запуск обязательного компонента Фидесис fc
r = 0.25 # Начальный радиус основания
print("Начальный диаметра ", 2*r)
isOptimized = False # Изначально False - начальная конструкция не оптимизирована
prohod = 1 # Начальное значение счетчика проходов(итераций)
while isOptimized == False:
print("Проход № ",prohod) # Пишем в консоль какой проход
overstressed = [] # Создаем пустой массив для заполнения перенапряженными узлами
# ---------Начало вставляемого скрипта из Фидесис-------------
fidesys.cmd("reset")
fidesys.cmd("brick x 20 y 0.5 z 10")
fidesys.cmd("move Volume 1 x 0 y 0 z 30 include_merged ")
fidesys.cmd("create frustum height 25 radius "+str(r)+"top 0.25")
fidesys.cmd("move Volume 2 x 0 y 0 z 12.5 include_merged ")
fidesys.cmd("undo group begin")
fidesys.cmd("imprint volume all ")
fidesys.cmd("merge volume all ")
fidesys.cmd("undo group end")
fidesys.cmd("volume all scheme tetmesh")
fidesys.cmd("mesh volume all")
fidesys.cmd("create material 1 from 'Углеродистая сталь'")
fidesys.cmd("set duplicate block elements off")
fidesys.cmd("block 1 add volume all")
fidesys.cmd("block 'Block 1' material 1 cs 1 element solid order 1")
fidesys.cmd("create displacement on surface 8 dof all fix ")
fidesys.cmd("create distributed force on surface 3 force value 230 moment value 0 direction 0 1 0 specific")
fidesys.cmd("create gravity global")
fidesys.cmd("modify gravity 1 dof 3 value -9.81")
fidesys.cmd("analysis type static elasticity dim3")
# ---------Конец вставляемого скрипта из Фидесис-------------
output_pvd_path = os.path.join(base_dir + "\\" + "1.pvd") # Объявляем директорию и файл сохранения
print("strarting calculation to " + output_pvd_path) # Выводим в консоль директорию и файл сохранения
fidesys.cmd("calculation start path '" + output_pvd_path + "'") # Просим Фидесис начать расчет в указанную директорию
print(" ")
print("Расчет успешно завершен!")
print(" ")
reader = vtk.vtkXMLUnstructuredGridReader() #Подключаем читалку
print("Читаем результаты из ",str(base_dir)+r"\1\case1_step0001_substep0001.vtu") # Пишет откуда берем результаты
filename = os.path.join(str(base_dir)+r"\1\case1_step0001_substep0001.vtu") # Указываем путь к файлу
reader.SetFileName(filename) # Подключаем путь к читалке и читаем
reader.Update() # Needed because of GetScalarRange
grid = reader.GetOutput() # Забираем выходные данные
point_data = grid.GetPointData() # Забираем данные для точек
arrayOfStress = vtk_to_numpy(point_data.GetArray("Stress")) # Считываем напряжения из массива результатов
node_id = vtk_to_numpy(point_data.GetArray("Node ID")) # Считываем номера узлов из массива результатов
print("Начинаем поиск перенапряженных узлов")
print(" ")
for point in range(len(arrayOfStress)):
if arrayOfStress[point][6] > 106e6: # Проверяем напряжения по Мизесу в узлах
overstressed.append(node_id[point]) # Заполняем массив номерами перенапряженных узлов
if len(overstressed) == 0: # Проверяется размер массива перенапряженных узлов, если он 0 то
isOptimized = True # приравниваем переменную isOptimized=True, чтобы выйти из цикла
print("Конструкция оптимизирована!")
else:
print("Перенапряженных узлов: ",len(overstressed)) # Выводим информацию о количестве перенапряженных узлов
print(" ")
r = r + 0.05 # Увеличиваем радиус на 0.05
prohod = prohod + 1 # Увеличиваем значение счетчика проходов
fc.deleteApplication() #Удаляем из памяти выполненную задачу
print(" ")
print("Готово! Оптимальный диаметр не менее ", 2*r)
Далее скрипт необходимо запустить и, когда система попросит, сохранить этот файл к примеру в папку Example, созданную на рабочем столе.
Если возникнут ошибки чтения/записи, то проверьте нет ли в тексте пути кириллических символов. Во избежание ошибок желательно, чтобы путь содержал только латинские буквы.
Запускаем.
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4cf1f981bd5f4e0616e6_22.png)
После того как расчет прошел вы увидите:
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4cf2f981bd66fc0617d0_23.png)
И в папке с файлом скрипта будут лежать следующие файлы:
![](https://uploads-ssl.webflow.com/577f3315340bfadb0a80534f/630e4cf2f268da7fca0df988_24.png)