Skip to content

Commit

Permalink
Merge pull request #91 from DLR-AE/feature_hs2_import_classification
Browse files Browse the repository at this point in the history
feature(haswstab2): created numbering 1st, 2nd , ... for HAWCStab2 mo…
  • Loading branch information
hendrikverdonck authored Nov 27, 2024
2 parents 38d71ea + 57043ce commit dad7161
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 36 deletions.
3 changes: 2 additions & 1 deletion campbellviewer/data_storage/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ def add_data(self, name, tool, tool_specific_info={}):
if key == 'filenamecmb':
self['HAWCStab2'][name].read_cmb_data(value, tool_specific_info['skip_header_CMB'])
elif key == 'filenameamp':
self['HAWCStab2'][name].read_amp_data(value, tool_specific_info['skip_header_AMP'])
self['HAWCStab2'][name].read_amp_data(value, tool_specific_info['skip_header_AMP'],
tool_specific_info['override_mode_names'])
elif key == 'filenameopt':
self['HAWCStab2'][name].read_opt_data(value, tool_specific_info['skip_header_OP'])
else:
Expand Down
23 changes: 17 additions & 6 deletions campbellviewer/dialogs/dialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from PyQt5.QtCore import Qt, QSettings, pyqtSignal, pyqtSlot

from campbellviewer.settings.globals import view_cfg, database
from campbellviewer.utilities import safe_bool_conversion

####
# Popup setting dialogs
Expand Down Expand Up @@ -206,6 +207,9 @@ class SettingsHS2(QWidget):
skip_header_CMB (int): Number of header lines in the .cmb file
skip_header_AMP (int): Number of header lines in the .amp file
skip_header_OP (int): Number of header lines in the .opt file
override_mode_names(bool): flag, which defines, whether the first three modes
in amp file shall be renamed to 'lag mode',
'1st Tower SS','1st Tower FA', default is True
"""
def __init__(self, qsettings: QSettings) -> None:
"""Initializes popup for HAWCStab2 input file header line definitions
Expand All @@ -221,32 +225,39 @@ def __init__(self, qsettings: QSettings) -> None:
layout.setAlignment(Qt.AlignLeft|Qt.AlignTop)

# try to fetch the data from qsettings, otherwise take default
self.skip_header_CMB = int(self.__qsettings.value('skip_header_CMB', 1)) # default to 1
self.skip_header_AMP = int(self.__qsettings.value('skip_header_AMP', 5)) # default to 5
self.skip_header_OP = int(self.__qsettings.value('skip_header_OP' , 1)) # default to 6
self.skip_header_CMB = int(self.__qsettings.value('skip_header_CMB' , 1 )) # default to 1
self.skip_header_AMP = int(self.__qsettings.value('skip_header_AMP' , 5 )) # default to 5
self.skip_header_OP = int(self.__qsettings.value('skip_header_OP' , 1 )) # default to 6
self.override_mode_names = safe_bool_conversion(self.__qsettings.value('override_mode_names', True)) # default to True

layout.addWidget(QLabel("<b>HAWCStab2: Header lines to skip</b>"), 0,0,1,2)
headerLinesCMBL = QLabel('Number of header lines in Campbell file:')
headerLinesAMPL = QLabel('Number of header lines in Amplitude file:')
headerLinesOPL = QLabel('Number of header lines in Operational data file:')
headerLinesOMN = QLabel('Flag for overriding first three mode names:')
layout.addWidget(headerLinesCMBL, 1,0,1,1)
layout.addWidget(headerLinesAMPL, 2,0,1,1)
layout.addWidget(headerLinesOPL , 3,0,1,1)
layout.addWidget(headerLinesOMN , 4,0,1,1)
self.__headerLinesCMBE = QSpinBox()
self.__headerLinesAMPE = QSpinBox()
self.__headerLinesOPE = QSpinBox()
self.__headerLinesOME = QCheckBox()
self.__headerLinesCMBE.setValue(self.skip_header_CMB)
self.__headerLinesAMPE.setValue(self.skip_header_AMP)
self.__headerLinesOPE.setValue(self.skip_header_OP)
self.__headerLinesOME.setChecked(self.override_mode_names)
layout.addWidget(self.__headerLinesCMBE, 1,1,1,1)
layout.addWidget(self.__headerLinesAMPE, 2,1,1,1)
layout.addWidget(self.__headerLinesOPE , 3,1,1,1)
layout.addWidget(self.__headerLinesOME , 4,1,1,1)

def save_settings(self):
"""save the settings"""
self.__qsettings.setValue('skip_header_CMB',self.__headerLinesCMBE.value())
self.__qsettings.setValue('skip_header_AMP',self.__headerLinesAMPE.value())
self.__qsettings.setValue('skip_header_OP' ,self.__headerLinesOPE.value())
self.__qsettings.setValue('skip_header_CMB' ,self.__headerLinesCMBE.value())
self.__qsettings.setValue('skip_header_AMP' ,self.__headerLinesAMPE.value())
self.__qsettings.setValue('skip_header_OP' ,self.__headerLinesOPE.value())
self.__qsettings.setValue('override_mode_names',self.__headerLinesOME.isChecked())

