diff --git a/.codex/environments/environment.toml b/.codex/environments/environment.toml new file mode 100644 index 0000000..92de10b --- /dev/null +++ b/.codex/environments/environment.toml @@ -0,0 +1,11 @@ +# THIS IS AUTOGENERATED. DO NOT EDIT MANUALLY +version = 1 +name = "astra_gui" + +[setup] +script = "" + +[[actions]] +name = "Run" +icon = "run" +command = "hatch run all" diff --git a/src/astra_gui/app.py b/src/astra_gui/app.py index 815a67f..0d252f7 100644 --- a/src/astra_gui/app.py +++ b/src/astra_gui/app.py @@ -375,8 +375,8 @@ def menu(self) -> None: def get_process_from_notebooks(self, action: str, *args, **kwargs) -> None: """Get action from all the notebooks.""" - for _notebook in self.notebooks: - getattr(_notebook, action)(*args, **kwargs) + for notebook in self.notebooks: + getattr(notebook, action)(*args, **kwargs) @log_operation('erasing in all notebooks') def erase(self) -> None: diff --git a/src/astra_gui/close_coupling/bsplines.py b/src/astra_gui/close_coupling/bsplines.py index 5aaa580..c038dc6 100644 --- a/src/astra_gui/close_coupling/bsplines.py +++ b/src/astra_gui/close_coupling/bsplines.py @@ -14,6 +14,7 @@ missing_required_calculation_popup, missing_required_file_popup, required_field_popup, + save_success_popup, warning_popup, ) from astra_gui.utils.required_fields_module import RequiredFields @@ -170,7 +171,7 @@ def erase(self) -> None: self.num_bspline_entry.delete(0, tk.END) self.erase_plot_parameters() - def save(self) -> None: + def save(self, show_popup: bool = True) -> None: """Validate the current configuration and write all required input files.""" # Saving EXTERNAL_BASIS_BSPLINES.INP @@ -344,6 +345,8 @@ class PlotRequiredFields(RequiredFields): if self.path_exists(self.PRISM_FOLDER): self.remove_path(self.PRISM_FOLDER) + if show_popup: + save_success_popup(f'{self.label} inputs saved successfully.') def load(self) -> None: """Populate the form from existing Astra or PRISM files.""" diff --git a/src/astra_gui/close_coupling/clscplng.py b/src/astra_gui/close_coupling/clscplng.py index c1d10a0..5374cdb 100644 --- a/src/astra_gui/close_coupling/clscplng.py +++ b/src/astra_gui/close_coupling/clscplng.py @@ -12,7 +12,12 @@ import numpy as np from astra_gui.utils.font_module import title_font -from astra_gui.utils.popup_module import invalid_input_popup, missing_required_calculation_popup, required_field_popup +from astra_gui.utils.popup_module import ( + invalid_input_popup, + missing_required_calculation_popup, + required_field_popup, + save_success_popup, +) from astra_gui.utils.required_fields_module import RequiredFields from astra_gui.utils.scrollable_module import ScrollableFrame @@ -224,9 +229,10 @@ class ClscplngRequiredFields(RequiredFields): bsplines_page = cast('Bsplines', self.notebook.pages[4]) if self.path_exists(bsplines_page.BSPLINES_INPUT_FILE): - bsplines_page.save() + bsplines_page.save(show_popup=False) self.get_cc_data() + save_success_popup(f'{self.label} inputs saved successfully.') def load(self) -> None: """Populate the form based on an existing CLSCPLNG.INP file.""" diff --git a/src/astra_gui/close_coupling/dalton.py b/src/astra_gui/close_coupling/dalton.py index 78d3dc1..16612fb 100644 --- a/src/astra_gui/close_coupling/dalton.py +++ b/src/astra_gui/close_coupling/dalton.py @@ -9,6 +9,7 @@ from tkinter import ttk from typing import TYPE_CHECKING, cast +from astra_gui.utils.popup_module import save_success_popup from astra_gui.utils.required_fields_module import RequiredFields from .cc_notebook_page_module import CcNotebookPage @@ -356,6 +357,7 @@ class DaltonRequiredFields(RequiredFields): self.notebook.dalton_data[occ_option] = '' self.save_file(self.DALTON_FILE, self.notebook.dalton_data, '!', blank_lines=False) + save_success_popup(f'{self.label} inputs saved successfully.') def erase(self) -> None: """Reset Dalton form fields to their defaults.""" diff --git a/src/astra_gui/close_coupling/lucia.py b/src/astra_gui/close_coupling/lucia.py index 26ec544..2542abf 100644 --- a/src/astra_gui/close_coupling/lucia.py +++ b/src/astra_gui/close_coupling/lucia.py @@ -19,6 +19,7 @@ missing_output_popup, missing_required_calculation_popup, required_field_popup, + save_success_popup, warning_popup, ) from astra_gui.utils.required_fields_module import RequiredFields @@ -292,7 +293,7 @@ def get_new_dimension_requirement() -> int: error_string += '\nUpdating LUCIA.INP and running Hamiltonian calculation again.' - self.save() + self.save(show_popup=False) if self.sa_var.get(): self.run_astra_setup('-run eht --sa', 'State average') @@ -758,7 +759,7 @@ def get_title(self) -> str: return '\n'.join(title_lines) - def save(self) -> None: + def save(self, show_popup: bool = True) -> None: """Validate the Lucia form and update the associated input files.""" @dataclass @@ -812,6 +813,8 @@ class LuciaRequiredFields(RequiredFields): commands['lz2'] = 'LZ2' self.save_file(self.LUCIA_FILE, commands, '*', blank_lines=False) + if show_popup: + save_success_popup(f'{self.label} inputs saved successfully.') def save_sa(self) -> None: """Persist the state-averaged Lucia configuration to disk.""" diff --git a/src/astra_gui/close_coupling/molecule.py b/src/astra_gui/close_coupling/molecule.py index 4c4badb..517ae17 100644 --- a/src/astra_gui/close_coupling/molecule.py +++ b/src/astra_gui/close_coupling/molecule.py @@ -14,7 +14,7 @@ from astra_gui.utils.font_module import title_font from astra_gui.utils.notebook_module import NotebookPage -from astra_gui.utils.popup_module import required_field_popup +from astra_gui.utils.popup_module import required_field_popup, save_success_popup from astra_gui.utils.symmetry_module import Symmetry from astra_gui.utils.table_module import Table @@ -334,6 +334,7 @@ def save(self) -> None: ) self.notebook.molecule_data['number_atoms'] = np.shape(self.get_all_atoms()[1])[0] self.notebook.molecule_data['linear_molecule'] = self.is_molecule_linear() + save_success_popup(f'{self.label} inputs saved successfully.') def plot_molecule(self) -> None: """Render the molecule via Molden if the environment supports it.""" diff --git a/src/astra_gui/time_dependent/pulse.py b/src/astra_gui/time_dependent/pulse.py index 8076057..db51bdb 100644 --- a/src/astra_gui/time_dependent/pulse.py +++ b/src/astra_gui/time_dependent/pulse.py @@ -13,7 +13,7 @@ from astra_gui.utils.font_module import bold_font from astra_gui.utils.notebook_module import NotebookPage -from astra_gui.utils.popup_module import invalid_input_popup, warning_popup +from astra_gui.utils.popup_module import invalid_input_popup, save_success_popup, warning_popup from astra_gui.utils.required_fields_module import RequiredFields from astra_gui.utils.table_module import Table @@ -1153,6 +1153,7 @@ def save(self) -> None: for pulse_name, pulse_tabulation_data in pulse_tabulation.items(): self.save_file_from_blank(Path(f'{pulse_name}.DAT'), pulse_tabulation_data) + save_success_popup(f'{self.label} inputs saved successfully.') def print_irrep(self, _new_sym: bool = False) -> None: """Relay symmetry changes to both pulse configuration frames.""" diff --git a/src/astra_gui/time_independent/structural.py b/src/astra_gui/time_independent/structural.py index 2ba9458..35733f2 100644 --- a/src/astra_gui/time_independent/structural.py +++ b/src/astra_gui/time_independent/structural.py @@ -566,11 +566,15 @@ def get_commands(self) -> str: susc_dp_length_vals = ','.join([self.dp_labels[ind] for ind in range(3) if susc_dp_vals[ind]]) lines.extend([ - f'astraDipoleTransition -gif ASTRA.INP -op {susc_dp_length_vals} ' - f'-ketsym {susc_entries[0]} -trans bb {cap_text}', - f'astraSusceptibility -gif ASTRA.INP -op {susc_dp_length_vals} ' - f'-ketsym {susc_entries[0]} -trans bb -emin {susc_entries[1]} ' - f'-emax {susc_entries[2]} -ne {susc_entries[3]} {cap_text}', + ( + f'astraDipoleTransition -gif ASTRA.INP -op {susc_dp_length_vals} ' + f'-ketsym {susc_entries[0]} -trans bb {cap_text}' + ), + ( + f'astraSusceptibility -gif ASTRA.INP -op {susc_dp_length_vals} ' + f'-ketsym {susc_entries[0]} -trans bb -emin {susc_entries[1]} ' + f'-emax {susc_entries[2]} -ne {susc_entries[3]} {cap_text}' + ), ]) if any(susc_dp_vals[3:]): @@ -579,11 +583,15 @@ def get_commands(self) -> str: susc_dp_velocity_vals = ','.join([self.dp_labels[ind] for ind in range(3, 6) if susc_dp_vals[ind]]) lines.extend([ - f'astraDipoleTransition -gif ASTRA.INP -op {susc_dp_velocity_vals} ' - f'-ketsym {susc_entries[0]} -trans bb {cap_text}', - f'astraSusceptibility -gif ASTRA.INP -op {susc_dp_velocity_vals} ' - f'-ketsym {susc_entries[0]} -trans bb -emin {susc_entries[1]} ' - f'-emax {susc_entries[2]} -ne {susc_entries[3]} {cap_text}', + ( + f'astraDipoleTransition -gif ASTRA.INP -op {susc_dp_velocity_vals} ' + f'-ketsym {susc_entries[0]} -trans bb {cap_text}' + ), + ( + f'astraSusceptibility -gif ASTRA.INP -op {susc_dp_velocity_vals} ' + f'-ketsym {susc_entries[0]} -trans bb -emin {susc_entries[1]} ' + f'-emax {susc_entries[2]} -ne {susc_entries[3]} {cap_text}' + ), ]) return self.add_idle_thread_and_join_lines(lines) diff --git a/src/astra_gui/time_independent/ti_notebook_page_module.py b/src/astra_gui/time_independent/ti_notebook_page_module.py index f80502c..341f085 100644 --- a/src/astra_gui/time_independent/ti_notebook_page_module.py +++ b/src/astra_gui/time_independent/ti_notebook_page_module.py @@ -12,7 +12,7 @@ from astra_gui.utils.font_module import bold_font from astra_gui.utils.notebook_module import NotebookPage -from astra_gui.utils.popup_module import missing_symmetry_popup, required_field_popup +from astra_gui.utils.popup_module import missing_symmetry_popup, required_field_popup, save_success_popup from astra_gui.utils.scrollable_module import ScrollableFrame, ScrollableTreeview if TYPE_CHECKING: @@ -242,6 +242,7 @@ def save(self) -> None: return self.save_script(self.SCRIPT_FILE, commands, f'{self.label} calculation', convert_cs_irreps=True) + save_success_popup(f'{self.label} inputs saved successfully.') def run(self) -> None: """Execute the notebook script using the shared runner.""" diff --git a/src/astra_gui/utils/notebook_module.py b/src/astra_gui/utils/notebook_module.py index 62f7b60..e015f11 100644 --- a/src/astra_gui/utils/notebook_module.py +++ b/src/astra_gui/utils/notebook_module.py @@ -27,6 +27,7 @@ invalid_input_popup, missing_script_file_popup, required_field_popup, + started_calculation_popup, ) from .symmetry_module import Symmetry @@ -316,8 +317,7 @@ def get_cpu_stats_data() -> list[str]: lines = stdout.split('\n') else: try: - with Path(proc_stat_file).open('r') as f: - lines = f.read().split('\n') + lines = Path(proc_stat_file).read_text().split('\n') except FileNotFoundError: if system() == 'Darwin': logger.warning( @@ -577,6 +577,10 @@ def check_programs_helper(script_name: str) -> None: return if not run[0]: return + self.controller.after( + 0, + lambda: started_calculation_popup(f'{script_name} started running.'), + ) if self.ssh_client: remote_command = ( diff --git a/src/astra_gui/utils/popup_module.py b/src/astra_gui/utils/popup_module.py index d228c1d..0c3b960 100644 --- a/src/astra_gui/utils/popup_module.py +++ b/src/astra_gui/utils/popup_module.py @@ -88,6 +88,16 @@ def completed_calculation_popup(message: str) -> None: messagebox.showinfo('Completed Calculation!', message) +def started_calculation_popup(message: str) -> None: + """Display a start message for long-running calculations.""" + messagebox.showinfo('Calculation Started', message) + + +def save_success_popup(message: str) -> None: + """Display a confirmation message after saving files.""" + messagebox.showinfo('Files Saved', message) + + def missing_script_file_popup(name: str) -> None: """Inform that a required script file has not been saved yet.""" messagebox.showerror('Missing script file!', f'Please save the script for {name} before running!')