"""
Frame for handling Cross-Correlation Night selection and configuration.
This module provides a GUI panel for selecting and configuring cross-correlation
parameters for night observations, including target selection, instrument settings,
and night simulation options.
"""
from pathlib import Path
# Local application imports
from GUIBRUSHR.GUI.Input_Output_Panels.Input_Panels.Frame_Cross_Correlation.Notebook_Cross_Correlation import (
NotebookCrossCorrelation
)
from GUIBRUSHR.GUI.LAYOUT.MyPanel import MyPanel
from GUIBRUSHR.GUI.WIDGET.MyButton import MyButton
from GUIBRUSHR.GUI.WIDGET.MyCheckBox import MyCheckBox
from GUIBRUSHR.GUI.WIDGET.MyDropDown import MyDropdown
from GUIBRUSHR.GUI.WIDGET.MyTextField import MyTextField
from GUIBRUSHR.General_Constants.FunctionsAndConstants.Constant_Variables import ConstantVariables
from GUIBRUSHR.GUI.DataInterface.DataInterface import (
get_target_info,
get_target_list,
get_target_instruments,
get_target_nights,
get_list_cross_corr_models
)
from GUIBRUSHR.General_Constants.Classes.HelpButton import HelpButton
[docs]
class FrameCCNight(MyPanel):
"""
Panel for managing cross-correlation night selection and configuration.
This class provides a GUI interface for selecting targets, instruments,
and configuring cross-correlation parameters for night observations.
"""
[docs]
def __init__(self, parent, color, row, column, path_default, frame_input, width_GUI, height_GUI, window, **kwargs):
"""
Initialize the FrameCCNight panel.
Args:
parent: Parent widget
color: Background color
row: Row position
column: Column position
path_default: Default path for resources
frame_input: Input frame reference
width_GUI: GUI width
height_GUI: GUI height
window: Main window reference
**kwargs: Additional keyword arguments
"""
# Initialize instance variables
self.path_folder_targets = frame_input.frame_path.path_folder_targets.get_text()
self.global_exc = 0
self.frame_input = frame_input
self.path_default = path_default
self.window = window
self.color = color
self.dropdown_target = None
# Initialize parent class
super().__init__(parent, color, row, column, **kwargs)
# Create panel rows
self._create_panel_rows()
# Create and configure widgets
self._create_widgets()
# Set up event bindings
self._setup_event_bindings()
# Create cross-correlation notebook
self._create_cc_notebook(width_GUI, height_GUI)
self.global_exc = 1
def _create_panel_rows(self):
"""Create the three panel rows for widget organization."""
self.row1 = MyPanel(self, self.color, 0, 1)
self.row2 = MyPanel(self, self.color, 1, 1)
self.row3 = MyPanel(self, self.color, 2, 1)
def _create_widgets(self):
"""Create and configure all widgets in the panel."""
self.target_list = get_target_list(self.path_folder_targets)
self.target_information = get_target_info(self.path_folder_targets, self.target_list[0])
self.list_hr_instrument = get_target_instruments(
self.path_folder_targets, self.target_list[0], "HR", "Transmission", Path(__file__).name
)
self.nights = get_target_nights(
self.path_folder_targets, self.target_list[0], "Transmission",
self.list_hr_instrument[0], 0
)
self.dict_list_cc = get_list_cross_corr_models(
self.path_folder_targets, self.target_list[0], "Transmission"
)
# Help text dictionary
help_text = {
"Target": "Select the exoplanet target for cross-correlation analysis. Only targets previously added to the database (via the Target tab) appear in this list. The target must have associated observational data organized in the correct folder structure.",
"Model CC": "Select the cross-correlation template model to use for signal detection. Models are pre-computed atmospheric transmission/emission spectra stored in the target's Models directory. These typically represent different atmospheric compositions (e.g., different molecular abundances or T-P profiles).",
"Rad. Transf. Mode": "Radiative transfer mode: 'Transmission' for primary transit observations (planet in front of star, atmospheric absorption features) or 'Emission' for secondary eclipse observations (planet behind star, thermal emission features).",
"HR Instrument": "Select the high-resolution spectrograph used for observations. Only instruments with data in the target's folder structure appear. Different instruments may have different wavelength coverage, resolution, and observing nights.",
"Order Selection": "Specify which spectral orders to process.",
"Tell rm method": "Telluric removal method previously applied to the data (from the Telluric Removal tab)..",
"Nights": "Available observation nights for the selected target, instrument, and mode. Nights are detected automatically from the folder structure. Format: YYYY-MM-DD. Multiple nights can be selected by listing them comma-separated.",
"Night sim/syn": "When checked, loads simulated or synthetic observation nights instead of real observational data. Simulated nights are useful for testing, validation, and injection-recovery experiments.",
"Selection for CC": "Multi-instrument/multi-night selection string for cross-correlation. Format: 'Instrument1:Night1,Night2;Instrument2:Night3,Night4'. Use 'UPDATE SELECTION' button to add each instrument's nights to this field. This allows combining data from different instruments or multiple nights in a single cross-correlation analysis."
}
# Create help button
self.help_button = HelpButton(
self.row1, 0, 0,
"Cross-Correlation Night Selection Help",
help_text,
columnspan=1
)
# Row 1 widgets
self.dropdown_target = MyDropdown(
self.row1, 0, 1, self.target_list, "Target:",
color=self.color, columnspan=2
)
self.dropdown_cross_corr = MyDropdown(
self.row1, 0, 3, list(sorted(self.dict_list_cc.keys())),
"Model CC", initial_value=0,
color=self.color, columnspan=2
)
self.dropdown_rad_mode = MyDropdown(
self.row1, 0, 5, ConstantVariables.LIST_RAD_MODE,
"Rad. Transf. Mode:", initial_value=0,
color=self.color, columnspan=2
)
self.dropdown_hr_instrument = MyDropdown(
self.row1, 0, 7, self.list_hr_instrument, "HR Instrument:",
color=self.color, columnspan=2
)
self.textfield_order_selection = MyTextField(
self.row1, 0, 9, "full", "Order Selection:",
color=self.color, columnspan=3, width=20
)
self.dropdown_tell_rm_method = MyDropdown(
self.row1, 0, 12, ConstantVariables.LIST_TELL_TABLE,
"Tell rm method:", color=self.color, columnspan=2
)
# Row 2 widgets
self.textfield_nights = MyTextField(
self.row2, 0, 1, self.nights, "Nights:",
color=self.color, columnspan=3, width=40, height=3
)
self.check_nights_sim = MyCheckBox(self.row2, 0, 4, "Night sim/syn")
self.button_add_selection = MyButton(
self.row2, 0, 5, 'UPDATE SELECTION', "#00AA00",
command=self.update_selection
)
self.textfield_selection = MyTextField(
self.row2, 0, 7, "", "Selection for CC:",
color=self.color, columnspan=3, width=80, height=3, rowspan=9
)
def _setup_event_bindings(self):
"""Set up event bindings for widgets."""
self.check_nights_sim.var.trace("w", lambda *args: self.update_night_sim())
self.dropdown_target.chosen_var.trace("w", lambda *args: self.update_target())
self.dropdown_hr_instrument.chosen_var.trace("w", lambda *args: self.update_hr())
self.dropdown_rad_mode.chosen_var.trace("w", lambda *args: self.update_from_rad_mode())
def _create_cc_notebook(self, width_GUI, height_GUI):
"""Create the cross-correlation notebook widget."""
self.notebook_CC = NotebookCrossCorrelation(
self.row3, self.color, 0, 1, self.path_default,
self.frame_input, self.window,
ConstantVariables.list_tab_cross_correlation_2,
width_GUI, height_GUI, widget_nights=self
)
[docs]
def update_selection(self):
"""Update the selection text field with current instrument and nights."""
past_txt = self.textfield_selection.get_text()
if past_txt:
past_txt += ";"
nights = self.textfield_nights.get_text()
new_instrument = f"{self.dropdown_hr_instrument.get_value()}:{nights}"
self.textfield_selection.insert_text(past_txt + new_instrument)
[docs]
def update_target(self):
"""Update widgets when target selection changes."""
if self.global_exc == 0:
return
target_id = self.dropdown_target.get_value()
self._update_target_data(target_id)
self._refresh_target_widgets(target_id)
def _update_target_data(self, target_id):
"""Update data based on selected target."""
self.list_hr_instrument = get_target_instruments(
self.path_folder_targets, target_id, "HR",
self.dropdown_rad_mode.get_value(), Path(__file__).name
)
self.nights = get_target_nights(
self.path_folder_targets, target_id,
self.dropdown_rad_mode.get_value(),
self.list_hr_instrument[0],
self.check_nights_sim.get_value()
)
self.target_information = get_target_info(
self.path_folder_targets, target_id,
self.dropdown_rad_mode.get_value()
)
self.textfield_nights.insert_text(self.nights)
def _refresh_target_widgets(self, target_id):
"""Refresh widgets with new target data."""
self.dropdown_hr_instrument.clean_widget()
self.dropdown_cross_corr.clean_widget()
self.dict_list_cc = get_list_cross_corr_models(
self.path_folder_targets, target_id,
self.dropdown_rad_mode.get_value()
)
self.dropdown_cross_corr = MyDropdown(
self.row1, 0, 3, list(sorted(self.dict_list_cc.keys())),
"Model CC", initial_value=0,
color=self.color, columnspan=2
)
self.dropdown_hr_instrument = MyDropdown(
self.row1, 0, 7, self.list_hr_instrument, "HR Instrument:",
color=self.color, columnspan=2
)
self.dropdown_hr_instrument.chosen_var.trace("w", lambda *args: self.update_hr())
self.update_hr()
[docs]
def update_night_sim(self):
"""Update nights when simulation checkbox changes."""
if self.global_exc == 0:
return
target_id = self.dropdown_target.get_value()
nights = get_target_nights(
self.path_folder_targets, target_id,
self.dropdown_rad_mode.get_value(),
self.dropdown_hr_instrument.get_value(),
self.check_nights_sim.get_value()
)
self.textfield_nights.insert_text(nights)
[docs]
def update_hr(self):
"""Update nights when HR instrument changes."""
instrument = self.dropdown_hr_instrument.get_value()
target_id = self.dropdown_target.get_value()
nights = get_target_nights(
self.path_folder_targets, target_id,
self.dropdown_rad_mode.get_value(),
instrument,
self.check_nights_sim.get_value()
)
self.textfield_nights.insert_text(nights)
[docs]
def modify_target_list(self, target_list):
"""Update the target dropdown with a new list of targets."""
self.dropdown_target.clean_widget()
self.dropdown_target = MyDropdown(
self.row1, 0, 1, target_list, "Target:",
color=self.color, columnspan=2
)
self.dropdown_target.chosen_var.trace("w", lambda *args: self.update_target())
[docs]
def update_from_rad_mode(self):
"""Update widgets when radiation mode changes."""
target_id = self.dropdown_target.get_value()
self._update_rad_mode_data(target_id)
self._refresh_rad_mode_widgets(target_id)
def _update_rad_mode_data(self, target_id):
"""Update data based on radiation mode."""
self.list_hr_instrument = get_target_instruments(
self.path_folder_targets, target_id, "HR",
self.dropdown_rad_mode.get_value(), Path(__file__).name
)
def _refresh_rad_mode_widgets(self, target_id):
"""Refresh widgets with new radiation mode data."""
self.dropdown_hr_instrument.clean_widget()
self.dropdown_cross_corr.clean_widget()
self.dict_list_cc = get_list_cross_corr_models(
self.path_folder_targets, target_id,
self.dropdown_rad_mode.get_value()
)
self.dropdown_cross_corr = MyDropdown(
self.row1, 0, 3, list(sorted(self.dict_list_cc.keys())),
"Model CC", initial_value=0,
color=self.color, columnspan=2
)
self.dropdown_hr_instrument = MyDropdown(
self.row1, 0, 7, self.list_hr_instrument, "HR Instrument:",
color=self.color, columnspan=2
)
self.dropdown_hr_instrument.chosen_var.trace("w", lambda *args: self.update_hr())
self.update_hr()