########################################################################################################################
class SettingsPopup(QDialog):
Expand Down
40 changes: 31 additions & 9 deletions campbellviewer/interfaces/hawcstab2.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
"""

import numpy as np
from typing import Optional

from campbellviewer.data_storage.data_template import AbstractLinearizationData
from campbellviewer.utilities import AEMode


class HAWCStab2Data(AbstractLinearizationData):
"""This is a class for handling HAWCStab2 linearization data.
r"""This is a class for handling HAWCStab2 linearization data.
Attributes:
ds (xarray.Dataset): xarray Dataset containing all linearization data
Expand Down Expand Up @@ -93,7 +94,10 @@ def read_cmb_data(self, filenamecmb:str=None, skip_header_lines:int=1):
)


def read_amp_data(self, filenameamp:str=None, skip_header_lines:int=5):
def read_amp_data(self,
filenameamp:str,
skip_header_lines: Optional[int]=5,
override_mode_names: Optional[bool]=True):
"""Reads and parse the HS2 result amp data.
- The first 5 rows contains header text.
Expand All @@ -115,6 +119,13 @@ def read_amp_data(self, filenameamp:str=None, skip_header_lines:int=5):
Sym tors[rad] phase [deg]
BW tors [rad] phase [deg]
FW tors [rad] phase [deg]
Args:
filenameamp: filename of the amp file
skip_header_lines: parameter to skip the comment rows in amp file
override_mode_names: flag, which defines, whether the first three modes
in amp file shall be renamed to 'lag mode',
'1st Tower SS','1st Tower FA', default is True
"""

Expand Down Expand Up @@ -181,14 +192,25 @@ def read_amp_data(self, filenameamp:str=None, skip_header_lines:int=5):
)

# Determine dominant DOF per mode
shape_numbering = {1 : '1st', 2 : '2nd', 3 : '3rd'}
for i in range(4,20):
shape_numbering[i] =f'{i}th'
mode_names = []
for i_mode in range(0, num_modes):
mean_dof = np.mean(amp_data[:, :, i_mode], axis=0)
mode_names.append(sensor_list[np.argmax(mean_dof)])

# Override first tower mode
if mode_names[2] == sensor_list[0]:
mode_names[1] = sensor_list[1]
reoccurant_mode_shape = {}
for shape_name in sensor_list:
reoccurant_mode_shape[shape_name.strip()] = 0
for i_mode in range(0,num_modes):
mean_DOF = np.mean(amp_data[:,:,i_mode],axis=0)
shape_name = sensor_list[np.argmax(mean_DOF)].strip()
reoccurant_mode_shape[shape_name] += 1
mode_names.append(f'{shape_numbering[reoccurant_mode_shape[shape_name]]} {shape_name}')

# Override data for first two modes, because in HAWCStab2 tower amplitudes are not 1.0 although it is a tower mode.
# Unfortunately, higher tower modes cannot be filtered easyly.
if override_mode_names:
mode_names[0]='lag mode'
mode_names[1]='1st Tower FA'
mode_names[2]='1st Tower SS'

# Make sure mode names are unique -> mode names are used as indices in xarrays
# unique_mode_names = []
Expand Down
42 changes: 22 additions & 20 deletions campbellviewer/main_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
SettingsPopupAMP,
GeneralSettingsDialog
)
from campbellviewer.utilities import safe_bool_conversion

matplotlib.use("Qt5Agg")
matplotlib.rcParams['hatch.color'] = 'grey'
Expand Down Expand Up @@ -329,8 +330,7 @@ class ApplicationWindow(QMainWindow):
main_layout (QVBoxLayout): Layout widget containing all widgets
button_layout (QHBoxLayout): Layout widget containing interactive buttons
layout_mplib (QVBoxLayout): Layout widget containing matplotlib plot
layout_list (QVBoxLayout): Layout widget containing data tree
layout_mpliblist (QHBoxLayout): Layout widget containing matplotlib and data tree
plot_splitter (QSplitter): for dynamic size adjustment of plot and tree visualization
dataset_tree_model (TreeModel): Model for the dataset tree
dataset_tree (DatasetTree): View for the dataset tree
fig (Figure): Matplotlib figure
Expand All @@ -340,7 +340,7 @@ class ApplicationWindow(QMainWindow):
axes2 (mpl.ax): damping plot axes of the matplotlib figure
right_mouse_press (bool): Flag for storing right mouse press on matplotlib figure
cursor (mplcursors.cursor): Cursor object
button_pharm (QPushButton): Button to toggle plotting P-harmonics
cbox_pharm (QCheckBox): Checkbox to toggle plotting P-harmonics
button_xaxis (QComboBox): Button to select xaxis parameter
xaxis_param (str): xaxis parameter
xaxis_selection_box (QVBoxLayout): Layout for xaxis button + text
Expand Down Expand Up @@ -402,10 +402,10 @@ def __init__(self):

##############################################################
# Set buttons
self.button_pharm = QCheckBox('Plot P-Harmonics', self)
self.button_pharm.setToolTip('Adds or removes the P-harmonics from operational data into the frequency plot.')
self.button_pharm.clicked.connect(self.plot_P_harmonics)
self.main_layout.addWidget(self.button_pharm, 0,0,1,1)
self.cbox_pharm = QCheckBox('Plot P-Harmonics', self)
self.cbox_pharm.setToolTip('Adds or removes the P-harmonics from operational data into the frequency plot.')
self.cbox_pharm.clicked.connect(self.plot_P_harmonics)
self.main_layout.addWidget(self.cbox_pharm, 0,0,1,1)

self.pick_markers = False
self.pick_markers_box = QCheckBox('Pick markers', self)
Expand Down Expand Up @@ -619,7 +619,7 @@ def main_plot(self, title: str='Campbell', xlabel: str='', ylabel: str='', y2lab
# plot p-harmonics if present
if database[atool][ads].ds.operating_points.values.ndim != 0 and self.__CV_settings['pharmonics']:
if self.__CV_settings['pharmonics']:
self.button_pharm.setChecked(True)
self.cbox_pharm.setChecked(True)
P_harmonics = [1, 3, 6, 9, 12]
for index in P_harmonics:
P_hamonics_data = database[atool][ads].ds.operating_points.loc[:, 'rot. speed [rpm]']/60.*index # rpm in Hz
Expand Down Expand Up @@ -1032,7 +1032,8 @@ def openFileNameDialogHAWCStab2(self, datasetname: str='default'):
tool_specific_info={'filename{}'.format(suffix): fileName,
'skip_header_CMB': self.__CV_settings['skip_header_CMB'],
'skip_header_AMP': self.__CV_settings['skip_header_AMP'],
'skip_header_OP': self.__CV_settings['skip_header_OP']})
'skip_header_OP': self.__CV_settings['skip_header_OP'],
'override_mode_names': self.__CV_settings['override_mode_names']})
# save location to settings
self.__qsettings.setValue("IO/HS2_project", QFileInfo(fileName).absolutePath())

Expand Down Expand Up @@ -1062,10 +1063,10 @@ def openFileNameDialogBladedLin(self, datasetname: str='default'):
def plot_P_harmonics(self):
""" Plot P-Harmonics in Campbell diagram """
if self.__CV_settings['pharmonics']:
self.button_pharm.setChecked(False)
self.cbox_pharm.setChecked(False)
self.__CV_settings['pharmonics'] = False
else:
self.button_pharm.setChecked(True)
self.cbox_pharm.setChecked(True)
self.__CV_settings['pharmonics'] = True
self.UpdateMainPlot()

Expand Down Expand Up @@ -1147,13 +1148,14 @@ def set_settings_to_default(self, save: bool = False) -> None:
"""
# defaults
self.__CV_settings = {'mode_minpara_cmb' : 1,
'mode_maxpara_cmb' : 6,
'pharmonics' : False,
'skip_header_CMB' : 1,
'skip_header_AMP' : 5,
'skip_header_OP' : 1,
'amp_part_threshold': 0.5}
self.__CV_settings = {'mode_minpara_cmb' : 1,
'mode_maxpara_cmb' : 6,
'pharmonics' : False,
'skip_header_CMB' : 1,
'skip_header_AMP' : 5,
'skip_header_OP' : 1,
'override_mode_names' : True,
'amp_part_threshold' : 0.5}

