Skip to content

Commit

Permalink
Implemented pkl file load
Browse files Browse the repository at this point in the history
  • Loading branch information
mlau154 committed Nov 10, 2023
1 parent 5f628c5 commit 997737a
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 10 deletions.
2 changes: 2 additions & 0 deletions install/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ def run():
else:
raise ValueError("iss setup install command failed")

print(f"Install complete. Output is in {install_dir}")


if __name__ == "__main__":
run()
69 changes: 62 additions & 7 deletions pymead/gui/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
from collections import namedtuple
import multiprocessing as mp

from pymoo.factory import get_decomposition

from pymead.gui.rename_popup import RenamePopup
from pymead.gui.main_icon_toolbar import MainIconToolbar

Expand All @@ -34,7 +36,7 @@
from pymead.gui.input_dialog import LoadDialog, SaveAsDialog, OptimizationSetupDialog, \
MultiAirfoilDialog, ColorInputDialog, ExportCoordinatesDialog, ExportControlPointsDialog, AirfoilPlotDialog, \
AirfoilMatchingDialog, MSESFieldPlotDialog, ExportIGESDialog, XFOILDialog, NewMEADialog, EditBoundsDialog, \
ExitDialog, ScreenshotDialog
ExitDialog, ScreenshotDialog, LoadAirfoilAlgFile
from pymead.gui.pymeadPColorMeshItem import PymeadPColorMeshItem
from pymead.gui.analysis_graph import AnalysisGraph
from pymead.gui.parameter_tree import MEAParamTree
Expand Down Expand Up @@ -489,19 +491,72 @@ def auto_range_geometry(self):
x_data_range, y_data_range = self.mea.get_curve_bounds()
self.v.getViewBox().setRange(xRange=x_data_range, yRange=y_data_range)

def update_airfoil_parameters_from_vector(self, param_vec: np.ndarray):
for airfoil in self.mea.airfoils.values():
airfoil.airfoil_graph.airfoil_parameters = self.param_tree_instance.p.param('Airfoil Parameters')

try:
self.mea.update_parameters(param_vec)
except:
self.disp_message_box("Could not load parameters into airfoil. Check that the current airfoil system"
" displayed matches the one used in the optimization.")
return

self.param_tree_instance.plot_change_recursive(
self.param_tree_instance.p.param('Airfoil Parameters').child('Custom').children())

def import_parameter_list(self):
"""This function imports a list of parameters normalized by their bounds"""
file_filter = "DAT Files (*.dat)"
dialog = LoadDialog(self, settings_var="parameter_list_default_open_location", file_filter=file_filter)
if dialog.exec_():
file_name = dialog.selectedFiles()[0]
q_settings.setValue(dialog.settings_var, os.path.dirname(file_name))
parameter_list = np.loadtxt(file_name).tolist()
for airfoil in self.mea.airfoils.values():
airfoil.airfoil_graph.airfoil_parameters = self.param_tree_instance.p.param('Airfoil Parameters')
self.mea.update_parameters(parameter_list)
self.param_tree_instance.plot_change_recursive(
self.param_tree_instance.p.param('Airfoil Parameters').child('Custom').children())
param_vec = np.loadtxt(file_name).tolist()
self.update_airfoil_parameters_from_vector(param_vec)

def import_algorithm_pkl_file(self):
dialog = LoadAirfoilAlgFile(self)
if dialog.exec_():
inputs = dialog.getInputs()

try:
alg = load_data(inputs["pkl_file"])
except:
self.disp_message_box("Could not load .pkl file. Check that the file selected is of the form"
" algorithm_gen_XX.pkl.")
return

try:
X = alg.opt.get("X")
except AttributeError:
self.disp_message_box("Algorithm file not recognized. Check that the file selected is of the form"
" algorithm_gen_XX.pkl.")
return

if X.shape[0] == 1: # If single-objective:
x = X[0, :]
elif X.shape[0] == 0: # If the optimization result is empty:
self.disp_message_box("Empty optimization result")
return
else: # If multi-objective
if inputs["use_index"]:
x = X[inputs["index"], :]
elif inputs["use_weights"]:
F = alg.opt.get("F")
decomp = get_decomposition("asf")

if len(inputs["weights"]) != F.shape[0]:
self.disp_message_box(f"Length of the requested weight list ({len(inputs['weights'])}) does"
f" not match the number of objective functions ({F.shape[0]})")
return

IDX = decomp.do(F, inputs["weights"]).argmin()
x = X[IDX, :]
else:
raise ValueError("Either 'index' or 'weights' must be selected in the dialog")

self.update_airfoil_parameters_from_vector(x)

