Для создания модели используется модель из данной статьи: Оптимизация диаметра сечения столба рекламного щита с использованием Python API Fidesys
Для добавления картинки в графическое окно программы скачайте эту картинку и разместите ее в папке со скриптом.
Не забудьте проверить верно ли указана версия CAE Fidesys в пути скрипта.
#https://realpython.com/python-gui-tkinter/
import tkinter as tk # Библиотека графического интерфейса
import vtk # Библиотека работы с выходными данными
from vtk.util.numpy_support import vtk_to_numpy # Модуль для преобразования результатов
import sys # Cистемная библиотека
import os # Cистемная библиотека
from PIL import Image, ImageTk # Библиотеки для удобной работы с изображением
fidesys_path = r'C:\Program Files\Fidesys\CAE-Fidesys-6.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
#Пытаемся импортировать библиотеки Фидесис
try: #Блок попыток
import cubit # Библиотека препроцессинга
import fidesys # Библиотека Фидесиса
except ModuleNotFoundError: #Если не вышло, то выводим в консоль сообщение
print("В скрипте указан следующий путь к Фидесис: ", fidesys_path)
print("Укажите в скрипте путь к вашей версии Фидесис. Вероятно ваша версия отличается от указанной или установлена в другую директорию.")
sys.exit(1)
cubit.init([""]) # Инициализация препроцессора
fc = fidesys.FidesysComponent() # Создание обязательного компонента Фидесис fc
window = tk.Tk() # Создание окна
window.title("One-Button Solution for Billboard") # Заголовок окна
# Основной класс
class MainClass(object):
# Инициализация переменных
def __init__(self):
# Строчки давления
self.lbl1 = tk.Label(window, text="Wind pressure", width=13)
self.lbl1.place(x=310, y=10)
self.entry1 = tk.Entry(window, width=14)
self.entry1.place(x=410, y=10)
self.entry1.insert(1, '230')
self.lbl2 = tk.Label(window, text="p, Pa", width=5)
self.lbl2.place(x=497, y=10)
# Строчки длины столба
self.lbl3 = tk.Label(window, text="Pillar lenght", width=13)
self.lbl3.place(x=305, y=55)
self.entry2 = tk.Entry(window, width=14)
self.entry2.place(x=410, y=55)
self.entry2.insert(1, '25')
self.lbl4 = tk.Label(window, text="L, m", width=4)
self.lbl4.place(x=500, y=55)
# Строчки диаметра
self.lbl5 = tk.Label(window, text="Pillar diameter", width=15)
self.lbl5.place(x=305, y=100)
self.entry3 = tk.Entry(window, width=14)
self.entry3.place(x=410, y=100)
self.entry3.insert(1, '0.5')
self.lbl6 = tk.Label(window, text="D, m", width=4)
self.lbl6.place(x=500, y=100)
# Строчки высоты щита
self.lbl7 = tk.Label(window, text="Billboard width", width=15)
self.lbl7.place(x=306, y=145)
self.entry4 = tk.Entry(window, width=14)
self.entry4.place(x=410, y=145)
self.entry4.insert(1, '20')
self.lbl8 = tk.Label(window, text="H, m", width=4)
self.lbl8.place(x=500, y=145)
# Строчки ширины щита
self.lbl9 = tk.Label(window, text="Billboard height", width=16)
self.lbl9.place(x=305, y=190)
self.entry5 = tk.Entry(window, width=14)
self.entry5.place(x=410, y=190)
self.entry5.insert(1, '10')
self.lbl10 = tk.Label(window, text="W, m", width=4)
self.lbl10.place(x=500, y=190)
# Прочностной прогноз
self.lbl11 = tk.Label(window, text="Strength status", width=15)
self.lbl11.place(x=305, y=235)
self.entry6 = tk.Entry(window, width=14)
self.entry6.place(x=410, y=235)
self.entry6.insert(1, ' Unknown')
self.pict = Image.open(os.path.join(str(base_dir)+r"\Billboard.png")) # Добавление картинки
try: # Обработка ошибки на случай разных версий библиотеки PIL
# Ресайзинг картинки под нужный размер
self.pict = self.pict.resize((300, 250), Image.Resampling.LANCZOS)
except AttributeError:
# Ресайзинг картинки под нужный размер
self.pict = self.pict.resize((300,250),resample=Image.BICUBIC)
picture = ImageTk.PhotoImage(self.pict)
self.label1 = tk.Label(image=picture)
self.label1.image = picture
self.label1.place(x=10, y=10)
self.btn2 = tk.Button(master=window, text = 'Calculate', command=self.calculate)
self.btn2.place(x=260, y=270)
self.tbx = tk.Text(window, width = 65, height = 5, background ='White')
self.tbx.place(x=10, y=305)
self.tbx.insert('1.0', '...')
self.ext=tk.Button(master=window, text="Close", command=window.destroy)
self.ext.place(x=495, y=395)
self.btn3 = tk.Button(master=window, text = 'Open in FidesysViewer', command=self.openView, state=['disabled'])
self.btn3.place(x=225, y=395)
def convert(self):
self.tbx.delete(1.0, 3.0) # Вычищаем поле
p = self.entry1.get()
self.appendToField('1.0', "Wind pressure is "+ str(p) + " Pa")
return
def calculate(self):
fc.init_application(prep_path) # !!!!!Инициализация для версий 5.1+ (для 5.0 и ниже заменить на fc.initApplication(prep_path))
fc.start_up_no_args() # Запуск обязательного компонента Фидесис fc
self.tbx.delete(1.0, 100.0) # Вычищаем поле
p = self.entry1.get()
L = self.entry2.get()
D = self.entry3.get()
W = self.entry4.get()
H = self.entry5.get()
self.appendToField('1.0', "Calculation has started. \n")
overstressed = [] # Создаем пустой массив для заполнения перенапряженными узлами
# ---------Начало вставляемого скрипта из Фидесис-------------
fidesys.cmd("reset")
fidesys.cmd("brick x "+str(W)+" y 0.5 z "+str(H)+"")
fidesys.cmd("move Volume 1 x 0 y 0 z 30 include_merged ")
fidesys.cmd("create frustum height "+str(L)+" radius "+str(float(D)/2)+"top 0.25")
fidesys.cmd("move Surface 9 location surface 2 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 "+str(p)+" 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 + "'") # Просим Фидесис начать расчет в указанную директорию
self.appendToField('2.0', "Calculation has finished. \n")
self.appendToField('3.0', "Reading results. \n")
reader = vtk.vtkXMLUnstructuredGridReader() #Подключаем читалку
print("Читаем результаты из ",str(base_dir)+r"\1\case1_step0001_substep0001.vtu") # Пишет откуда берем результаты
self.filename = os.path.join(str(base_dir)+r"\1\case1_step0001_substep0001.vtu") # Указываем путь к файлу
reader.SetFileName(self.filename) # Подключаем путь к читалке и читаем
reader.Update() # Needed because of GetScalarRange
grid = reader.GetOutput() # Забираем выходные данные
point_data = grid.GetPointData() # Забираем данные для точек
self.appendToField('4.0', "Analysing results. \n")
arrayOfStress = vtk_to_numpy(point_data.GetArray("Stress")) # Считываем напряжения из массива результатов
node_id = vtk_to_numpy(point_data.GetArray("Node ID")) # Считываем номера узлов из массива результатов
for point in range(len(arrayOfStress)):
if arrayOfStress[point][6] > 106e6: # Проверяем напряжения по Мизесу в узлах
overstressed.append(node_id[point]) # Заполняем массив номерами перенапряженных узлов
if len(overstressed) == 0: # Проверяется размер массива перенапряженных узлов, если он 0 то
self.entry6.configure(bg='green')
self.entry6.delete(1,30)
self.entry6.insert(1, ' Good design')
print("Good")
self.appendToField('5.0', "Design is good. \n")
self.btn3.config(state="active")
else:
self.entry6.configure(bg='red')
self.entry6.delete(1,30)
self.entry6.insert(1, ' Bad design')
print("Bad")
self.appendToField('6.0', "Design is bad. Try another parameters. \n")
self.btn3.config(state="active")
fc.delete_application() # Команда удаления задачи из памяти для версии 5.1 (для 5.0 и ниже заменить на fc.deleteApplication())
return
def openView(self):
os.startfile(pvd_file)
return
def appendToField(self, pos, txtData):
self.tbx.insert(pos, txtData)
self.tbx.update()
def main(self):
window.minsize(545,430)
window.mainloop()
if __name__ == "__main__":
MainClass().main()
Попробуйте запустить программу. В случае успешного запуска вы увидите следующее окно:
Попробуйте нажать "Calculate" и посмотреть результат, затем изменить диаметр столба с 0.5 на 0.6 и еще раз запустить расчет.
fidesys