if save:
for settings_key in self.__CV_settings:
Expand All @@ -1164,15 +1166,15 @@ def update_settings(self) -> None:
"""retrieves the default values or the user specific settings from QSettings"""
# defaults
self.set_settings_to_default(save=False)

# try to get the user settings
for settings_key in self.__CV_settings:
if self.__qsettings.contains(settings_key):
user_setting = self.__qsettings.value(settings_key)
if isinstance(self.__CV_settings[settings_key], float):
self.__CV_settings[settings_key] = float(user_setting)
elif isinstance(self.__CV_settings[settings_key], bool):
self.__CV_settings[settings_key] = bool(user_setting)
self.__CV_settings[settings_key] = safe_bool_conversion(user_setting)
elif isinstance(self.__CV_settings[settings_key], int):
self.__CV_settings[settings_key] = int(user_setting)
else:
Expand Down
12 changes: 12 additions & 0 deletions campbellviewer/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@
import re
from PyQt5.QtCore import Qt

def safe_bool_conversion(input_value: str|bool) -> bool:
"""converts a string or a bool value to type bool safely
Args:
input_value: the value, which shall be converted
Returns:
result: the resulting value of type bool
"""
bool_conversion_dict = {"true": True, "false": False}
result = bool_conversion_dict[(str(input_value)).lower()]
return result

def assure_unique_name(unique_name, occupied_names):
"""
Expand Down

0 comments on commit dad7161

Please sign in to comment.