def export_parameter_list(self):
"""This function imports a list of parameters normalized by their bounds"""
Expand Down
3 changes: 2 additions & 1 deletion pymead/gui/gui_settings/menu.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"Save As": "save_as_mea",
"Save": ["save_mea", "Ctrl+S"],
"Import": {
"Parameter List": "import_parameter_list"
"Parameter List": "import_parameter_list",
"Optimized Airfoil": "import_algorithm_pkl_file"
},
"Export": {
"Airfoil Coordinates": "export_coordinates",
Expand Down
3 changes: 2 additions & 1 deletion pymead/gui/gui_settings/q_settings_descriptions.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"parameter_list_default_open_location": "Directory where import_parameter_list() starts by default",
"geometry_plot_default_open_location": "Directory where plot_geometry() starts by default",
"dark_theme_checked": "set_theme('dark') used if true, else set_theme('light')",
"ga-settings-dir": "Directory where GAGeneralSettingsDialogWidget.load_opt_settings starts"
"ga-settings-dir": "Directory where GAGeneralSettingsDialogWidget.load_opt_settings starts",
"pkl_file_dir": "Directory where import_algorithm_pkl_file starts"
}
106 changes: 105 additions & 1 deletion pymead/gui/input_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import numpy as np
from typing import List
from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QFormLayout, QDoubleSpinBox, QComboBox, QSpinBox, \
QTabWidget, QLabel, QMessageBox, QCheckBox, QVBoxLayout, QWidget, QGridLayout, QPushButton, QListView
QTabWidget, QLabel, QMessageBox, QCheckBox, QVBoxLayout, QWidget, QGridLayout, QPushButton, QListView, QRadioButton
from PyQt5.QtCore import QEvent, Qt, pyqtSignal
from PyQt5.QtGui import QStandardItem, QStandardItemModel
import tempfile
Expand Down Expand Up @@ -2025,6 +2025,110 @@ def __init__(self, parent, settings_var: str, file_filter: str = "JMEA Files (*.
self.setDirectory(path)


class LoadAirfoilAlgFileWidget(QWidget):
def __init__(self, parent):
super().__init__(parent)
layout = QGridLayout(self)

self.pkl_line = QLineEdit("", self)
self.pkl_selection_button = QPushButton("Choose File", self)
self.index_button = QRadioButton("Use Index", self)
self.weight_button = QRadioButton("Use Weights", self)
self.index_spin = QSpinBox(self)
self.index_spin.setValue(0)
self.index_spin.setMaximum(9999)
self.weight_line = QLineEdit(self)

self.index_button.toggled.connect(self.index_selected)
self.weight_button.toggled.connect(self.weight_selected)

self.weight_line.textChanged.connect(self.weights_changed)
self.pkl_selection_button.clicked.connect(self.choose_file_clicked)

self.weight_line.setText("0.5,0.5")

self.index_button.toggle()

layout.addWidget(self.pkl_line, 0, 0)
layout.addWidget(self.pkl_selection_button, 0, 1)
layout.addWidget(self.index_button, 1, 0)
layout.addWidget(self.weight_button, 1, 1)
layout.addWidget(self.index_spin, 2, 0)
layout.addWidget(self.weight_line, 2, 1)

self.setLayout(layout)

def choose_file_clicked(self):
dialog = LoadDialog(self, settings_var="pkl_file_dir", file_filter="PKL files (*.pkl)")

if dialog.exec_():
file_name = dialog.selectedFiles()[0]
self.pkl_line.setText(file_name)
file_name_parent_dir = os.path.dirname(file_name)
q_settings.setValue(dialog.settings_var, file_name_parent_dir)

def index_selected(self):
self.index_spin.setReadOnly(False)
self.weight_line.setReadOnly(True)

def weight_selected(self):
self.index_spin.setReadOnly(True)
self.weight_line.setReadOnly(False)

def weights_changed(self, new_text: str):
weights = self.validate_weights(new_text)
if len(weights) > 0:
self.weight_line.setStyleSheet("QLineEdit { background: rgba(16,201,87,50) }")
else:
self.weight_line.setStyleSheet("QLineEdit { background: rgba(176,25,25,50) }")

@staticmethod
def validate_weights(text: str):
text = text.strip()
text_list = text.split(",")
try:
weights = [float(t) for t in text_list]
weight_sum = sum(weights)
if not np.isclose(weight_sum, 1.0, rtol=1e-12):
return []
except:
return []

return weights

def getInputs(self):
return {
"pkl_file": self.pkl_line.text(),
"use_index": self.index_button.isChecked(),
"use_weights": self.weight_button.isChecked(),
"index": self.index_spin.value(),
"weights": self.validate_weights(self.weight_line.text())
}


class LoadAirfoilAlgFile(QDialog):
def __init__(self, parent):
super().__init__(parent=parent)

self.setWindowTitle("Load Optimized Airfoil")
self.setFont(self.parent().font())

buttonBox = QDialogButtonBox(self)
buttonBox.addButton(QDialogButtonBox.Ok)
buttonBox.addButton(QDialogButtonBox.Cancel)
self.grid_layout = QGridLayout(self)

self.load_airfoil_alg_file_widget = LoadAirfoilAlgFileWidget(self)
self.grid_layout.addWidget(self.load_airfoil_alg_file_widget, 0, 0)
self.grid_layout.addWidget(buttonBox, self.grid_layout.rowCount(), 0)

buttonBox.accepted.connect(self.accept)
buttonBox.rejected.connect(self.reject)

def getInputs(self):
return self.load_airfoil_alg_file_widget.getInputs()


class SaveAsDialog(QFileDialog):
def __init__(self, parent, file_filter: str = "JMEA Files (*.jmea)"):
super().__init__(parent=parent)
Expand Down

0 comments on commit 997737a

Please sign in to comment.