Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added final test (final version of user script before I leave) #158

Merged
merged 20 commits into from
Nov 6, 2024
Merged
6 changes: 0 additions & 6 deletions src/nectarchain/user_scripts/dmousadi/test_scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@ Automated tests from the Test Readiness Review document for the CTA NectarCAM ba

## Installation

Instructions on how to install and set up the project:
```
git clone https://drf-gitlab.cea.fr/dmousadi/camera-test-scripts
cd camera-test-scripts
pip install -r requirements.txt
```
If you want to automatically download your data, one of the requirements is also DIRAC, for which you need to have a grid certificate. It is not necessary for this repo, if you have your NectarCAM runs (fits files) locally stored. You can find more information about DIRAC [here](https://gitlab.cta-observatory.org/cta-computing/dpps/workload/CTADIRAC). If you are installing these packages for the first time and getting 'error building wheel', you might need to (re)install some of these: swig, ca-certificates, openssl, boost, protobuff, cmake.

Once you have set up your environment, if you're not already a nectarchain user you need to set the NECTARCAMDATA environment variable to the directory where you have the NectarCAM runs:
Expand Down
144 changes: 100 additions & 44 deletions src/nectarchain/user_scripts/dmousadi/test_scripts/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
The class uses the PyQt5 library for the GUI implementation and the Matplotlib library for plotting the test results.
"""


import argparse
import os
import pickle
Expand All @@ -38,6 +37,7 @@
QTextEdit,
QVBoxLayout,
QWidget,
QWidgetItem,
)

# Ensure the tests directory is in sys.path
Expand All @@ -52,9 +52,19 @@
import pedestal_test
import pix_couple_tim_uncertainty_test
import pix_tim_uncertainty_test
import trigger_timing_test


class TestRunner(QWidget):
test_modules = {
"Linearity Test": linearity_test,
"Deadtime Test": deadtime_test,
"Pedestal Test": pedestal_test,
"Pixel Time Uncertainty Test": pix_tim_uncertainty_test,
"Time Uncertainty Between Couples of Pixels": pix_couple_tim_uncertainty_test,
"Trigger Timing Test": trigger_timing_test,
}

def __init__(self):
super().__init__()
self.params = {}
Expand Down Expand Up @@ -89,25 +99,13 @@ def init_ui(self):
color: #ffffff; /* Light text */
border: 1px solid #888888; /* Light border */
padding: 5px; /* Add padding */
fixed-height: 30px; /* Set a fixed height */
min-width: 200px; /* Fixed width */
}
QPushButton {
background-color: #4caf50; /* Green button */
color: white; /* White text */
border: none; /* No border */
padding: 10px; /* Add padding */
border-radius: 5px; /* Rounded corners */
}
QPushButton:hover {
background-color: #45a049; /* Darker green on hover */
}
QTextEdit {
background-color: #1e1e1e; /* Dark output box */
color: #ffffff; /* Light text */
border: 1px solid #888888; /* Light border */
padding: 5px; /* Add padding */
fixed-height: 150px; /* Set a fixed height */
min-width: 800px; /* Set a minimum width to match the canvas */
}
QTextEdit:focus {
Expand Down Expand Up @@ -144,13 +142,15 @@ def init_ui(self):
controls_layout.addWidget(self.label)

self.test_selector = QComboBox(self)
self.test_selector.addItem("Select Test")
self.test_selector.addItems(
[
"Linearity Test",
"Deadtime Test",
"Pedestal Test",
"Pixel Time Uncertainty Test",
"Time Uncertainty Between Couples of Pixels",
"Trigger Timing Test",
]
)
self.test_selector.setFixedWidth(400) # Fixed width for the dropdown
Expand All @@ -165,6 +165,8 @@ def init_ui(self):

# Button to run the test
self.run_button = QPushButton("Run Test", self)
# Disable the run button initially
self.run_button.setEnabled(False)
self.run_button.clicked.connect(self.run_test)
controls_layout.addWidget(self.run_button)

Expand Down Expand Up @@ -240,11 +242,14 @@ def get_parameters_from_module(self, module):
# Fetch parameters from the module
if hasattr(module, "get_args"):
parser = module.get_args()
return {
arg.dest: arg.default
for arg in parser._actions
if isinstance(arg, argparse._StoreAction)
}
params = {}
for arg in parser._actions:
if isinstance(arg, argparse._StoreAction):
params[arg.dest] = {
"default": arg.default,
"help": arg.help, # Store the help text
}
return params
else:
raise RuntimeError("No get_args function found in module.")

Expand All @@ -258,32 +263,83 @@ def debug_layout(self):
def update_parameters(self):
# Clear existing parameter fields
for i in reversed(range(self.param_layout.count())):
widget = self.param_layout.itemAt(i).widget()
if widget:
widget.deleteLater()
item = self.param_layout.itemAt(i)

if isinstance(
item, QHBoxLayout
): # Check if the item is a QHBoxLayout (contains label and help button)
for j in reversed(range(item.count())):
widget = item.itemAt(j).widget()
if widget:
widget.deleteLater()
elif isinstance(item, QWidgetItem): # For direct widgets like QLineEdit
widget = item.widget()
if widget:
widget.deleteLater()

# Remove the item itself from the layout
self.param_layout.removeItem(item)

# Get the selected test and corresponding module
selected_test = self.test_selector.currentText()
test_modules = {
"Linearity Test": linearity_test,
"Deadtime Test": deadtime_test,
"Pedestal Test": pedestal_test,
"Pixel Time Uncertainty Test": pix_tim_uncertainty_test,
"Time Uncertainty Between Couples of Pixels": pix_couple_tim_uncertainty_test,
}

module = test_modules.get(selected_test)

# If the placeholder is selected, do nothing
if selected_test == "Select Test":
self.run_button.setEnabled(False)
return

module = self.test_modules.get(selected_test)
if module:
try:
self.params = self.get_parameters_from_module(module)
for param, default in self.params.items():
if param == "temp_output":

for param, param_info in self.params.items():
if param == "temp_output": # Skip temp_output
continue

# Create a horizontal layout for the label and help button
param_layout = QHBoxLayout()

# Create label
label = QLabel(f"{param}:", self)
self.param_layout.addWidget(label)
param_layout.addWidget(label)

# Create tiny grey circle help button with a white question mark
help_button = QPushButton("?", self)
help_button.setFixedSize(16, 16) # Smaller button size
help_button.setStyleSheet(
"""
QPushButton {
background-color: grey;
color: white;
border-radius: 8px; /* Circular button */
font-weight: bold;
font-size: 10px; /* Smaller font size */
}
QPushButton:hover {
background-color: darkgrey; /* Change color on hover */
}
"""
)
help_button.setToolTip(param_info["help"])

# # Use lambda to capture the current param's help text
# help_button.clicked.connect(lambda _, p=param_info["help"]: self.show_help(p))

# Add the help button to the layout (next to the label)
param_layout.addWidget(help_button)
param_layout.addStretch() # Add stretch to push the help button to the right

# Add the horizontal layout (label + help button) to the main layout
self.param_layout.addLayout(param_layout)

# Create the input field for the parameter
entry = QLineEdit(self)
entry.setText(
str(default).replace("[", "").replace("]", "").replace(",", "")
str(param_info["default"])
.replace("[", "")
.replace("]", "")
.replace(",", "")
)
entry.setObjectName(param)
entry.setFixedWidth(400) # Set fixed width for QLineEdit
Expand All @@ -294,24 +350,24 @@ def update_parameters(self):
QTimer.singleShot(
0, self.param_widgets.update
) # Ensures the layout is updated

self.run_button.setEnabled(True)
except Exception as e:
QMessageBox.critical(self, "Error", f"Failed to fetch parameters: {e}")

else:
QMessageBox.critical(self, "Error", "No test selected or test not found")

def show_help(self, help_text):
QMessageBox.information(self, "Parameter Help", help_text)

def run_test(self):
# Clean up old plot files to avoid loading leftover files
self.cleanup_tempdir()

selected_test = self.test_selector.currentText()
test_modules = {
"Linearity Test": linearity_test,
"Deadtime Test": deadtime_test,
"Pedestal Test": pedestal_test,
"Pixel Time Uncertainty Test": pix_tim_uncertainty_test,
"Time Uncertainty Between Couples of Pixels": pix_couple_tim_uncertainty_test,
}
module = test_modules.get(selected_test)

module = self.test_modules.get(selected_test)

if module:
params = []
Expand All @@ -320,9 +376,9 @@ def run_test(self):

# Generate temporary output path
self.temp_output = tempfile.gettempdir()
print(f"Temporary output dir: {self.temp_output}") # Debug print
# print(f"Temporary output dir: {self.temp_output}") # Debug print

for param, default in self.params.items():
for param, _ in self.params.items():
widget_list = self.param_widgets.findChildren(QLineEdit, param)
if widget_list:
widget = widget_list[0]
Expand Down
Loading