Для создания модели используется модель из данной статьи: Оптимизация диаметра сечения столба рекламного щита с использованием 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 и еще раз запустить расчет.
