diff --git a/hypnotoad/cases/tokamak.py b/hypnotoad/cases/tokamak.py
index 46d4a8ad..2d5c4cde 100644
--- a/hypnotoad/cases/tokamak.py
+++ b/hypnotoad/cases/tokamak.py
@@ -1452,7 +1452,7 @@ def Bt_axis(self):
return self.fpol(self.psi_axis) / self.o_point.R
-def read_geqdsk(filehandle, options={}, **kwargs):
+def just_read_geqdsk(filehandle, options=None, **kwargs):
"""
Read geqdsk formatted data from a file object, returning
a TokamakEquilibrium object
@@ -1472,6 +1472,9 @@ def read_geqdsk(filehandle, options={}, **kwargs):
from ..geqdsk._geqdsk import read as geq_read
+ if options is None:
+ options = {}
+
data = geq_read(filehandle)
# Range of psi normalises psi derivatives
@@ -1525,14 +1528,38 @@ def read_geqdsk(filehandle, options={}, **kwargs):
# fpol constant in SOL
fpol = np.concatenate([fpol, np.full(psiSOL.shape, fpol[-1])])
- return TokamakEquilibrium(
- R1D,
- Z1D,
- psi2D,
- psi1D,
- fpol,
+ return dict(
+ R1D=R1D,
+ Z1D=Z1D,
+ psi2D=psi2D,
+ psi1D=psi1D,
+ fpol1D=fpol,
pressure=pressure,
wall=wall,
- options=options,
- **kwargs,
+ )
+
+
+def read_geqdsk(filehandle, options=None, **kwargs):
+ """
+ Read geqdsk formatted data from a file object, returning
+ a TokamakEquilibrium object
+
+ Inputs
+ ------
+ filehandle A file handle to read
+ options Options|dict passed to TokamakEquilibrium
+ kwargs Other keywords passed to TokamakEquilibrim
+ These override values in options.
+
+ Options
+ -------
+ reverse_current = bool Changes the sign of poloidal flux psi
+ extrapolate_profiles = bool Extrapolate pressure using exponential
+ """
+
+ if options is None:
+ options = {}
+
+ return TokamakEquilibrium(
+ **just_read_geqdsk(filehandle), options=options, **kwargs,
)
diff --git a/hypnotoad/gui/gui.py b/hypnotoad/gui/gui.py
index 97337174..76983acc 100644
--- a/hypnotoad/gui/gui.py
+++ b/hypnotoad/gui/gui.py
@@ -4,12 +4,16 @@
"""
import ast
+import contextlib
import copy
-import options
+import functools
import os
import pathlib
import yaml
+import numpy as np
+import options
+
from Qt.QtWidgets import (
QFileDialog,
QMainWindow,
@@ -28,6 +32,7 @@
from ..cases import tokamak
from ..core.mesh import BoutMesh
from ..core.equilibrium import SolutionError
+from ..utils import critical
from ..__init__ import __version__
@@ -51,6 +56,29 @@ def _table_item_edit_display(item):
item.setText(item.text()[: -len(default_marker)])
+def psinorm_to_psi(psinorm, psi_axis, psi_sep):
+ if psinorm is None:
+ return None
+ return psi_axis + psinorm * (psi_sep[0] - psi_axis)
+
+
+def psi_to_psinorm(psi, psi_axis, psi_sep):
+ if psi is None:
+ return None
+ return (psi - psi_axis) / (psi_sep[0] - psi_axis)
+
+
+@contextlib.contextmanager
+def disconnected(signal, function):
+ """Temporarily disconnect a function from a signal
+
+ """
+ try:
+ yield signal.disconnect(function)
+ finally:
+ signal.connect(function)
+
+
class HypnotoadGui(QMainWindow, Ui_Hypnotoad):
"""A graphical interface for Hypnotoad
@@ -127,6 +155,125 @@ def set_clicked(widget, function):
self.options_form.itemDoubleClicked.connect(_table_item_edit_display)
self.update_options_form()
+ # Equilibrium tab
+ self.equilibrium_plot_widget = MatplotlibWidget(self.equilibrium_plotting_area)
+
+ set_clicked(self.eq_geqdsk_browse, self.eq_select_geqdsk_file)
+ self.eq_geqdsk_lineedit.editingFinished.connect(self.eq_read_geqdsk)
+
+ # Different limits in psi
+ self.psi_contours = {
+ "core": {
+ "unnorm_widget": self.psi_coreDoubleSpinBox,
+ "unnorm_slot": lambda value: self.update_linked_psi(
+ value, name="core", direction="norm"
+ ),
+ "norm_widget": self.psinorm_coreDoubleSpinBox,
+ "norm_slot": lambda value: self.update_linked_psi(
+ value, name="core", direction="unnorm"
+ ),
+ "style": "solid",
+ "enabled": True,
+ },
+ "sol": {
+ "unnorm_widget": self.psi_solDoubleSpinBox,
+ "unnorm_slot": lambda value: self.update_linked_psi(
+ value, name="sol", direction="norm"
+ ),
+ "norm_widget": self.psinorm_solDoubleSpinBox,
+ "norm_slot": lambda value: self.update_linked_psi(
+ value, name="sol", direction="unnorm"
+ ),
+ "style": "dashed",
+ "enabled": True,
+ },
+ "sol_inner": {
+ "unnorm_widget": self.psi_sol_innerDoubleSpinBox,
+ "unnorm_slot": lambda value: self.update_linked_psi(
+ value, name="sol_inner", direction="norm"
+ ),
+ "norm_widget": self.psinorm_sol_innerDoubleSpinBox,
+ "norm_slot": lambda value: self.update_linked_psi(
+ value, name="sol_inner", direction="unnorm"
+ ),
+ "style": "dotted",
+ "enabled": False,
+ "parent": "sol",
+ },
+ "pf": {
+ "unnorm_widget": self.psi_pfDoubleSpinBox,
+ "unnorm_slot": lambda value: self.update_linked_psi(
+ value, name="pf", direction="norm"
+ ),
+ "norm_widget": self.psinorm_pfDoubleSpinBox,
+ "norm_slot": lambda value: self.update_linked_psi(
+ value, name="pf", direction="unnorm"
+ ),
+ "style": "dashdot",
+ "enabled": False,
+ "parent": "core",
+ },
+ "pf_lower": {
+ "unnorm_widget": self.psi_pf_lowerDoubleSpinBox,
+ "unnorm_slot": lambda value: self.update_linked_psi(
+ value, name="pf_lower", direction="norm"
+ ),
+ "norm_widget": self.psinorm_pf_lowerDoubleSpinBox,
+ "norm_slot": lambda value: self.update_linked_psi(
+ value, name="pf_lower", direction="unnorm"
+ ),
+ "style": "dashdot",
+ "enabled": False,
+ "parent": "pf",
+ },
+ "pf_upper": {
+ "unnorm_widget": self.psi_pf_upperDoubleSpinBox,
+ "unnorm_slot": lambda value: self.update_linked_psi(
+ value, name="pf_upper", direction="norm"
+ ),
+ "norm_widget": self.psinorm_pf_upperDoubleSpinBox,
+ "norm_slot": lambda value: self.update_linked_psi(
+ value, name="pf_upper", direction="unnorm"
+ ),
+ "style": "dashdot",
+ "enabled": False,
+ "parent": "pf",
+ },
+ }
+
+ self.deal_with_separate_psi_contour(False, "sol_inner")
+ self.separateInnerSolCheckBox.stateChanged.connect(
+ lambda state: self.deal_with_separate_psi_contour(state, name="sol_inner")
+ )
+ self.deal_with_separate_psi_contour(False, "pf")
+ self.separatePrivateFluxCheckBox.stateChanged.connect(
+ lambda state: self.deal_with_separate_psi_contour(state, name="pf")
+ )
+ self.deal_with_separate_psi_contour(False, "pf_lower")
+ self.deal_with_separate_psi_contour(False, "pf_upper")
+ self.separate_upper_lowerPrivateFluxCheckBox.stateChanged.connect(
+ lambda state: self.deal_with_separate_psi_contour(state, name="pf_lower")
+ )
+ self.separate_upper_lowerPrivateFluxCheckBox.stateChanged.connect(
+ lambda state: self.deal_with_separate_psi_contour(state, name="pf_upper")
+ )
+
+ def add_to_and_update_options_form(value, name):
+ self.options[name] = value
+ self.update_options_form()
+
+ for name, contour in self.psi_contours.items():
+ contour["unnorm_widget"].valueChanged.connect(contour["unnorm_slot"])
+ contour["unnorm_widget"].valueChanged.connect(
+ functools.partial(add_to_and_update_options_form, name=f"psi_{name}")
+ )
+ contour["norm_widget"].valueChanged.connect(contour["norm_slot"])
+ contour["norm_widget"].valueChanged.connect(
+ functools.partial(
+ add_to_and_update_options_form, name=f"psinorm_{name}"
+ )
+ )
+
def help_about(self):
"""About Hypnotoad
@@ -385,8 +532,22 @@ def read_geqdsk(self):
return
try:
- with open(geqdsk_filename, "rt") as f:
- self.eq = tokamak.read_geqdsk(f, options=copy.deepcopy(self.options))
+ try:
+ self.eq = tokamak.TokamakEquilibrium(
+ self.eq_data["R1D"],
+ self.eq_data["Z1D"],
+ self.eq_data["psi2D"],
+ self.eq_data["psi1D"],
+ self.eq_data["fpol1D"],
+ self.eq_data["pressure"],
+ self.eq_data["wall"],
+ options=copy.deepcopy(self.options),
+ )
+ except AttributeError:
+ with open(geqdsk_filename, "rt") as f:
+ self.eq = tokamak.read_geqdsk(
+ f, options=copy.deepcopy(self.options)
+ )
except (ValueError, RuntimeError) as e:
error_message = QErrorMessage()
error_message.showMessage(str(e))
@@ -406,7 +567,7 @@ def run(self):
"""
- if not hasattr(self, "eq"):
+ if not (hasattr(self, "eq") or hasattr(self, "eq_data")):
self.statusbar.showMessage("Missing equilibrium file!")
self.geqdsk_file_line_edit.setStyleSheet(
f"QLineEdit {{ background-color: {COLOURS['red']} }}"
@@ -490,6 +651,208 @@ def plot_grid(self):
self.plot_widget.canvas.draw()
+ def eq_select_geqdsk_file(self):
+ """Choose a "geqdsk" equilibrium file to open
+
+ """
+
+ filename, _ = QFileDialog.getOpenFileName(self, "Open geqdsk file", ".")
+
+ if (filename is None) or (filename == ""):
+ return # Cancelled
+ if not os.path.exists(filename):
+ self.write("Could not find " + filename)
+ self.geqdsk_file_line_edit.setStyleSheet(
+ f"QLineEdit {{ background-color: {COLOURS['red']} }}"
+ )
+ return
+
+ self.eq_geqdsk_lineedit.setText(filename)
+ self.eq_geqdsk_lineedit.setStyleSheet("")
+
+ self.eq_read_geqdsk()
+
+ def eq_read_geqdsk(self):
+ """Read an equilibrium file
+
+ """
+
+ self.statusbar.showMessage("Reading geqdsk", 2000)
+ geqdsk_filename = self.eq_geqdsk_lineedit.text()
+
+ if not os.path.exists(geqdsk_filename):
+ self.geqdsk_file_line_edit.setStyleSheet(
+ f"QLineEdit {{ background-color : {COLOURS['red']} }}"
+ )
+ self.statusbar.showMessage(
+ f"Could not find equilibrium file '{geqdsk_filename}'"
+ )
+ return
+
+ try:
+ with open(geqdsk_filename, "rt") as f:
+ self.eq_data = tokamak.just_read_geqdsk(f)
+ except (ValueError, RuntimeError) as e:
+ error_message = QErrorMessage()
+ error_message.showMessage(str(e))
+ error_message.exec_()
+ return
+
+ self.R2D, self.Z2D = np.meshgrid(
+ self.eq_data["R1D"], self.eq_data["Z1D"], indexing="ij"
+ )
+ self.opoints, self.xpoints = critical.find_critical(
+ self.R2D, self.Z2D, self.eq_data["psi2D"]
+ )
+ self.eq_data["psi_axis"] = self.opoints[0][2]
+ self.eq_data["psi_sep"] = [x[2] for x in self.xpoints]
+ self.eq_data["Rmin"] = min(self.eq_data["R1D"])
+ self.eq_data["Rmax"] = max(self.eq_data["R1D"])
+ self.eq_data["Zmin"] = min(self.eq_data["Z1D"])
+ self.eq_data["Zmax"] = max(self.eq_data["Z1D"])
+
+ min_psi = self.eq_data["psi2D"].min()
+ max_psi = self.eq_data["psi2D"].max()
+
+ def setup_psi_widget(widget):
+ widget.setRange(min_psi, max_psi)
+ widget.setDecimals(4)
+ widget.setSingleStep(0.0001)
+
+ def setup_psinorm_widget(widget):
+ widget.setDecimals(4)
+ widget.setSingleStep(0.01)
+
+ for contour in self.psi_contours.values():
+ setup_psi_widget(contour["unnorm_widget"])
+ setup_psinorm_widget(contour["norm_widget"])
+
+ self.psinorm_coreDoubleSpinBox.setValue(
+ tokamak.TokamakEquilibrium.default_options["psinorm_core"]
+ )
+ self.psinorm_solDoubleSpinBox.setValue(
+ tokamak.TokamakEquilibrium.default_options["psinorm_sol"]
+ )
+
+ self.plot_equilibrium()
+
+ def deal_with_separate_psi_contour(self, state, name):
+ checked = state == Qt.Checked
+
+ contour = self.psi_contours[name]
+ parent = self.psi_contours[contour["parent"]]
+
+ self._remove_contour_from_plot(name, redraw=True)
+
+ contour["norm_widget"].setEnabled(checked)
+ contour["unnorm_widget"].setEnabled(checked)
+ contour["enabled"] = checked
+
+ if checked:
+ parent["norm_widget"].valueChanged.disconnect(
+ contour["norm_widget"].setValue
+ )
+ parent["unnorm_widget"].valueChanged.disconnect(
+ contour["unnorm_widget"].setValue
+ )
+ else:
+ parent["norm_widget"].valueChanged.connect(contour["norm_widget"].setValue)
+ parent["unnorm_widget"].valueChanged.connect(
+ contour["unnorm_widget"].setValue
+ )
+ contour["norm_widget"].setValue(parent["norm_widget"].value())
+ contour["unnorm_widget"].setValue(parent["unnorm_widget"].value())
+ try:
+ del self.options["psi_" + name]
+ except KeyError:
+ pass
+
+ def _remove_contour_from_plot(self, name, redraw=False):
+ """Remove named psi contour from equilibrium plot
+
+ """
+ try:
+ self.psi_contours[name]["plot"].collections[0].remove()
+ del self.psi_contours[name]["plot"]
+ if redraw:
+ self.equilibrium_plot_widget.canvas.draw()
+ except KeyError:
+ pass
+
+ def plot_equilibrium(self):
+ """Plot preliminary-equilibrium and psi contours
+ """
+ for contour in self.psi_contours:
+ self._remove_contour_from_plot(contour)
+
+ self.equilibrium_plot_widget.clear()
+
+ if not hasattr(self, "eq_data"):
+ return
+ self.statusbar.showMessage("plotting equilibrium", 2000)
+ self.equilibrium_plot_widget.axes.contour(
+ self.eq_data["R1D"], self.eq_data["Z1D"], self.eq_data["psi2D"].T, levels=40
+ )
+ for num, opoint in enumerate(self.opoints):
+ self.equilibrium_plot_widget.axes.plot(
+ opoint[0], opoint[1], "o", label=f"O-point {num}"
+ )
+ for num, xpoint in enumerate(self.xpoints):
+ self.equilibrium_plot_widget.axes.plot(
+ xpoint[0], xpoint[1], "x", label=f"X-point {num}"
+ )
+ self.equilibrium_plot_widget.canvas.draw()
+
+ for contour in self.psi_contours:
+ self.plot_single_psi_contour(contour)
+
+ def update_linked_psi(self, value, name, direction):
+ """Update the value of the normalised/unnormalised psi widget
+
+ """
+ contour = self.psi_contours[name]
+ widget = direction + "_widget"
+ slot = direction + "_slot"
+
+ if direction == "norm":
+ conversion = psi_to_psinorm
+ elif direction == "unnorm":
+ conversion = psinorm_to_psi
+ else:
+ raise ValueError("Direction must be 'unnorm' or 'norm'")
+
+ with disconnected(contour[widget].valueChanged, contour[slot]):
+ contour[widget].setValue(
+ conversion(value, self.eq_data["psi_axis"], self.eq_data["psi_sep"])
+ )
+ self.plot_single_psi_contour(name)
+
+ def plot_single_psi_contour(self, name):
+ """Plot a single psi contour onto the equilibrium plot
+ """
+ if not hasattr(self, "eq_data"):
+ return
+
+ self._remove_contour_from_plot(name)
+
+ # Nicer local name
+ contour = self.psi_contours[name]
+
+ if not contour["enabled"]:
+ return
+
+ self.psi_contours[name]["plot"] = self.equilibrium_plot_widget.axes.contour(
+ self.eq_data["R1D"],
+ self.eq_data["Z1D"],
+ self.eq_data["psi2D"].T,
+ levels=[contour["unnorm_widget"].value()],
+ colors="k",
+ linewidths=3,
+ linestyles=contour["style"],
+ )
+
+ self.equilibrium_plot_widget.canvas.draw()
+
class Preferences(QDialog, Ui_Preferences):
"""Dialog box for editing Hypnotoad preferences
diff --git a/hypnotoad/gui/hypnotoad_mainWindow.py b/hypnotoad/gui/hypnotoad_mainWindow.py
index 2d770ace..f3d3ea1e 100644
--- a/hypnotoad/gui/hypnotoad_mainWindow.py
+++ b/hypnotoad/gui/hypnotoad_mainWindow.py
@@ -113,22 +113,245 @@ def setupUi(self, Hypnotoad):
self.action_Revert.setIcon(icon8)
self.action_Preferences = QAction(Hypnotoad)
self.action_Preferences.setObjectName(u"action_Preferences")
- icon9 = QIcon(QIcon.fromTheme(u"document-properties"))
+ icon9 = QIcon()
+ iconThemeName = u"document-properties"
+ if QIcon.hasThemeIcon(iconThemeName):
+ icon9 = QIcon.fromTheme(iconThemeName)
+ else:
+ icon9.addFile(u".", QSize(), QIcon.Normal, QIcon.Off)
+
self.action_Preferences.setIcon(icon9)
self.centralwidget = QWidget(Hypnotoad)
self.centralwidget.setObjectName(u"centralwidget")
- self.horizontalLayout_2 = QHBoxLayout(self.centralwidget)
+ self.verticalLayout = QVBoxLayout(self.centralwidget)
+ self.verticalLayout.setObjectName(u"verticalLayout")
+ self.tabWidget = QTabWidget(self.centralwidget)
+ self.tabWidget.setObjectName(u"tabWidget")
+ self.equilibrium_tab = QWidget()
+ self.equilibrium_tab.setObjectName(u"equilibrium_tab")
+ self.horizontalLayout_2 = QHBoxLayout(self.equilibrium_tab)
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
+ self.verticalLayout_5 = QVBoxLayout()
+ self.verticalLayout_5.setObjectName(u"verticalLayout_5")
+ self.horizontalLayout_4 = QHBoxLayout()
+ self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
+ self.eq_geqdsk_label = QLabel(self.equilibrium_tab)
+ self.eq_geqdsk_label.setObjectName(u"eq_geqdsk_label")
+
+ self.horizontalLayout_4.addWidget(self.eq_geqdsk_label)
+
+ self.eq_geqdsk_lineedit = QLineEdit(self.equilibrium_tab)
+ self.eq_geqdsk_lineedit.setObjectName(u"eq_geqdsk_lineedit")
+
+ self.horizontalLayout_4.addWidget(self.eq_geqdsk_lineedit)
+
+ self.eq_geqdsk_browse = QPushButton(self.equilibrium_tab)
+ self.eq_geqdsk_browse.setObjectName(u"eq_geqdsk_browse")
+
+ self.horizontalLayout_4.addWidget(self.eq_geqdsk_browse)
+
+
+ self.verticalLayout_5.addLayout(self.horizontalLayout_4)
+
+ self.normalised_psi_box = QGroupBox(self.equilibrium_tab)
+ self.normalised_psi_box.setObjectName(u"normalised_psi_box")
+ self.formLayoutWidget = QWidget(self.normalised_psi_box)
+ self.formLayoutWidget.setObjectName(u"formLayoutWidget")
+ self.formLayoutWidget.setGeometry(QRect(10, 30, 361, 263))
+ self.formLayout_2 = QFormLayout(self.formLayoutWidget)
+ self.formLayout_2.setObjectName(u"formLayout_2")
+ self.formLayout_2.setSizeConstraint(QLayout.SetDefaultConstraint)
+ self.formLayout_2.setContentsMargins(0, 0, 0, 0)
+ self.psinorm_coreLabel = QLabel(self.formLayoutWidget)
+ self.psinorm_coreLabel.setObjectName(u"psinorm_coreLabel")
+
+ self.formLayout_2.setWidget(1, QFormLayout.LabelRole, self.psinorm_coreLabel)
+
+ self.psinorm_coreDoubleSpinBox = QDoubleSpinBox(self.formLayoutWidget)
+ self.psinorm_coreDoubleSpinBox.setObjectName(u"psinorm_coreDoubleSpinBox")
+
+ self.formLayout_2.setWidget(1, QFormLayout.FieldRole, self.psinorm_coreDoubleSpinBox)
+
+ self.psinorm_solLabel = QLabel(self.formLayoutWidget)
+ self.psinorm_solLabel.setObjectName(u"psinorm_solLabel")
+
+ self.formLayout_2.setWidget(2, QFormLayout.LabelRole, self.psinorm_solLabel)
+
+ self.psinorm_solDoubleSpinBox = QDoubleSpinBox(self.formLayoutWidget)
+ self.psinorm_solDoubleSpinBox.setObjectName(u"psinorm_solDoubleSpinBox")
+
+ self.formLayout_2.setWidget(2, QFormLayout.FieldRole, self.psinorm_solDoubleSpinBox)
+
+ self.separateInnerSolLabel = QLabel(self.formLayoutWidget)
+ self.separateInnerSolLabel.setObjectName(u"separateInnerSolLabel")
+
+ self.formLayout_2.setWidget(3, QFormLayout.LabelRole, self.separateInnerSolLabel)
+
+ self.separateInnerSolCheckBox = QCheckBox(self.formLayoutWidget)
+ self.separateInnerSolCheckBox.setObjectName(u"separateInnerSolCheckBox")
+
+ self.formLayout_2.setWidget(3, QFormLayout.FieldRole, self.separateInnerSolCheckBox)
+
+ self.innerSolLabel = QLabel(self.formLayoutWidget)
+ self.innerSolLabel.setObjectName(u"innerSolLabel")
+
+ self.formLayout_2.setWidget(4, QFormLayout.LabelRole, self.innerSolLabel)
+
+ self.psinorm_sol_innerDoubleSpinBox = QDoubleSpinBox(self.formLayoutWidget)
+ self.psinorm_sol_innerDoubleSpinBox.setObjectName(u"psinorm_sol_innerDoubleSpinBox")
+
+ self.formLayout_2.setWidget(4, QFormLayout.FieldRole, self.psinorm_sol_innerDoubleSpinBox)
+
+ self.separatePrivateFluxLabel = QLabel(self.formLayoutWidget)
+ self.separatePrivateFluxLabel.setObjectName(u"separatePrivateFluxLabel")
+
+ self.formLayout_2.setWidget(5, QFormLayout.LabelRole, self.separatePrivateFluxLabel)
+
+ self.separatePrivateFluxCheckBox = QCheckBox(self.formLayoutWidget)
+ self.separatePrivateFluxCheckBox.setObjectName(u"separatePrivateFluxCheckBox")
+
+ self.formLayout_2.setWidget(5, QFormLayout.FieldRole, self.separatePrivateFluxCheckBox)
+
+ self.psinorm_pfLabel = QLabel(self.formLayoutWidget)
+ self.psinorm_pfLabel.setObjectName(u"psinorm_pfLabel")
+
+ self.formLayout_2.setWidget(6, QFormLayout.LabelRole, self.psinorm_pfLabel)
+
+ self.psinorm_pfDoubleSpinBox = QDoubleSpinBox(self.formLayoutWidget)
+ self.psinorm_pfDoubleSpinBox.setObjectName(u"psinorm_pfDoubleSpinBox")
+
+ self.formLayout_2.setWidget(6, QFormLayout.FieldRole, self.psinorm_pfDoubleSpinBox)
+
+ self.separateInnerPrivateFluxLabel = QLabel(self.formLayoutWidget)
+ self.separateInnerPrivateFluxLabel.setObjectName(u"separateInnerPrivateFluxLabel")
+
+ self.formLayout_2.setWidget(7, QFormLayout.LabelRole, self.separateInnerPrivateFluxLabel)
+
+ self.separate_upper_lowerPrivateFluxCheckBox = QCheckBox(self.formLayoutWidget)
+ self.separate_upper_lowerPrivateFluxCheckBox.setObjectName(u"separate_upper_lowerPrivateFluxCheckBox")
+
+ self.formLayout_2.setWidget(7, QFormLayout.FieldRole, self.separate_upper_lowerPrivateFluxCheckBox)
+
+ self.psinorm_pf_upperLabel = QLabel(self.formLayoutWidget)
+ self.psinorm_pf_upperLabel.setObjectName(u"psinorm_pf_upperLabel")
+
+ self.formLayout_2.setWidget(8, QFormLayout.LabelRole, self.psinorm_pf_upperLabel)
+
+ self.psinorm_pf_upperDoubleSpinBox = QDoubleSpinBox(self.formLayoutWidget)
+ self.psinorm_pf_upperDoubleSpinBox.setObjectName(u"psinorm_pf_upperDoubleSpinBox")
+
+ self.formLayout_2.setWidget(8, QFormLayout.FieldRole, self.psinorm_pf_upperDoubleSpinBox)
+
+ self.psinorm_pf_lowerLabel = QLabel(self.formLayoutWidget)
+ self.psinorm_pf_lowerLabel.setObjectName(u"psinorm_pf_lowerLabel")
+
+ self.formLayout_2.setWidget(9, QFormLayout.LabelRole, self.psinorm_pf_lowerLabel)
+
+ self.psinorm_pf_lowerDoubleSpinBox = QDoubleSpinBox(self.formLayoutWidget)
+ self.psinorm_pf_lowerDoubleSpinBox.setObjectName(u"psinorm_pf_lowerDoubleSpinBox")
+
+ self.formLayout_2.setWidget(9, QFormLayout.FieldRole, self.psinorm_pf_lowerDoubleSpinBox)
+
+
+ self.verticalLayout_5.addWidget(self.normalised_psi_box)
+
+ self.unnormalised_psi_box = QGroupBox(self.equilibrium_tab)
+ self.unnormalised_psi_box.setObjectName(u"unnormalised_psi_box")
+ self.formLayoutWidget_2 = QWidget(self.unnormalised_psi_box)
+ self.formLayoutWidget_2.setObjectName(u"formLayoutWidget_2")
+ self.formLayoutWidget_2.setGeometry(QRect(10, 20, 361, 217))
+ self.formLayout_4 = QFormLayout(self.formLayoutWidget_2)
+ self.formLayout_4.setObjectName(u"formLayout_4")
+ self.formLayout_4.setSizeConstraint(QLayout.SetMaximumSize)
+ self.formLayout_4.setContentsMargins(0, 0, 0, 0)
+ self.psi_coreLabel = QLabel(self.formLayoutWidget_2)
+ self.psi_coreLabel.setObjectName(u"psi_coreLabel")
+
+ self.formLayout_4.setWidget(0, QFormLayout.LabelRole, self.psi_coreLabel)
+
+ self.psi_coreDoubleSpinBox = QDoubleSpinBox(self.formLayoutWidget_2)
+ self.psi_coreDoubleSpinBox.setObjectName(u"psi_coreDoubleSpinBox")
+
+ self.formLayout_4.setWidget(0, QFormLayout.FieldRole, self.psi_coreDoubleSpinBox)
+
+ self.psi_solLabel = QLabel(self.formLayoutWidget_2)
+ self.psi_solLabel.setObjectName(u"psi_solLabel")
+
+ self.formLayout_4.setWidget(1, QFormLayout.LabelRole, self.psi_solLabel)
+
+ self.psi_solDoubleSpinBox = QDoubleSpinBox(self.formLayoutWidget_2)
+ self.psi_solDoubleSpinBox.setObjectName(u"psi_solDoubleSpinBox")
+
+ self.formLayout_4.setWidget(1, QFormLayout.FieldRole, self.psi_solDoubleSpinBox)
+
+ self.psi_sol_innerLabel = QLabel(self.formLayoutWidget_2)
+ self.psi_sol_innerLabel.setObjectName(u"psi_sol_innerLabel")
+
+ self.formLayout_4.setWidget(2, QFormLayout.LabelRole, self.psi_sol_innerLabel)
+
+ self.psi_sol_innerDoubleSpinBox = QDoubleSpinBox(self.formLayoutWidget_2)
+ self.psi_sol_innerDoubleSpinBox.setObjectName(u"psi_sol_innerDoubleSpinBox")
+
+ self.formLayout_4.setWidget(2, QFormLayout.FieldRole, self.psi_sol_innerDoubleSpinBox)
+
+ self.psi_pf_upperLabel = QLabel(self.formLayoutWidget_2)
+ self.psi_pf_upperLabel.setObjectName(u"psi_pf_upperLabel")
+
+ self.formLayout_4.setWidget(4, QFormLayout.LabelRole, self.psi_pf_upperLabel)
+
+ self.psi_pf_upperDoubleSpinBox = QDoubleSpinBox(self.formLayoutWidget_2)
+ self.psi_pf_upperDoubleSpinBox.setObjectName(u"psi_pf_upperDoubleSpinBox")
+
+ self.formLayout_4.setWidget(4, QFormLayout.FieldRole, self.psi_pf_upperDoubleSpinBox)
+
+ self.psi_pf_lowerLabel = QLabel(self.formLayoutWidget_2)
+ self.psi_pf_lowerLabel.setObjectName(u"psi_pf_lowerLabel")
+
+ self.formLayout_4.setWidget(5, QFormLayout.LabelRole, self.psi_pf_lowerLabel)
+
+ self.psi_pf_lowerDoubleSpinBox = QDoubleSpinBox(self.formLayoutWidget_2)
+ self.psi_pf_lowerDoubleSpinBox.setObjectName(u"psi_pf_lowerDoubleSpinBox")
+
+ self.formLayout_4.setWidget(5, QFormLayout.FieldRole, self.psi_pf_lowerDoubleSpinBox)
+
+ self.psi_pfLabel = QLabel(self.formLayoutWidget_2)
+ self.psi_pfLabel.setObjectName(u"psi_pfLabel")
+
+ self.formLayout_4.setWidget(3, QFormLayout.LabelRole, self.psi_pfLabel)
+
+ self.psi_pfDoubleSpinBox = QDoubleSpinBox(self.formLayoutWidget_2)
+ self.psi_pfDoubleSpinBox.setObjectName(u"psi_pfDoubleSpinBox")
+
+ self.formLayout_4.setWidget(3, QFormLayout.FieldRole, self.psi_pfDoubleSpinBox)
+
+
+ self.verticalLayout_5.addWidget(self.unnormalised_psi_box)
+
+
+ self.horizontalLayout_2.addLayout(self.verticalLayout_5)
+
+ self.equilibrium_plotting_area = QFrame(self.equilibrium_tab)
+ self.equilibrium_plotting_area.setObjectName(u"equilibrium_plotting_area")
+ self.equilibrium_plotting_area.setFrameShape(QFrame.StyledPanel)
+ self.equilibrium_plotting_area.setFrameShadow(QFrame.Raised)
+
+ self.horizontalLayout_2.addWidget(self.equilibrium_plotting_area)
+
+ self.tabWidget.addTab(self.equilibrium_tab, "")
+ self.mesh_tab = QWidget()
+ self.mesh_tab.setObjectName(u"mesh_tab")
+ self.verticalLayout_3 = QVBoxLayout(self.mesh_tab)
+ self.verticalLayout_3.setObjectName(u"verticalLayout_3")
self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.verticalLayout_2 = QVBoxLayout()
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
- self.search_bar = QLineEdit(self.centralwidget)
+ self.search_bar = QLineEdit(self.mesh_tab)
self.search_bar.setObjectName(u"search_bar")
self.verticalLayout_2.addWidget(self.search_bar)
- self.options_form = QTableWidget(self.centralwidget)
+ self.options_form = QTableWidget(self.mesh_tab)
if (self.options_form.columnCount() < 2):
self.options_form.setColumnCount(2)
__qtablewidgetitem = QTableWidgetItem()
@@ -141,42 +364,42 @@ def setupUi(self, Hypnotoad):
self.horizontalLayout_3 = QHBoxLayout()
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
- self.options_file_label = QLabel(self.centralwidget)
+ self.options_file_label = QLabel(self.mesh_tab)
self.options_file_label.setObjectName(u"options_file_label")
self.horizontalLayout_3.addWidget(self.options_file_label)
- self.options_file_line_edit = QLineEdit(self.centralwidget)
+ self.options_file_line_edit = QLineEdit(self.mesh_tab)
self.options_file_line_edit.setObjectName(u"options_file_line_edit")
self.horizontalLayout_3.addWidget(self.options_file_line_edit)
- self.options_file_browse_button = QPushButton(self.centralwidget)
+ self.options_file_browse_button = QPushButton(self.mesh_tab)
self.options_file_browse_button.setObjectName(u"options_file_browse_button")
self.horizontalLayout_3.addWidget(self.options_file_browse_button)
- self.geqdsk_file_label = QLabel(self.centralwidget)
+ self.geqdsk_file_label = QLabel(self.mesh_tab)
self.geqdsk_file_label.setObjectName(u"geqdsk_file_label")
self.horizontalLayout_3.addWidget(self.geqdsk_file_label)
- self.geqdsk_file_line_edit = QLineEdit(self.centralwidget)
+ self.geqdsk_file_line_edit = QLineEdit(self.mesh_tab)
self.geqdsk_file_line_edit.setObjectName(u"geqdsk_file_line_edit")
self.horizontalLayout_3.addWidget(self.geqdsk_file_line_edit)
- self.geqdsk_file_browse_button = QPushButton(self.centralwidget)
+ self.geqdsk_file_browse_button = QPushButton(self.mesh_tab)
self.geqdsk_file_browse_button.setObjectName(u"geqdsk_file_browse_button")
self.horizontalLayout_3.addWidget(self.geqdsk_file_browse_button)
- self.run_button = QPushButton(self.centralwidget)
+ self.run_button = QPushButton(self.mesh_tab)
self.run_button.setObjectName(u"run_button")
self.horizontalLayout_3.addWidget(self.run_button)
- self.write_grid_button = QPushButton(self.centralwidget)
+ self.write_grid_button = QPushButton(self.mesh_tab)
self.write_grid_button.setObjectName(u"write_grid_button")
self.horizontalLayout_3.addWidget(self.write_grid_button)
@@ -187,13 +410,17 @@ def setupUi(self, Hypnotoad):
self.horizontalLayout.addLayout(self.verticalLayout_2)
- self.plottingArea = QWidget(self.centralwidget)
+ self.plottingArea = QFrame(self.mesh_tab)
self.plottingArea.setObjectName(u"plottingArea")
self.horizontalLayout.addWidget(self.plottingArea)
- self.horizontalLayout_2.addLayout(self.horizontalLayout)
+ self.verticalLayout_3.addLayout(self.horizontalLayout)
+
+ self.tabWidget.addTab(self.mesh_tab, "")
+
+ self.verticalLayout.addWidget(self.tabWidget)
Hypnotoad.setCentralWidget(self.centralwidget)
self.menubar = QMenuBar(Hypnotoad)
@@ -236,6 +463,9 @@ def setupUi(self, Hypnotoad):
self.retranslateUi(Hypnotoad)
+ self.tabWidget.setCurrentIndex(0)
+
+
QMetaObject.connectSlotsByName(Hypnotoad)
# setupUi
@@ -275,6 +505,26 @@ def retranslateUi(self, Hypnotoad):
#endif // QT_CONFIG(shortcut)
self.action_Revert.setText(QCoreApplication.translate("Hypnotoad", u"&Revert", None))
self.action_Preferences.setText(QCoreApplication.translate("Hypnotoad", u"&Preferences...", None))
+ self.eq_geqdsk_label.setText(QCoreApplication.translate("Hypnotoad", u"geqdsk file", None))
+ self.eq_geqdsk_browse.setText(QCoreApplication.translate("Hypnotoad", u"Browse", None))
+ self.normalised_psi_box.setTitle(QCoreApplication.translate("Hypnotoad", u"Normalised Psi", None))
+ self.psinorm_coreLabel.setText(QCoreApplication.translate("Hypnotoad", u"Core", None))
+ self.psinorm_solLabel.setText(QCoreApplication.translate("Hypnotoad", u"SOL", None))
+ self.separateInnerSolLabel.setText(QCoreApplication.translate("Hypnotoad", u"Separate inner SOL", None))
+ self.innerSolLabel.setText(QCoreApplication.translate("Hypnotoad", u"Inner SOL", None))
+ self.separatePrivateFluxLabel.setText(QCoreApplication.translate("Hypnotoad", u"Separate private flux", None))
+ self.psinorm_pfLabel.setText(QCoreApplication.translate("Hypnotoad", u"PF", None))
+ self.separateInnerPrivateFluxLabel.setText(QCoreApplication.translate("Hypnotoad", u"Separate upper/lower private flux", None))
+ self.psinorm_pf_upperLabel.setText(QCoreApplication.translate("Hypnotoad", u"Upper PF", None))
+ self.psinorm_pf_lowerLabel.setText(QCoreApplication.translate("Hypnotoad", u"Lower PF", None))
+ self.unnormalised_psi_box.setTitle(QCoreApplication.translate("Hypnotoad", u"Unormalised Psi", None))
+ self.psi_coreLabel.setText(QCoreApplication.translate("Hypnotoad", u"Core", None))
+ self.psi_solLabel.setText(QCoreApplication.translate("Hypnotoad", u"SOL", None))
+ self.psi_sol_innerLabel.setText(QCoreApplication.translate("Hypnotoad", u"Inner sol", None))
+ self.psi_pf_upperLabel.setText(QCoreApplication.translate("Hypnotoad", u"Lower PF", None))
+ self.psi_pf_lowerLabel.setText(QCoreApplication.translate("Hypnotoad", u"Upper PF", None))
+ self.psi_pfLabel.setText(QCoreApplication.translate("Hypnotoad", u"PF", None))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.equilibrium_tab), QCoreApplication.translate("Hypnotoad", u"&Equilibrium", None))
___qtablewidgetitem = self.options_form.horizontalHeaderItem(0)
___qtablewidgetitem.setText(QCoreApplication.translate("Hypnotoad", u"Name", None));
___qtablewidgetitem1 = self.options_form.horizontalHeaderItem(1)
@@ -285,6 +535,7 @@ def retranslateUi(self, Hypnotoad):
self.geqdsk_file_browse_button.setText(QCoreApplication.translate("Hypnotoad", u"Browse", None))
self.run_button.setText(QCoreApplication.translate("Hypnotoad", u"Run", None))
self.write_grid_button.setText(QCoreApplication.translate("Hypnotoad", u"Write Grid", None))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.mesh_tab), QCoreApplication.translate("Hypnotoad", u"&Mesh", None))
self.menu_File.setTitle(QCoreApplication.translate("Hypnotoad", u"&File", None))
self.menu_Help.setTitle(QCoreApplication.translate("Hypnotoad", u"&Help", None))
self.menu_Mesh.setTitle(QCoreApplication.translate("Hypnotoad", u"&Mesh", None))
diff --git a/hypnotoad/gui/hypnotoad_mainWindow.ui b/hypnotoad/gui/hypnotoad_mainWindow.ui
index d3c6aa07..61c51cc3 100644
--- a/hypnotoad/gui/hypnotoad_mainWindow.ui
+++ b/hypnotoad/gui/hypnotoad_mainWindow.ui
@@ -14,86 +14,336 @@
MainWindow
-
+
-
-
-
-
-
+
+
+ 0
+
+
+
+ &Equilibrium
+
+
-
-
-
- -
-
-
-
- Name
-
-
-
-
- Value
-
-
-
-
- -
-
-
-
-
-
- Options file
-
-
-
+
-
-
+
+
-
+
+
+ geqdsk file
+
+
+
+ -
+
+
+ -
+
+
+ Browse
+
+
+
+
-
-
-
- Browse
+
+
+ Normalised Psi
+
+
+
+ 10
+ 30
+ 361
+ 263
+
+
+
+
+ QLayout::SetDefaultConstraint
+
+
-
+
+
+ Core
+
+
+
+ -
+
+
+ -
+
+
+ SOL
+
+
+
+ -
+
+
+ -
+
+
+ Separate inner SOL
+
+
+
+ -
+
+
+ -
+
+
+ Inner SOL
+
+
+
+ -
+
+
+ -
+
+
+ Separate private flux
+
+
+
+ -
+
+
+ -
+
+
+ PF
+
+
+
+ -
+
+
+ -
+
+
+ Separate upper/lower private flux
+
+
+
+ -
+
+
+ -
+
+
+ Upper PF
+
+
+
+ -
+
+
+ -
+
+
+ Lower PF
+
+
+
+ -
+
+
+
+
-
-
-
- geqdsk file
+
+
+ Unormalised Psi
+
+
+
+ 10
+ 20
+ 361
+ 217
+
+
+
+
+ QLayout::SetMaximumSize
+
+
-
+
+
+ Core
+
+
+
+ -
+
+
+ -
+
+
+ SOL
+
+
+
+ -
+
+
+ -
+
+
+ Inner sol
+
+
+
+ -
+
+
+ -
+
+
+ Upper PF
+
+
+
+ -
+
+
+ -
+
+
+ Lower PF
+
+
+
+ -
+
+
+ -
+
+
+ PF
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
+
+
+
+
+ &Mesh
+
+
+ -
+
-
-
-
- -
-
-
- Browse
-
-
-
- -
-
-
- Run
-
-
+
+
-
+
+
+ -
+
+
+
+ Name
+
+
+
+
+ Value
+
+
+
+
+ -
+
+
-
+
+
+ Options file
+
+
+
+ -
+
+
+ -
+
+
+ Browse
+
+
+
+ -
+
+
+ geqdsk file
+
+
+
+ -
+
+
+ -
+
+
+ Browse
+
+
+
+ -
+
+
+ Run
+
+
+
+ -
+
+
+ Write Grid
+
+
+
+
+
+
-
-
-
- Write Grid
-
-
+
-
- -
-
-
-
+
+
@@ -261,7 +511,8 @@
-
+
+ ..
&Preferences...