Пример #1
0
    def create_wizard(self, parent=None):
        """Create the user function wizard GUI object, with embedded wizard page.

        @keyword parent:    The parent wx window.
        @type parent:       wx.Window instance
        @return:            True if the wizard was created, False if a problem was encountered.
        @rtype:             bool
        """

        # The parent object defaults to the main relax window.
        if parent == None:
            app = wx.GetApp()
            parent = app.gui

        # Create the wizard dialog.
        self.wizard = Wiz_window(parent=parent, size_x=self._size[0], size_y=self._size[1], title="The %s user function"%self._name)

        # Create the page.
        self.page = self.create_page(self.wizard, sync=self._sync)

        # For an update of the argument data.
        if not self.page.update_args():
            return False

        # Add the page to the wizard.
        self.wizard.add_page(self.page, apply_button=self._apply_button)

        # Success.
        return True
Пример #2
0
    def setup_dipole_pair(self, event=None):
        """Create the wizard for the dipole-dipole interaction.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Change the cursor to busy.
        wx.BeginBusyCursor()

        # Destroy the dipole-dipole interaction wizard, if it exists.
        if hasattr(self, 'dipole_wizard'):
            self.dipole_wizard.Destroy()

        # Create the wizard.
        self.dipole_wizard = Wiz_window(
            parent=self.gui,
            size_x=1000,
            size_y=750,
            title="Dipole-dipole interaction setup")

        # Structural data.
        if not hasattr(cdp, 'structure'):
            # Create the PDB reading page.
            page = uf_store['structure.read_pdb'].create_page(
                self.dipole_wizard, sync=True)
            self.dipole_wizard.add_page(page, skip_button=True)

            # Create the position reading page.
            page = uf_store['structure.get_pos'].create_page(
                self.dipole_wizard, sync=True)
            self.dipole_wizard.add_page(page, skip_button=True)

        # Create the interatom.define page.
        page = uf_store['interatom.define'].create_page(self.dipole_wizard,
                                                        sync=True)
        page.SetValue('spin_id1', '@N')
        page.SetValue('spin_id2', '@H')
        self.dipole_wizard.add_page(page)

        # Create the interatom.set_dist page.
        page = uf_store['interatom.set_dist'].create_page(self.dipole_wizard,
                                                          sync=True)
        page.SetValue('spin_id1', '@N*')
        page.SetValue('spin_id2', '@H*')
        page.SetValue('ave_dist', NH_BOND_LENGTH)
        self.dipole_wizard.add_page(page)

        # Create the interatom.unit_vectors page.
        page = uf_store['interatom.unit_vectors'].create_page(
            self.dipole_wizard, sync=True)
        self.dipole_wizard.add_page(page)

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()

        # Execute the wizard.
        self.dipole_wizard.run()
Пример #3
0
    def create_wizard(self, parent=None):
        """Create the user function wizard GUI object, with embedded wizard page.

        @keyword parent:    The parent wx window.
        @type parent:       wx.Window instance
        @return:            True if the wizard was created, False if a problem was encountered.
        @rtype:             bool
        """

        # The parent object defaults to the main relax window.
        if parent == None:
            app = wx.GetApp()
            parent = app.gui

        # Create the wizard dialog.
        self.wizard = Wiz_window(parent=parent, size_x=self._size[0], size_y=self._size[1], title="The %s user function"%self._name)

        # Create the page.
        self.page = self.create_page(self.wizard, sync=self._sync)

        # For an update of the argument data.
        if not self.page.update_args():
            return False

        # Add the page to the wizard.
        self.wizard.add_page(self.page, apply_button=self._apply_button)

        # Success.
        return True
Пример #4
0
    def load_spins_wizard(self, event=None):
        """The spin loading wizard.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # No current data pipe.
        if not cdp_name():
            gui_raise(RelaxNoPipeError())
            return

        # Change the cursor to busy.
        wx.BeginBusyCursor()

        # Initialise a wizard.
        self.wizard = Wiz_window(parent=self, size_x=1000, size_y=800, title="Load spins")
        self.page_indices = {}

        # The loading method page.
        self.page_method = Load_method_page(self.wizard)
        self.page_indices['method'] = self.wizard.add_page(self.page_method, apply_button=True, skip_button=False)
        self.wizard.set_seq_next_fn(self.page_indices['method'], self.wizard_page_after_load_method)

        # The sequence.read page.
        page = uf_store['sequence.read'].create_page(self.wizard)
        self.page_indices['sequence.read'] = self.wizard.add_page(page, skip_button=True)
        self.wizard.set_seq_next_fn(self.page_indices['sequence.read'], self.wizard_page_after_sequence_read)

        # The structure.read_pdb page.
        page = uf_store['structure.read_pdb'].create_page(self.wizard)
        self.page_indices['structure.read_pdb'] = self.wizard.add_page(page, skip_button=True)
        self.wizard.set_seq_next_fn(self.page_indices['structure.read_pdb'], self.wizard_page_after_structure_read)

        # The structure.read_xyz page.
        page = uf_store['structure.read_xyz'].create_page(self.wizard)
        self.page_indices['structure.read_xyz'] = self.wizard.add_page(page, skip_button=True)
        self.wizard.set_seq_next_fn(self.page_indices['structure.read_xyz'], self.wizard_page_after_structure_read)

        # The spectrum.read_spins page.
        page = uf_store['spectrum.read_spins'].create_page(self.wizard)
        self.page_indices['spectrum.read_spins'] = self.wizard.add_page(page, skip_button=True)
        self.wizard.set_seq_next_fn(self.page_indices['spectrum.read_spins'], self.wizard_page_after_sequence_read)

        # The structure.load_spins page.
        page = uf_store['structure.load_spins'].create_page(self.wizard)
        self.page_indices['structure.load_spins'] = self.wizard.add_page(page)

        # The termination page.
        page = Finish_page(self.wizard)
        self.page_indices['fin'] = self.wizard.add_page(page, apply_button=False, skip_button=False)

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()

        # Run the wizard.
        self.wizard.run()
Пример #5
0
    def run(self):
        """Run through the analysis selection wizard, returning the results.

        @return:    The analysis type, analysis name, data pipe name, data pipe bundle name, and user function on_execute method list.
        @rtype:     tuple of str
        """

        # Change the cursor to busy.
        wx.Yield()
        wx.BeginBusyCursor()

        # Set up the wizard.
        self.wizard = Wiz_window(size_x=1000,
                                 size_y=700,
                                 title='Analysis selection wizard')

        # Change the finish button.
        self.wizard.TEXT_FINISH = " Start"

        # Add the new analysis panel.
        self.new_page = New_analysis_page(self.wizard)
        self.wizard.add_page(self.new_page, apply_button=False)
        self.wizard.set_seq_next_fn(0, self.wizard_page_after_analysis)

        # Add the data pipe name panel.
        self.pipe_page = Data_pipe_page(self.wizard, height_desc=400)
        self.wizard.add_page(self.pipe_page, apply_button=False)

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()

        # Execute the wizard.
        setup = self.wizard.run(modal=True)
        if setup != wx.ID_OK:
            return

        # Return the analysis type, analysis name, data pipe name, data pipe bundle name, and user function on_execute method list.
        return self.get_data()
Пример #6
0
    def setup_dipole_pair(self, event=None):
        """Create the wizard for the dipole-dipole interaction.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Change the cursor to busy.
        wx.BeginBusyCursor()

        # Destroy the dipole-dipole interaction wizard, if it exists.
        if hasattr(self, 'dipole_wizard'):
            self.dipole_wizard.Destroy()

        # Create the wizard.
        self.dipole_wizard = Wiz_window(parent=self.gui, size_x=1000, size_y=750, title="Dipole-dipole interaction setup")

        # Structural data.
        if not hasattr(cdp, 'structure'):
            # Create the PDB reading page.
            page = uf_store['structure.read_pdb'].create_page(self.dipole_wizard, sync=True)
            self.dipole_wizard.add_page(page, skip_button=True)

            # Create the position reading page.
            page = uf_store['structure.get_pos'].create_page(self.dipole_wizard, sync=True)
            self.dipole_wizard.add_page(page, skip_button=True)

        # Create the interatom.define page.
        page = uf_store['interatom.define'].create_page(self.dipole_wizard, sync=True)
        page.SetValue('spin_id1', '@N')
        page.SetValue('spin_id2', '@H')
        self.dipole_wizard.add_page(page)

        # Create the interatom.set_dist page.
        page = uf_store['interatom.set_dist'].create_page(self.dipole_wizard, sync=True)
        page.SetValue('spin_id1', '@N*')
        page.SetValue('spin_id2', '@H*')
        page.SetValue('ave_dist', NH_BOND_LENGTH)
        self.dipole_wizard.add_page(page)

        # Create the interatom.unit_vectors page.
        page = uf_store['interatom.unit_vectors'].create_page(self.dipole_wizard, sync=True)
        self.dipole_wizard.add_page(page)

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()

        # Execute the wizard.
        self.dipole_wizard.run()
Пример #7
0
    def wizard_exec(self, bruker=False):
        """Launch the Rx peak loading wizard.

        @keyword bruker:    A flag which if True will launch the Bruker Dynamics Centre data reading wizard and if False will launch the relaxation data reading wizard
        @type bruker:       bool
        """

        # Change the cursor to busy.
        wx.BeginBusyCursor()

        # The title.
        if bruker:
            title = "The Bruker Dynamics Centre data reading wizard"
        else:
            title = "The relaxation data reading wizard"

        # Initialise a wizard.
        self.wizard = Wiz_window(parent=self.gui, size_x=1000, size_y=800, title=title)
        self.page_indices = {}

        # The reading page.
        if bruker:
            page = uf_store['bruker.read'].create_page(self.wizard, sync=True)
        else:
            page = uf_store['relax_data.read'].create_page(self.wizard, sync=True)
        self.page_indices['read'] = self.wizard.add_page(page, skip_button=True, proceed_on_error=False)

        # The peak intensity type page.
        page = uf_store['relax_data.peak_intensity_type'].create_page(self.wizard, sync=True)
        self.page_indices['peak_intensity_type'] = self.wizard.add_page(page, apply_button=True, skip_button=True)
        page.on_display_post = self.wizard_update_int_type

        # The temperature calibration page.
        page = uf_store['relax_data.temp_calibration'].create_page(self.wizard, sync=True)
        self.page_indices['temp_calibration'] = self.wizard.add_page(page, apply_button=True, skip_button=True)
        page.on_display_post = self.wizard_update_temp_calibration

        # The temperature control page.
        page = uf_store['relax_data.temp_control'].create_page(self.wizard, sync=True)
        self.page_indices['temp_control'] = self.wizard.add_page(page, apply_button=True)
        page.on_display_post = self.wizard_update_temp_control

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()

        # Run the wizard.
        self.wizard.run()
Пример #8
0
    def run(self):
        """Run through the analysis selection wizard, returning the results.

        @return:    The analysis type, analysis name, data pipe name, data pipe bundle name, and user function on_execute method list.
        @rtype:     tuple of str
        """

        # Change the cursor to busy.
        wx.Yield()
        wx.BeginBusyCursor()

        # Set up the wizard.
        self.wizard = Wiz_window(size_x=1000, size_y=700, title='Analysis selection wizard')

        # Change the finish button.
        self.wizard.TEXT_FINISH = " Start"

        # Add the new analysis panel.
        self.new_page = New_analysis_page(self.wizard)
        self.wizard.add_page(self.new_page, apply_button=False)
        self.wizard.set_seq_next_fn(0, self.wizard_page_after_analysis)

        # Add the data pipe name panel.
        self.pipe_page = Data_pipe_page(self.wizard, height_desc=400)
        self.wizard.add_page(self.pipe_page, apply_button=False)

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()

        # Execute the wizard.
        setup = self.wizard.run(modal=True)
        if setup != wx.ID_OK:
            return

        # Return the analysis type, analysis name, data pipe name, data pipe bundle name, and user function on_execute method list.
        return self.get_data()
Пример #9
0
class Analysis_wizard:
    """The analysis selection wizard."""

    def Destroy(self):
        """Properly delete the wizard and all its elements."""

        self.wizard.Destroy()


    def run(self):
        """Run through the analysis selection wizard, returning the results.

        @return:    The analysis type, analysis name, data pipe name, data pipe bundle name, and user function on_execute method list.
        @rtype:     tuple of str
        """

        # Change the cursor to busy.
        wx.Yield()
        wx.BeginBusyCursor()

        # Set up the wizard.
        self.wizard = Wiz_window(size_x=1000, size_y=700, title='Analysis selection wizard')

        # Change the finish button.
        self.wizard.TEXT_FINISH = " Start"

        # Add the new analysis panel.
        self.new_page = New_analysis_page(self.wizard)
        self.wizard.add_page(self.new_page, apply_button=False)
        self.wizard.set_seq_next_fn(0, self.wizard_page_after_analysis)

        # Add the data pipe name panel.
        self.pipe_page = Data_pipe_page(self.wizard, height_desc=400)
        self.wizard.add_page(self.pipe_page, apply_button=False)

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()

        # Execute the wizard.
        setup = self.wizard.run(modal=True)
        if setup != wx.ID_OK:
            return

        # Return the analysis type, analysis name, data pipe name, data pipe bundle name, and user function on_execute method list.
        return self.get_data()


    def get_data(self):
        """Assemble and return the analysis type, analysis name, and pipe name.

        @return:    The analysis type, analysis name, data pipe name, data pipe bundle name, and list of user function on_execute methods.
        @rtype:     str, str, str, str, list of methods
        """

        # Get the data.
        analysis_type = gui_to_str(self.wizard.analysis_type)
        analysis_name = gui_to_str(self.new_page.analysis_name.GetValue())
        pipe_name = gui_to_str(self.pipe_page.pipe_name.GetValue())
        pipe_bundle = gui_to_str(self.pipe_page.pipe_bundle.GetValue())

        # The user function on_execute methods.
        uf_exec = []

        # Return it.
        return analysis_type, analysis_name, pipe_name, pipe_bundle, uf_exec


    def wizard_page_after_analysis(self):
        """Set the page after the data pipe setup.

        @return:    The index of the next page, which is the current page index plus one.
        @rtype:     int
        """

        # The selected analysis.
        analysis_name = gui_to_str(self.new_page.analysis_name.GetValue())

        # Default to the second page.
        return 1
Пример #10
0
    def load_spins_wizard(self, event=None):
        """The spin loading wizard.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # No current data pipe.
        if not cdp_name():
            gui_raise(RelaxNoPipeError())
            return

        # Change the cursor to busy.
        wx.BeginBusyCursor()

        # Destroy the spin loading wizard, if it exists.
        if hasattr(self, 'wizard'):
            self.wizard.Destroy()

        # Initialise a wizard.
        self.wizard = Wiz_window(parent=self, size_x=1000, size_y=750, title="Load spins")
        self.page_indices = {}

        # The loading method page.
        self.page_method = Load_method_page(self.wizard)
        self.page_indices['method'] = self.wizard.add_page(self.page_method, apply_button=True, skip_button=False)
        self.wizard.set_seq_next_fn(self.page_indices['method'], self.wizard_page_after_load_method)

        # The sequence.read page.
        page = uf_store['sequence.read'].create_page(self.wizard)
        self.page_indices['sequence.read'] = self.wizard.add_page(page, skip_button=True)
        self.wizard.set_seq_next_fn(self.page_indices['sequence.read'], self.wizard_page_after_sequence_read)

        # The structure.read_pdb page.
        page = uf_store['structure.read_pdb'].create_page(self.wizard)
        self.page_indices['structure.read_pdb'] = self.wizard.add_page(page, skip_button=True)
        self.wizard.set_seq_next_fn(self.page_indices['structure.read_pdb'], self.wizard_page_after_structure_read)

        # The structure.read_xyz page.
        page = uf_store['structure.read_xyz'].create_page(self.wizard)
        self.page_indices['structure.read_xyz'] = self.wizard.add_page(page, skip_button=True)
        self.wizard.set_seq_next_fn(self.page_indices['structure.read_xyz'], self.wizard_page_after_structure_read)

        # The spectrum.read_spins page.
        page = uf_store['spectrum.read_spins'].create_page(self.wizard)
        self.page_indices['spectrum.read_spins'] = self.wizard.add_page(page, skip_button=True)
        self.wizard.set_seq_next_fn(self.page_indices['spectrum.read_spins'], self.wizard_page_after_sequence_read)

        # The structure.load_spins page.
        page = uf_store['structure.load_spins'].create_page(self.wizard)
        self.page_indices['structure.load_spins'] = self.wizard.add_page(page)

        # The termination page.
        page = Finish_page(self.wizard)
        self.page_indices['fin'] = self.wizard.add_page(page, apply_button=False, skip_button=False)

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()

        # Run the wizard.
        self.wizard.run()
Пример #11
0
class Relax_data_list(Base_list):
    """The GUI element for listing loaded relaxation data."""
    def action_relax_data_delete(self, event):
        """Launch the relax_data.delete user function.

        @param event:   The wx event.
        @type event:    wx event
        """

        # The current selection.
        item = self.element.GetFirstSelected()

        # No selection.
        if item == -1:
            id = None

        # Selected item.
        else:
            # The spectrum ID.
            id = gui_to_str(self.element.GetItemText(item))

        # Launch the dialog.
        uf_store['relax_data.delete'](ri_id=id)

    def action_relax_data_display(self, event):
        """Launch the relax_data.display user function.

        @param event:   The wx event.
        @type event:    wx event
        """

        # The current selection.
        item = self.element.GetFirstSelected()

        # The spectrum ID.
        id = gui_to_str(self.element.GetItemText(item))

        # Launch the dialog.
        uf_store['relax_data.display'](ri_id=id)

    def action_relax_data_peak_intensity_type(self, event):
        """Launch the relax_data.peak_intensity_type user function.

        @param event:   The wx event.
        @type event:    wx event
        """

        # The current selection.
        item = self.element.GetFirstSelected()

        # The spectrum ID.
        id = gui_to_str(self.element.GetItemText(item))

        # The current type.
        type = None
        if hasattr(cdp, 'exp_info') and hasattr(
                cdp.exp_info, 'peak_intensity_type'
        ) and id in cdp.exp_info.peak_intensity_type:
            type = cdp.exp_info.peak_intensity_type[id]

        # Launch the dialog.
        if type == None:
            uf_store['relax_data.peak_intensity_type'](ri_id=id)
        else:
            uf_store['relax_data.peak_intensity_type'](ri_id=id, type=type)

    def action_relax_data_temp_calibration(self, event):
        """Launch the relax_data.temp_calibration user function.

        @param event:   The wx event.
        @type event:    wx event
        """

        # The current selection.
        item = self.element.GetFirstSelected()

        # The spectrum ID.
        id = gui_to_str(self.element.GetItemText(item))

        # The current method.
        method = None
        if hasattr(cdp, 'exp_info') and hasattr(
                cdp.exp_info,
                'temp_calibration') and id in cdp.exp_info.temp_calibration:
            method = cdp.exp_info.temp_calibration[id]

        # Launch the dialog.
        if method == None:
            uf_store['relax_data.temp_calibration'](ri_id=id)
        else:
            uf_store['relax_data.temp_calibration'](ri_id=id, method=method)

    def action_relax_data_temp_control(self, event):
        """Launch the relax_data.temp_control user function.

        @param event:   The wx event.
        @type event:    wx event
        """

        # The current selection.
        item = self.element.GetFirstSelected()

        # The spectrum ID.
        id = gui_to_str(self.element.GetItemText(item))

        # The current method.
        method = None
        if hasattr(cdp, 'exp_info') and hasattr(
                cdp.exp_info,
                'temp_control') and id in cdp.exp_info.temp_control:
            method = cdp.exp_info.temp_control[id]

        # Launch the dialog.
        if method == None:
            uf_store['relax_data.temp_control'](ri_id=id)
        else:
            uf_store['relax_data.temp_control'](ri_id=id, method=method)

    def action_relax_data_type(self, event):
        """Launch the relax_data.type user function.

        @param event:   The wx event.
        @type event:    wx event
        """

        # The current selection.
        item = self.element.GetFirstSelected()

        # The spectrum ID.
        id = gui_to_str(self.element.GetItemText(item))

        # The current type.
        type = None
        if hasattr(cdp, 'ri_type') and id in cdp.ri_type:
            type = cdp.ri_type[id]

        # Launch the dialog.
        if type == None:
            uf_store['relax_data.type'](ri_id=id)
        else:
            uf_store['relax_data.type'](ri_id=id, ri_type=type)

    def action_spectrometer_frequency(self, event):
        """Launch the spectrometer.frequency user function.

        @param event:   The wx event.
        @type event:    wx event
        """

        # The current selection.
        item = self.element.GetFirstSelected()

        # The spectrum ID.
        id = gui_to_str(self.element.GetItemText(item))

        # The current frequency.
        frq = None
        if hasattr(cdp, 'spectrometer_frq') and id in cdp.spectrometer_frq:
            frq = cdp.spectrometer_frq[id]

        # Launch the dialog.
        if frq == None:
            uf_store['spectrometer.frequency'](id=id)
        else:
            uf_store['spectrometer.frequency'](id=id, frq=frq)

    def setup(self):
        """Override the base variables."""

        # GUI variables.
        self.title = "Relaxation data list"
        self.observer_base_name = "relaxation data list"

        # The column titles.
        self.columns = ["Relaxation data ID", "Data type", "Frequency (Hz)"]

        # Button set up.
        self.button_placement = 'top'
        self.button_size = (170, 40)
        self.button_info = [{
            'object':
            'button_add',
            'label':
            ' Add',
            'icon':
            fetch_icon('oxygen.actions.list-add-relax-blue', "22x22"),
            'method':
            self.wizard_relax_data,
            'tooltip':
            "Read relaxation data from a file."
        }, {
            'object':
            'button_bruker',
            'label':
            ' Add',
            'icon':
            fetch_icon('relax.bruker_add', "22x22"),
            'method':
            self.wizard_bruker,
            'tooltip':
            "Read a Bruker Dynamics Center relaxation data file."
        }, {
            'object':
            'button_delete',
            'label':
            ' Delete',
            'icon':
            fetch_icon('oxygen.actions.list-remove', "22x22"),
            'method':
            self.action_relax_data_delete,
            'tooltip':
            "Delete loaded relaxation data from the relax data store."
        }, {
            'object':
            'button_metadata',
            'label':
            ' View metadata',
            'icon':
            fetch_icon('oxygen.mimetypes.text-x-texinfo', "22x22"),
            'method':
            self.view_metadata,
            'tooltip':
            "View and edit the relaxation data metadata."
        }]

        # The right click popup menu.
        self.popup_menus = [{
            'id':
            MENU_RELAX_DATA_DELETE,
            'text':
            "&Delete the relaxation data",
            'icon':
            fetch_icon(uf_info.get_uf('relax_data.delete').gui_icon),
            'method':
            self.action_relax_data_delete
        }, {
            'id':
            MENU_RELAX_DATA_DISPLAY,
            'text':
            "Dis&play the relaxation data",
            'icon':
            fetch_icon(uf_info.get_uf('relax_data.display').gui_icon),
            'method':
            self.action_relax_data_display
        }, {
            'id':
            MENU_SPECTROMETER_FREQUENCY,
            'text':
            "Set the relaxation data &frequency",
            'icon':
            fetch_icon(uf_info.get_uf('spectrometer.frequency').gui_icon),
            'method':
            self.action_spectrometer_frequency
        }, {
            'id':
            MENU_RELAX_DATA_PEAK_INTENSITY_TYPE,
            'text':
            "Set the peak &intensity type",
            'icon':
            fetch_icon(
                uf_info.get_uf('relax_data.peak_intensity_type').gui_icon),
            'method':
            self.action_relax_data_peak_intensity_type
        }, {
            'id':
            MENU_RELAX_DATA_TEMP_CALIBRATION,
            'text':
            "Set the temperature &calibration",
            'icon':
            fetch_icon(uf_info.get_uf('relax_data.temp_calibration').gui_icon),
            'method':
            self.action_relax_data_temp_calibration
        }, {
            'id':
            MENU_RELAX_DATA_TEMP_CONTROL,
            'text':
            "Set the temperature c&ontrol",
            'icon':
            fetch_icon(uf_info.get_uf('relax_data.temp_control').gui_icon),
            'method':
            self.action_relax_data_temp_control
        }, {
            'id':
            MENU_RELAX_DATA_TYPE,
            'text':
            "Set the relaxation data &type",
            'icon':
            fetch_icon(uf_info.get_uf('relax_data.type').gui_icon),
            'method':
            self.action_relax_data_type
        }]

    def update_data(self):
        """Method called from self.build_element_safe() to update the list data."""

        # Translation table for the Rx data types.
        table = {
            "NOE": "Steady-state NOE",
            "R1": "%s longitudinal relaxation" % r1,
            "R2": "%s transverse relaxation" % r2
        }

        # Expand the number of rows to match the number of relaxation IDs, and add the IDs.
        n = 0
        if hasattr(cdp, 'ri_ids'):
            # The number of IDs.
            n = len(cdp.ri_ids)

            # Add all the data.
            for i in range(n):
                # Set the IDs.
                id = cdp.ri_ids[i]
                self.element.InsertStringItem(i, str_to_gui(id))

                # Set the data types.
                self.element.SetStringItem(i, 1,
                                           str_to_gui(table[cdp.ri_type[id]]))

                # Set the frequencies.
                self.element.SetStringItem(
                    i, 2, float_to_gui(cdp.spectrometer_frq[id]))

    def view_metadata(self, event=None):
        """Launch the metadata window.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Launch.
        Metadata_window(self.gui)

    def wizard_bruker(self, event):
        """Launch the Bruker Dynamics Centre data reading wizard.

        @param event:   The wx event.
        @type event:    wx event
        """

        # The wizard.
        self.wizard_exec(bruker=True)

    def wizard_exec(self, bruker=False):
        """Launch the Rx peak loading wizard.

        @keyword bruker:    A flag which if True will launch the Bruker Dynamics Centre data reading wizard and if False will launch the relaxation data reading wizard
        @type bruker:       bool
        """

        # Change the cursor to busy.
        wx.BeginBusyCursor()

        # The title.
        if bruker:
            title = "The Bruker Dynamics Centre data reading wizard"
        else:
            title = "The relaxation data reading wizard"

        # Destroy any pre-existing wizards.
        if hasattr(self, 'wizard'):
            self.wizard.Destroy()

        # Initialise a wizard.
        self.wizard = Wiz_window(parent=self.gui,
                                 size_x=1000,
                                 size_y=750,
                                 title=title)
        self.page_indices = {}

        # The reading page.
        if bruker:
            page = uf_store['bruker.read'].create_page(self.wizard, sync=True)
        else:
            page = uf_store['relax_data.read'].create_page(self.wizard,
                                                           sync=True)
        self.page_indices['read'] = self.wizard.add_page(
            page, skip_button=True, proceed_on_error=False)

        # The peak intensity type page.
        page = uf_store['relax_data.peak_intensity_type'].create_page(
            self.wizard, sync=True)
        self.page_indices['peak_intensity_type'] = self.wizard.add_page(
            page, apply_button=True, skip_button=True)
        page.on_display_post = self.wizard_update_int_type

        # The temperature calibration page.
        page = uf_store['relax_data.temp_calibration'].create_page(self.wizard,
                                                                   sync=True)
        self.page_indices['temp_calibration'] = self.wizard.add_page(
            page, apply_button=True, skip_button=True)
        page.on_display_post = self.wizard_update_temp_calibration

        # The temperature control page.
        page = uf_store['relax_data.temp_control'].create_page(self.wizard,
                                                               sync=True)
        self.page_indices['temp_control'] = self.wizard.add_page(
            page, apply_button=True)
        page.on_display_post = self.wizard_update_temp_control

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()

        # Run the wizard.
        self.wizard.run()

    def wizard_relax_data(self, event):
        """Launch the relaxation data reading wizard.

        @param event:   The wx event.
        @type event:    wx event
        """

        # The wizard.
        self.wizard_exec(bruker=False)

    def wizard_update_int_type(self):
        """Update the relax_data.peak_intensity_type page based on previous data."""

        # The relax_data.peak_intensity_type page.
        page = self.wizard.get_page(self.page_indices['read'])

        # Get the Rx ID.
        id = page.uf_args['ri_id'].GetValue()

        # Set the ID in the relax_data.peak_intensity_type page.
        page = self.wizard.get_page(self.page_indices['peak_intensity_type'])
        page.uf_args['ri_id'].SetValue(value=id)

    def wizard_update_temp_calibration(self):
        """Update the relax_data.temp_calibration page based on previous data."""

        # The relax_data.temp_calibration page.
        page = self.wizard.get_page(self.page_indices['read'])

        # Get the Rx ID.
        id = page.uf_args['ri_id'].GetValue()

        # Set the ID in the relax_data.temp_calibration page.
        page = self.wizard.get_page(self.page_indices['temp_calibration'])
        page.uf_args['ri_id'].SetValue(value=id)

    def wizard_update_temp_control(self):
        """Update the relax_data.temp_control page based on previous data."""

        # The relax_data.temp_control page.
        page = self.wizard.get_page(self.page_indices['read'])

        # Get the Rx ID.
        id = page.uf_args['ri_id'].GetValue()

        # Set the ID in the relax_data.temp_control page.
        page = self.wizard.get_page(self.page_indices['temp_control'])
        page.uf_args['ri_id'].SetValue(value=id)
Пример #12
0
    def wizard_exec(self, bruker=False):
        """Launch the Rx peak loading wizard.

        @keyword bruker:    A flag which if True will launch the Bruker Dynamics Centre data reading wizard and if False will launch the relaxation data reading wizard
        @type bruker:       bool
        """

        # Change the cursor to busy.
        wx.BeginBusyCursor()

        # The title.
        if bruker:
            title = "The Bruker Dynamics Centre data reading wizard"
        else:
            title = "The relaxation data reading wizard"

        # Destroy any pre-existing wizards.
        if hasattr(self, 'wizard'):
            self.wizard.Destroy()

        # Initialise a wizard.
        self.wizard = Wiz_window(parent=self.gui,
                                 size_x=1000,
                                 size_y=750,
                                 title=title)
        self.page_indices = {}

        # The reading page.
        if bruker:
            page = uf_store['bruker.read'].create_page(self.wizard, sync=True)
        else:
            page = uf_store['relax_data.read'].create_page(self.wizard,
                                                           sync=True)
        self.page_indices['read'] = self.wizard.add_page(
            page, skip_button=True, proceed_on_error=False)

        # The peak intensity type page.
        page = uf_store['relax_data.peak_intensity_type'].create_page(
            self.wizard, sync=True)
        self.page_indices['peak_intensity_type'] = self.wizard.add_page(
            page, apply_button=True, skip_button=True)
        page.on_display_post = self.wizard_update_int_type

        # The temperature calibration page.
        page = uf_store['relax_data.temp_calibration'].create_page(self.wizard,
                                                                   sync=True)
        self.page_indices['temp_calibration'] = self.wizard.add_page(
            page, apply_button=True, skip_button=True)
        page.on_display_post = self.wizard_update_temp_calibration

        # The temperature control page.
        page = uf_store['relax_data.temp_control'].create_page(self.wizard,
                                                               sync=True)
        self.page_indices['temp_control'] = self.wizard.add_page(
            page, apply_button=True)
        page.on_display_post = self.wizard_update_temp_control

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()

        # Run the wizard.
        self.wizard.run()
Пример #13
0
class Uf_object(object):
    """The object for auto-generating the GUI user functions."""

    def __call__(self, event=None, wx_parent=None, wx_wizard_sync=None, wx_wizard_run=True, wx_wizard_modal=False, **kwds):
        """Make the GUI user function executable.

        All keyword args, apart from 'event', 'wx_parent' and 'wx_wizard_run' will be assumed to be user function arguments and the Uf_page.SetValue() method of the page will be used to set the GUI arg elements to the values supplied.


        @keyword event:             The wx event.
        @type event:                wx event or None
        @keyword wx_parent:         The parent wx object to associate the user function wizard to.
        @type wx_parent:            wx object
        @keyword wx_wizard_sync:    A flag which if given will switch between synchronous and asynchronous user function operation.
        @type wx_wizard_sync:       None or bool
        @keyword wx_wizard_run:     A flag which if True will call the wizard run() method.
        @type wx_wizard_run:        bool
        @keyword wx_wizard_modal:   A flag which if True will cause the wizard run() method to have the modal flag set so that the wizard is modal.
        @type wx_wizard_modal:      bool
        @return:                    The status of the call.  If the call failed, False will be returned.
        @rtype:                     bool
        """

        # Store the sync flag.
        if wx_wizard_sync != None:
            self._sync = wx_wizard_sync

        # Create a new wizard if needed (checking that the parent of an old wizard is not the same).
        if self.wizard == None or (wx_parent != None and wx_parent != self.wizard.GetParent()) or len(self.wizard._pages) == 0:
            status = self.create_wizard(wx_parent)
            if not status:
                return False

        # Otherwise reset the wizard.
        else:
            self.wizard.reset()

        # Update all of the user function argument choices (ComboBoxes) to be current, returning if a failure occurred.
        if not self.page.update_args():
            return False

        # Loop over the keyword args, using the Uf_page.SetValue() method to set the user function argument GUI element values.
        for key in kwds:
            self.page.SetValue(key, kwds[key])

        # Execute the wizard when asked.
        if wx_wizard_run:
            self.wizard.run(modal=wx_wizard_modal)


    def __init__(self, name, title=None, size=None, height_desc=None, apply_button=True, sync=False):
        """Set up the object.

        @param name:            The name of the user function.
        @type name:             str
        @keyword title:         The long title of the user function to set as the window title.
        @type title:            str
        @keyword size:          The window size.
        @type size:             tuple of int
        @keyword height_desc:   The height in pixels of the description part of the wizard.
        @type height_desc:      int or None
        @keyword apply_button:  A flag specifying if the apply button should be shown or not.  This defaults to True.
        @type apply_button:     bool
        @keyword sync:          A flag which if True will call user functions via interpreter.apply and if False via interpreter.queue.
        @type sync:             bool
        """

        # Store the args.
        self._name = name
        self._title = title
        self._size = size
        self._height_desc = height_desc
        self._apply_button = apply_button
        self._sync = sync

        # Initialise the wizard storage.
        self.wizard = None

        # Create a unique wx ID for the user function.
        self._uf_id = wx.NewId()


    def Destroy(self):
        """Cleanly destroy the user function GUI elements."""

        # First flush all events.
        wx.Yield()

        # Destroy the user function page.
        if hasattr(self, 'page'):
            # Loop over the user function arguments.
            for key in self.page.uf_args:
                # Destroy any selection windows.
                if hasattr(self.page.uf_args[key], 'sel_win'):
                    self.page.uf_args[key].sel_win.Destroy()

            # Delete the page object.
            del self.page

        # Destroy the wizard, if it exists.
        if self.wizard != None:
            self.wizard.Destroy()
            self.wizard = None


    def create_page(self, wizard=None, sync=None, execute=True):
        """Create the user function wizard page GUI object.

        @keyword wizard:    The parent wizard.
        @type wizard:       Wiz_window instance
        @keyword sync:      A flag which if True will call user functions via interpreter.apply and if False via interpreter.queue.
        @type sync:         None or bool
        @keyword execute:   A flag which if True will prevent the user function from being executed when clicking on 'Next', 'Ok', or 'Apply'.  This can be useful for delaying the execution of the user function.
        @type execute:      bool
        @return:            The user function page object.
        @rtype:             Uf_page instance
        """

        # Overwrite (a)synchronous operation.
        if sync != None:
            self._sync = sync

        # Initialise and return the page.
        return Uf_page(self._name, parent=wizard, height_desc=self._height_desc, sync=self._sync, execute=execute)


    def create_wizard(self, parent=None):
        """Create the user function wizard GUI object, with embedded wizard page.

        @keyword parent:    The parent wx window.
        @type parent:       wx.Window instance
        @return:            True if the wizard was created, False if a problem was encountered.
        @rtype:             bool
        """

        # The parent object defaults to the main relax window.
        if parent == None:
            app = wx.GetApp()
            parent = app.gui

        # Create the wizard dialog.
        self.wizard = Wiz_window(parent=parent, size_x=self._size[0], size_y=self._size[1], title="The %s user function"%self._name)

        # Create the page.
        self.page = self.create_page(self.wizard, sync=self._sync)

        # For an update of the argument data.
        if not self.page.update_args():
            return False

        # Add the page to the wizard.
        self.wizard.add_page(self.page, apply_button=self._apply_button)

        # Success.
        return True
Пример #14
0
class Spin_view_window(wx.Frame):
    """A window element for the tree view."""

    def __init__(self, *args, **kwds):
        """Set up the relax prompt."""

        # Store the parent object.
        self.gui = kwds.pop('parent')

        # Create GUI elements
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        if not status.debug and status.wx_info["os"] != 'darwin':
            kwds["style"] = kwds["style"] | wx.MAXIMIZE
        wx.Frame.__init__(self, *args, **kwds)

        # Force the main window to start maximised (needed for MS Windows).
        if not status.debug and status.wx_info["os"] != 'darwin':
            self.Maximize()

        # Set up the window icon.
        self.SetIcons(relax_icons)

        # Some default values.
        self.size_x = 1000
        self.size_y = 750

        # Set up the window.
        sizer = self.setup_window()

        # Create a menu.
        self._create_menu()

        # Build the toolbar.
        self.toolbar()

        # The splitter window.
        splitter = Tree_splitter(self.gui, self, -1)
        sizer.Add(splitter, 1, wx.EXPAND|wx.ALL, 0)

        # Initialise observer name.
        self.name = 'spin viewer'


    def _activate(self):
        """Activate or deactivate certain elements in response to the execution lock."""

        # Flag for enabling or disabling the elements.
        enable = False
        if not status.exec_lock.locked():
            enable = True

        # Loop over the menus.
        for menu, label in self.menubar.GetMenus():
            # Loop over the menu items.
            for item in menu.GetMenuItems():
                wx.CallAfter(item.Enable, enable)

        # The spin loader.
        wx.CallAfter(self.bar.EnableTool, TB_SPIN_LOADER_ID, enable)

        # The pipe selector.
        wx.CallAfter(self.pipe_name.Enable, enable)


    def _create_menu(self):
        """Build a menu for the window."""

        # Create the menu bar GUI item and add it to the main frame.
        self.menubar = wx.MenuBar()
        if status.show_gui:
            self.SetMenuBar(self.menubar)

        # The user function menus.
        self.menu_uf_ids = build_uf_menus(parent=self, menubar=self.menubar)


    def Destroy(self, event=None):
        """Cleanly destroy the spin viewer window.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # First unregister the methods from the observers.
        status.observers.gui_uf.unregister(self.name)
        status.observers.pipe_alteration.unregister(self.name)
        status.observers.exec_lock.unregister(self.name)

        # Destroy the spin loading wizard, if it exists.
        if hasattr(self, 'wizard'):
            self.wizard.Destroy()
            del self.wizard

        # Destroy all children of the window.
        super(Spin_view_window, self).DestroyChildren()

        # Destroy the spin viewer window.
        super(Spin_view_window, self).Destroy()


    def Show(self, show=True):
        """Change the behaviour of showing the window to update the content.

        @keyword show:  A flag which is True shows the window.
        @type show:     bool
        """

        # Register a few methods in the observer objects.
        status.observers.gui_uf.register(self.name, self.refresh, method_name='ref')
        status.observers.pipe_alteration.register(self.name, self.refresh, method_name='ref')
        status.observers.exec_lock.register(self.name, self._activate, method_name='_activate')

        # First update.
        self.refresh()

        # Activate or deactivate the frame.
        self._activate()

        # Then show the window using the base class method.
        if status.show_gui:
            super(Spin_view_window, self).Show(show)


    def refresh(self, event=None):
        """Event handler for the refresh action (thread safe).

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Thread safe.
        wx.CallAfter(self.refresh_safe)


    def refresh_safe(self):
        """Refresh the spin viewer window."""

        # Change the cursor to busy.
        wx.BeginBusyCursor()

        # Update the data pipe selector.
        self.update_pipes()

        # Update the tree.
        self.tree_panel.update()

        # Redisplay the container.
        self.container.display(self.tree_panel.get_info())

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()


    def handler_close(self, event=None):
        """Event handler for the close window action.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Unregister the methods from the observers to avoid unnecessary updating.
        status.observers.gui_uf.unregister(self.name)
        status.observers.pipe_alteration.unregister(self.name)
        status.observers.exec_lock.unregister(self.name)

        # Close the window.
        self.Hide()


    def load_spins_wizard(self, event=None):
        """The spin loading wizard.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # No current data pipe.
        if not cdp_name():
            gui_raise(RelaxNoPipeError())
            return

        # Change the cursor to busy.
        wx.BeginBusyCursor()

        # Destroy the spin loading wizard, if it exists.
        if hasattr(self, 'wizard'):
            self.wizard.Destroy()

        # Initialise a wizard.
        self.wizard = Wiz_window(parent=self, size_x=1000, size_y=750, title="Load spins")
        self.page_indices = {}

        # The loading method page.
        self.page_method = Load_method_page(self.wizard)
        self.page_indices['method'] = self.wizard.add_page(self.page_method, apply_button=True, skip_button=False)
        self.wizard.set_seq_next_fn(self.page_indices['method'], self.wizard_page_after_load_method)

        # The sequence.read page.
        page = uf_store['sequence.read'].create_page(self.wizard)
        self.page_indices['sequence.read'] = self.wizard.add_page(page, skip_button=True)
        self.wizard.set_seq_next_fn(self.page_indices['sequence.read'], self.wizard_page_after_sequence_read)

        # The structure.read_pdb page.
        page = uf_store['structure.read_pdb'].create_page(self.wizard)
        self.page_indices['structure.read_pdb'] = self.wizard.add_page(page, skip_button=True)
        self.wizard.set_seq_next_fn(self.page_indices['structure.read_pdb'], self.wizard_page_after_structure_read)

        # The structure.read_xyz page.
        page = uf_store['structure.read_xyz'].create_page(self.wizard)
        self.page_indices['structure.read_xyz'] = self.wizard.add_page(page, skip_button=True)
        self.wizard.set_seq_next_fn(self.page_indices['structure.read_xyz'], self.wizard_page_after_structure_read)

        # The spectrum.read_spins page.
        page = uf_store['spectrum.read_spins'].create_page(self.wizard)
        self.page_indices['spectrum.read_spins'] = self.wizard.add_page(page, skip_button=True)
        self.wizard.set_seq_next_fn(self.page_indices['spectrum.read_spins'], self.wizard_page_after_sequence_read)

        # The structure.load_spins page.
        page = uf_store['structure.load_spins'].create_page(self.wizard)
        self.page_indices['structure.load_spins'] = self.wizard.add_page(page)

        # The termination page.
        page = Finish_page(self.wizard)
        self.page_indices['fin'] = self.wizard.add_page(page, apply_button=False, skip_button=False)

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()

        # Run the wizard.
        self.wizard.run()


    def setup_window(self):
        """Set up the window.

        @return:    The sizer object.
        @rtype:     wx.Sizer instance
        """

        # Set the frame title.
        self.SetTitle("The spin viewer")

        # Use a box sizer for packing the shell.
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(sizer)

        # Close the window cleanly (hide so it can be reopened).
        self.Bind(wx.EVT_CLOSE, self.handler_close)

        # Set the default size of the controller.
        self.SetSize((self.size_x, self.size_y))

        # Return the sizer.
        return sizer


    def toolbar(self):
        """Create the toolbar."""

        # Init.
        self.bar = self.CreateToolBar(wx.TB_HORIZONTAL|wx.TB_FLAT|wx.TB_TEXT)

        # The spin loading button.
        tooltip = "Load spins from either a sequence file or from a 3D structure file."
        self.bar.AddLabelTool(TB_SPIN_LOADER_ID, "Load spins", wx.Bitmap(fetch_icon('relax.spin', '32x32'), wx.BITMAP_TYPE_ANY), bmpDisabled=wx.Bitmap(fetch_icon('relax.spin_grey', '32x32'), wx.BITMAP_TYPE_ANY), shortHelp=tooltip, longHelp=tooltip)
        self.Bind(wx.EVT_TOOL, self.load_spins_wizard, id=TB_SPIN_LOADER_ID)

        # A separator.
        self.bar.AddSeparator()

        # The refresh button.
        tooltip = "Refresh the spin view."
        self.bar.AddLabelTool(TB_REFRESH, "Refresh", wx.Bitmap(fetch_icon('oxygen.actions.view-refresh', '32x32'), wx.BITMAP_TYPE_ANY), shortHelp=tooltip, longHelp=tooltip)
        self.Bind(wx.EVT_TOOL, self.refresh, id=TB_REFRESH)

        # A separator.
        self.bar.AddSeparator()

        # The pipe text.
        text = wx.StaticText(self.bar, -1, ' Current data pipe:  ', style=wx.ALIGN_LEFT)
        self.bar.AddControl(text)

        # The pipe selection.
        self.pipe_name = wx.ComboBox(self.bar, -1, "", style=wx.CB_DROPDOWN|wx.CB_READONLY, choices=[])
        self.bar.AddControl(self.pipe_name)
        self.Bind(wx.EVT_COMBOBOX, self.update_pipes, self.pipe_name)

        # Build the toolbar.
        self.bar.Realize()


    def uf_call(self, event=None):
        """Catch the user function call to properly specify the parent window.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # The user function ID.
        uf_id = event.GetId()

        # Get the user function name.
        name = uf_store.get_uf(uf_id)

        # Call the user function GUI object.
        uf_store[name](event=event, wx_parent=self)


    def update_pipes(self, event=None):
        """Update the spin view data pipe selector.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Change the cursor to busy.
        wx.BeginBusyCursor()

        # Init.
        pipe_switch = False

        # The selected pipe.
        if event:
            # The name of the selected pipe.
            pipe = gui_to_str(self.pipe_name.GetString(event.GetSelection()))

            # A pipe change.
            if pipe != cdp_name():
                pipe_switch = True
        else:
            pipe = cdp_name()
        if not pipe:
            pipe = ''

        # Clear the previous data.
        self.pipe_name.Clear()

        # The list of pipe names.
        for name in pipe_names():
            self.pipe_name.Append(str_to_gui(name))

        # Switch.
        if pipe_switch:
            # Switch data pipes.
            self.gui.interpreter.apply('pipe.switch', pipe)

            # Update the tree view.
            self.tree_panel.update()

        # Set the pipe name to the cdp.
        self.pipe_name.SetValue(str_to_gui(pipe))

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()


    def wizard_page_after_load_method(self):
        """Set the page after the load method choice.

        @return:    The index of the next page.
        @rtype:     int
        """

        # Go to the sequence.read page.
        if self.page_method.selection == 'sequence':
            return self.page_indices['sequence.read']

        # Go to the structure.read_pdb page.
        elif self.page_method.selection == 'new pdb':
            return self.page_indices['structure.read_pdb']

        # Go to the structure.read_xyz page.
        elif self.page_method.selection == 'new xyz':
            return self.page_indices['structure.read_xyz']

        # Go to the spectrum.read_spins page.
        elif self.page_method.selection == 'new spectrum':
            return self.page_indices['spectrum.read_spins']

        # Skip to the structure.load_spins page.
        elif self.page_method.selection == 'preload':
            return self.page_indices['structure.load_spins']


    def wizard_page_after_sequence_read(self):
        """Set the page after the sequence.read user function page.

        @return:    The index of the last page.
        @rtype:     int
        """

        # Return the index of the terminal page.
        return  self.page_indices['fin']


    def wizard_page_after_structure_read(self):
        """Set the page after the structure.read_* user function pages.

        @return:    The index of the structure.load_spins page.
        @rtype:     int
        """

        # Return the index of the terminal page.
        return  self.page_indices['structure.load_spins']
Пример #15
0
class Spin_view_window(wx.Frame):
    """A window element for the tree view."""

    def __init__(self, *args, **kwds):
        """Set up the relax prompt."""

        # Store the parent object.
        self.gui = kwds.pop('parent')

        # Create GUI elements
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        if not status.debug and status.wx_info["os"] != 'darwin':
            kwds["style"] = kwds["style"] | wx.MAXIMIZE
        wx.Frame.__init__(self, *args, **kwds)

        # Force the main window to start maximised (needed for MS Windows).
        if not status.debug and status.wx_info["os"] != 'darwin':
            self.Maximize()

        # Set up the window icon.
        self.SetIcons(relax_icons)

        # Some default values.
        self.size_x = 1000
        self.size_y = 750

        # Set up the window.
        sizer = self.setup_window()

        # Create a menu.
        self._create_menu()

        # Build the toolbar.
        self.toolbar()

        # The splitter window.
        splitter = Tree_splitter(self.gui, self, -1)
        sizer.Add(splitter, 1, wx.EXPAND|wx.ALL, 0)

        # Initialise observer name.
        self.name = 'spin viewer'


    def _activate(self):
        """Activate or deactivate certain elements in response to the execution lock."""

        # Flag for enabling or disabling the elements.
        enable = False
        if not status.exec_lock.locked():
            enable = True

        # Loop over the menus.
        for menu, label in self.menubar.GetMenus():
            # Loop over the menu items.
            for item in menu.GetMenuItems():
                wx.CallAfter(item.Enable, enable)

        # The spin loader.
        wx.CallAfter(self.bar.EnableTool, self.spin_loader_id, enable)

        # The pipe selector.
        wx.CallAfter(self.pipe_name.Enable, enable)


    def _create_menu(self):
        """Build a menu for the window."""

        # Create the menu bar GUI item and add it to the main frame.
        self.menubar = wx.MenuBar()
        if status.show_gui:
            self.SetMenuBar(self.menubar)

        # The user function menus.
        self.menu_uf_ids = build_uf_menus(parent=self, menubar=self.menubar)


    def Show(self, show=True):
        """Change the behaviour of showing the window to update the content.

        @keyword show:  A flag which is True shows the window.
        @type show:     bool
        """

        # Register a few methods in the observer objects.
        status.observers.gui_uf.register(self.name, self.refresh, method_name='ref')
        status.observers.pipe_alteration.register(self.name, self.refresh, method_name='ref')
        status.observers.exec_lock.register(self.name, self._activate, method_name='_activate')

        # First update.
        self.refresh()

        # Activate or deactivate the frame.
        self._activate()

        # Then show the window using the base class method.
        if status.show_gui:
            super(Spin_view_window, self).Show(show)


    def refresh(self, event=None):
        """Event handler for the refresh action (thread safe).

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Thread safe.
        wx.CallAfter(self.refresh_safe)


    def refresh_safe(self):
        """Refresh the spin viewer window."""

        # Change the cursor to busy.
        wx.BeginBusyCursor()

        # Update the data pipe selector.
        self.update_pipes()

        # Update the tree.
        self.tree_panel.update()

        # Redisplay the container.
        self.container.display(self.tree_panel.get_info())

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()


    def handler_close(self, event=None):
        """Event handler for the close window action.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Unregister the methods from the observers to avoid unnecessary updating.
        status.observers.gui_uf.unregister(self.name)
        status.observers.pipe_alteration.unregister(self.name)
        status.observers.exec_lock.unregister(self.name)

        # Close the window.
        self.Hide()


    def load_spins_wizard(self, event=None):
        """The spin loading wizard.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # No current data pipe.
        if not cdp_name():
            gui_raise(RelaxNoPipeError())
            return

        # Change the cursor to busy.
        wx.BeginBusyCursor()

        # Initialise a wizard.
        self.wizard = Wiz_window(parent=self, size_x=1000, size_y=800, title="Load spins")
        self.page_indices = {}

        # The loading method page.
        self.page_method = Load_method_page(self.wizard)
        self.page_indices['method'] = self.wizard.add_page(self.page_method, apply_button=True, skip_button=False)
        self.wizard.set_seq_next_fn(self.page_indices['method'], self.wizard_page_after_load_method)

        # The sequence.read page.
        page = uf_store['sequence.read'].create_page(self.wizard)
        self.page_indices['sequence.read'] = self.wizard.add_page(page, skip_button=True)
        self.wizard.set_seq_next_fn(self.page_indices['sequence.read'], self.wizard_page_after_sequence_read)

        # The structure.read_pdb page.
        page = uf_store['structure.read_pdb'].create_page(self.wizard)
        self.page_indices['structure.read_pdb'] = self.wizard.add_page(page, skip_button=True)
        self.wizard.set_seq_next_fn(self.page_indices['structure.read_pdb'], self.wizard_page_after_structure_read)

        # The structure.read_xyz page.
        page = uf_store['structure.read_xyz'].create_page(self.wizard)
        self.page_indices['structure.read_xyz'] = self.wizard.add_page(page, skip_button=True)
        self.wizard.set_seq_next_fn(self.page_indices['structure.read_xyz'], self.wizard_page_after_structure_read)

        # The spectrum.read_spins page.
        page = uf_store['spectrum.read_spins'].create_page(self.wizard)
        self.page_indices['spectrum.read_spins'] = self.wizard.add_page(page, skip_button=True)
        self.wizard.set_seq_next_fn(self.page_indices['spectrum.read_spins'], self.wizard_page_after_sequence_read)

        # The structure.load_spins page.
        page = uf_store['structure.load_spins'].create_page(self.wizard)
        self.page_indices['structure.load_spins'] = self.wizard.add_page(page)

        # The termination page.
        page = Finish_page(self.wizard)
        self.page_indices['fin'] = self.wizard.add_page(page, apply_button=False, skip_button=False)

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()

        # Run the wizard.
        self.wizard.run()


    def setup_window(self):
        """Set up the window.

        @return:    The sizer object.
        @rtype:     wx.Sizer instance
        """

        # Set the frame title.
        self.SetTitle("The spin viewer")

        # Use a box sizer for packing the shell.
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(sizer)

        # Close the window cleanly (hide so it can be reopened).
        self.Bind(wx.EVT_CLOSE, self.handler_close)

        # Set the default size of the controller.
        self.SetSize((self.size_x, self.size_y))

        # Return the sizer.
        return sizer


    def toolbar(self):
        """Create the toolbar."""

        # Init.
        self.bar = self.CreateToolBar(wx.TB_HORIZONTAL|wx.TB_FLAT|wx.TB_TEXT)

        # The spin loading button.
        self.spin_loader_id = wx.NewId()
        tooltip = "Load spins from either a sequence file or from a 3D structure file."
        self.bar.AddLabelTool(self.spin_loader_id, "Load spins", wx.Bitmap(fetch_icon('relax.spin', '32x32'), wx.BITMAP_TYPE_ANY), bmpDisabled=wx.Bitmap(fetch_icon('relax.spin_grey', '32x32'), wx.BITMAP_TYPE_ANY), shortHelp=tooltip, longHelp=tooltip)
        self.Bind(wx.EVT_TOOL, self.load_spins_wizard, id=self.spin_loader_id)

        # A separator.
        self.bar.AddSeparator()

        # The refresh button.
        id = wx.NewId()
        tooltip = "Refresh the spin view."
        self.bar.AddLabelTool(id, "Refresh", wx.Bitmap(fetch_icon('oxygen.actions.view-refresh', '32x32'), wx.BITMAP_TYPE_ANY), shortHelp=tooltip, longHelp=tooltip)
        self.Bind(wx.EVT_TOOL, self.refresh, id=id)

        # A separator.
        self.bar.AddSeparator()

        # The pipe text.
        text = wx.StaticText(self.bar, -1, ' Current data pipe:  ', style=wx.ALIGN_LEFT)
        self.bar.AddControl(text)

        # The pipe selection.
        self.pipe_name = wx.ComboBox(self.bar, -1, "", style=wx.CB_DROPDOWN|wx.CB_READONLY, choices=[])
        self.bar.AddControl(self.pipe_name)
        self.Bind(wx.EVT_COMBOBOX, self.update_pipes, self.pipe_name)

        # Build the toolbar.
        self.bar.Realize()


    def uf_call(self, event=None):
        """Catch the user function call to properly specify the parent window.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # The user function ID.
        uf_id = event.GetId()

        # Get the user function name.
        name = uf_store.get_uf(uf_id)

        # Call the user function GUI object.
        uf_store[name](event=event, wx_parent=self)


    def update_pipes(self, event=None):
        """Update the spin view data pipe selector.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Change the cursor to busy.
        wx.BeginBusyCursor()

        # Init.
        pipe_switch = False

        # The selected pipe.
        if event:
            # The name of the selected pipe.
            pipe = gui_to_str(self.pipe_name.GetString(event.GetSelection()))

            # A pipe change.
            if pipe != cdp_name():
                pipe_switch = True
        else:
            pipe = cdp_name()
        if not pipe:
            pipe = ''

        # Clear the previous data.
        self.pipe_name.Clear()

        # The list of pipe names.
        for name in pipe_names():
            self.pipe_name.Append(str_to_gui(name))

        # Switch.
        if pipe_switch:
            # Switch data pipes.
            self.gui.interpreter.apply('pipe.switch', pipe)

            # Update the tree view.
            self.tree_panel.update()

        # Set the pipe name to the cdp.
        self.pipe_name.SetValue(str_to_gui(pipe))

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()


    def wizard_page_after_load_method(self):
        """Set the page after the load method choice.

        @return:    The index of the next page.
        @rtype:     int
        """

        # Go to the sequence.read page.
        if self.page_method.selection == 'sequence':
            return self.page_indices['sequence.read']

        # Go to the structure.read_pdb page.
        elif self.page_method.selection == 'new pdb':
            return self.page_indices['structure.read_pdb']

        # Go to the structure.read_xyz page.
        elif self.page_method.selection == 'new xyz':
            return self.page_indices['structure.read_xyz']

        # Go to the spectrum.read_spins page.
        elif self.page_method.selection == 'new spectrum':
            return self.page_indices['spectrum.read_spins']

        # Skip to the structure.load_spins page.
        elif self.page_method.selection == 'preload':
            return self.page_indices['structure.load_spins']


    def wizard_page_after_sequence_read(self):
        """Set the page after the sequence.read user function page.

        @return:    The index of the last page.
        @rtype:     int
        """

        # Return the index of the terminal page.
        return  self.page_indices['fin']


    def wizard_page_after_structure_read(self):
        """Set the page after the structure.read_* user function pages.

        @return:    The index of the structure.load_spins page.
        @rtype:     int
        """

        # Return the index of the terminal page.
        return  self.page_indices['structure.load_spins']
Пример #16
0
class Uf_object(object):
    """The object for auto-generating the GUI user functions."""

    def __call__(self, event=None, wx_parent=None, wx_wizard_sync=None, wx_wizard_run=True, wx_wizard_modal=False, **kwds):
        """Make the GUI user function executable.

        All keyword args, apart from 'event', 'wx_parent' and 'wx_wizard_run' will be assumed to be user function arguments and the Uf_page.SetValue() method of the page will be used to set the GUI arg elements to the values supplied.


        @keyword event:             The wx event.
        @type event:                wx event or None
        @keyword wx_parent:         The parent wx object to associate the user function wizard to.
        @type wx_parent:            wx object
        @keyword wx_wizard_sync:    A flag which if given will switch between synchronous and asynchronous user function operation.
        @type wx_wizard_sync:       None or bool
        @keyword wx_wizard_run:     A flag which if True will call the wizard run() method.
        @type wx_wizard_run:        bool
        @keyword wx_wizard_modal:   A flag which if True will cause the wizard run() method to have the modal flag set so that the wizard is modal.
        @type wx_wizard_modal:      bool
        @return:                    The status of the call.  If the call failed, False will be returned.
        @rtype:                     bool
        """

        # Store the sync flag.
        if wx_wizard_sync != None:
            self._sync = wx_wizard_sync

        # Create a new wizard if needed (checking that the parent of an old wizard is not the same).
        if self.wizard == None or (wx_parent != None and wx_parent != self.wizard.GetParent()) or len(self.wizard._pages) == 0:
            status = self.create_wizard(wx_parent)
            if not status:
                return False

        # Otherwise reset the wizard.
        else:
            self.wizard.reset()

        # Update all of the user function argument choices (ComboBoxes) to be current, returning if a failure occurred.
        if not self.page.update_args():
            return False

        # Loop over the keyword args, using the Uf_page.SetValue() method to set the user function argument GUI element values.
        for key in kwds:
            self.page.SetValue(key, kwds[key])

        # Execute the wizard when asked.
        if wx_wizard_run:
            self.wizard.run(modal=wx_wizard_modal)


    def __init__(self, name, title=None, size=None, height_desc=None, apply_button=True, sync=False):
        """Set up the object.

        @param name:            The name of the user function.
        @type name:             str
        @keyword title:         The long title of the user function to set as the window title.
        @type title:            str
        @keyword size:          The window size.
        @type size:             tuple of int
        @keyword height_desc:   The height in pixels of the description part of the wizard.
        @type height_desc:      int or None
        @keyword apply_button:  A flag specifying if the apply button should be shown or not.  This defaults to True.
        @type apply_button:     bool
        @keyword sync:          A flag which if True will call user functions via interpreter.apply and if False via interpreter.queue.
        @type sync:             bool
        """

        # Store the args.
        self._name = name
        self._title = title
        self._size = size
        self._height_desc = height_desc
        self._apply_button = apply_button
        self._sync = sync

        # Initialise the wizard storage.
        self.wizard = None

        # Create a unique wx ID for the user function.
        self._uf_id = wx.NewId()


    def Destroy(self):
        """Cleanly destroy the user function GUI elements."""

        # First flush all events.
        wx.Yield()

        # Destroy the user function page.
        if hasattr(self, 'page'):
            # Loop over the user function arguments.
            for key in self.page.uf_args:
                # Destroy any selection windows.
                if hasattr(self.page.uf_args[key], 'sel_win'):
                    self.page.uf_args[key].sel_win.Destroy()

            # Delete the page object.
            del self.page

        # Destroy the wizard, if it exists.
        if self.wizard != None:
            self.wizard.Destroy()
            self.wizard = None


    def create_page(self, wizard=None, sync=None, execute=True):
        """Create the user function wizard page GUI object.

        @keyword wizard:    The parent wizard.
        @type wizard:       Wiz_window instance
        @keyword sync:      A flag which if True will call user functions via interpreter.apply and if False via interpreter.queue.
        @type sync:         None or bool
        @keyword execute:   A flag which if True will prevent the user function from being executed when clicking on 'Next', 'Ok', or 'Apply'.  This can be useful for delaying the execution of the user function.
        @type execute:      bool
        @return:            The user function page object.
        @rtype:             Uf_page instance
        """

        # Overwrite (a)synchronous operation.
        if sync != None:
            self._sync = sync

        # Initialise and return the page.
        return Uf_page(self._name, parent=wizard, height_desc=self._height_desc, sync=self._sync, execute=execute)


    def create_wizard(self, parent=None):
        """Create the user function wizard GUI object, with embedded wizard page.

        @keyword parent:    The parent wx window.
        @type parent:       wx.Window instance
        @return:            True if the wizard was created, False if a problem was encountered.
        @rtype:             bool
        """

        # The parent object defaults to the main relax window.
        if parent == None:
            app = wx.GetApp()
            parent = app.gui

        # Create the wizard dialog.
        self.wizard = Wiz_window(parent=parent, size_x=self._size[0], size_y=self._size[1], title="The %s user function"%self._name)

        # Create the page.
        self.page = self.create_page(self.wizard, sync=self._sync)

        # For an update of the argument data.
        if not self.page.update_args():
            return False

        # Add the page to the wizard.
        self.wizard.add_page(self.page, apply_button=self._apply_button)

        # Success.
        return True
Пример #17
0
class Relax_data_list(Base_list):
    """The GUI element for listing loaded relaxation data."""

    def action_relax_data_delete(self, event):
        """Launch the relax_data.delete user function.

        @param event:   The wx event.
        @type event:    wx event
        """

        # The current selection.
        item = self.element.GetFirstSelected()

        # No selection.
        if item == -1:
            id = None

        # Selected item.
        else:
            # The spectrum ID.
            id = gui_to_str(self.element.GetItemText(item))

        # Launch the dialog.
        uf_store['relax_data.delete'](ri_id=id)


    def action_relax_data_display(self, event):
        """Launch the relax_data.display user function.

        @param event:   The wx event.
        @type event:    wx event
        """

        # The current selection.
        item = self.element.GetFirstSelected()

        # The spectrum ID.
        id = gui_to_str(self.element.GetItemText(item))

        # Launch the dialog.
        uf_store['relax_data.display'](ri_id=id)


    def action_relax_data_peak_intensity_type(self, event):
        """Launch the relax_data.peak_intensity_type user function.

        @param event:   The wx event.
        @type event:    wx event
        """

        # The current selection.
        item = self.element.GetFirstSelected()

        # The spectrum ID.
        id = gui_to_str(self.element.GetItemText(item))

        # The current type.
        type = None
        if hasattr(cdp, 'exp_info') and hasattr(cdp.exp_info, 'peak_intensity_type') and id in cdp.exp_info.peak_intensity_type.keys():
            type = cdp.exp_info.peak_intensity_type[id]

        # Launch the dialog.
        if type == None:
            uf_store['relax_data.peak_intensity_type'](ri_id=id)
        else:
            uf_store['relax_data.peak_intensity_type'](ri_id=id, type=type)


    def action_relax_data_temp_calibration(self, event):
        """Launch the relax_data.temp_calibration user function.

        @param event:   The wx event.
        @type event:    wx event
        """

        # The current selection.
        item = self.element.GetFirstSelected()

        # The spectrum ID.
        id = gui_to_str(self.element.GetItemText(item))

        # The current method.
        method = None
        if hasattr(cdp, 'exp_info') and hasattr(cdp.exp_info, 'temp_calibration') and id in cdp.exp_info.temp_calibration.keys():
            method = cdp.exp_info.temp_calibration[id]

        # Launch the dialog.
        if method == None:
            uf_store['relax_data.temp_calibration'](ri_id=id)
        else:
            uf_store['relax_data.temp_calibration'](ri_id=id, method=method)


    def action_relax_data_temp_control(self, event):
        """Launch the relax_data.temp_control user function.

        @param event:   The wx event.
        @type event:    wx event
        """

        # The current selection.
        item = self.element.GetFirstSelected()

        # The spectrum ID.
        id = gui_to_str(self.element.GetItemText(item))

        # The current method.
        method = None
        if hasattr(cdp, 'exp_info') and hasattr(cdp.exp_info, 'temp_control') and id in cdp.exp_info.temp_control.keys():
            method = cdp.exp_info.temp_control[id]

        # Launch the dialog.
        if method == None:
            uf_store['relax_data.temp_control'](ri_id=id)
        else:
            uf_store['relax_data.temp_control'](ri_id=id, method=method)


    def action_relax_data_type(self, event):
        """Launch the relax_data.type user function.

        @param event:   The wx event.
        @type event:    wx event
        """

        # The current selection.
        item = self.element.GetFirstSelected()

        # The spectrum ID.
        id = gui_to_str(self.element.GetItemText(item))

        # The current type.
        type = None
        if hasattr(cdp, 'ri_type') and id in cdp.ri_type.keys():
            type = cdp.ri_type[id]

        # Launch the dialog.
        if type == None:
            uf_store['relax_data.type'](ri_id=id)
        else:
            uf_store['relax_data.type'](ri_id=id, ri_type=type)


    def action_spectrometer_frequency(self, event):
        """Launch the spectrometer.frequency user function.

        @param event:   The wx event.
        @type event:    wx event
        """

        # The current selection.
        item = self.element.GetFirstSelected()

        # The spectrum ID.
        id = gui_to_str(self.element.GetItemText(item))

        # The current frequency.
        frq = None
        if hasattr(cdp, 'spectrometer_frq') and id in cdp.spectrometer_frq.keys():
            frq = cdp.spectrometer_frq[id]

        # Launch the dialog.
        if frq == None:
            uf_store['spectrometer.frequency'](id=id)
        else:
            uf_store['spectrometer.frequency'](id=id, frq=frq)


    def setup(self):
        """Override the base variables."""

        # GUI variables.
        self.title = "Relaxation data list"
        self.observer_base_name = "relaxation data list"

        # The column titles.
        self.columns = [
            "Relaxation data ID",
            "Data type",
            "Frequency (Hz)"
        ]

        # Button set up.
        self.button_placement = 'top'
        self.button_size = (170, 40)
        self.button_info = [
            {
                'object': 'button_add',
                'label': ' Add',
                'icon': fetch_icon('oxygen.actions.list-add-relax-blue', "22x22"),
                'method': self.wizard_relax_data,
                'tooltip': "Read relaxation data from a file."
            }, {
                'object': 'button_bruker',
                'label': ' Add',
                'icon': fetch_icon('relax.bruker_add', "22x22"),
                'method': self.wizard_bruker,
                'tooltip': "Read a Bruker Dynamics Center relaxation data file."
            }, {
                'object': 'button_delete',
                'label': ' Delete',
                'icon': fetch_icon('oxygen.actions.list-remove', "22x22"),
                'method': self.action_relax_data_delete,
                'tooltip': "Delete loaded relaxation data from the relax data store."
            }, {
                'object': 'button_metadata',
                'label': ' View metadata',
                'icon': fetch_icon('oxygen.mimetypes.text-x-texinfo', "22x22"),
                'method': self.view_metadata,
                'tooltip': "View and edit the relaxation data metadata."
            }
        ]

        # The right click popup menu.
        self.popup_menus = [
            {
                'id': wx.NewId(),
                'text': "&Delete the relaxation data",
                'icon': fetch_icon(uf_info.get_uf('relax_data.delete').gui_icon),
                'method': self.action_relax_data_delete
            }, {
                'id': wx.NewId(),
                'text': "Dis&play the relaxation data",
                'icon': fetch_icon(uf_info.get_uf('relax_data.display').gui_icon),
                'method': self.action_relax_data_display
            }, {
                'id': wx.NewId(),
                'text': "Set the relaxation data &frequency",
                'icon': fetch_icon(uf_info.get_uf('spectrometer.frequency').gui_icon),
                'method': self.action_spectrometer_frequency
            }, {
                'id': wx.NewId(),
                'text': "Set the peak &intensity type",
                'icon': fetch_icon(uf_info.get_uf('relax_data.peak_intensity_type').gui_icon),
                'method': self.action_relax_data_peak_intensity_type
            }, {
                'id': wx.NewId(),
                'text': "Set the temperature &calibration",
                'icon': fetch_icon(uf_info.get_uf('relax_data.temp_calibration').gui_icon),
                'method': self.action_relax_data_temp_calibration
            }, {
                'id': wx.NewId(),
                'text': "Set the temperature c&ontrol",
                'icon': fetch_icon(uf_info.get_uf('relax_data.temp_control').gui_icon),
                'method': self.action_relax_data_temp_control
            }, {
                'id': wx.NewId(),
                'text': "Set the relaxation data &type",
                'icon': fetch_icon(uf_info.get_uf('relax_data.type').gui_icon),
                'method': self.action_relax_data_type
            }
        ]


    def update_data(self):
        """Method called from self.build_element_safe() to update the list data."""

        # Translation table for the Rx data types.
        table = {
            "NOE": "Steady-state NOE",
            "R1": "%s longitudinal relaxation" % r1,
            "R2": "%s transverse relaxation" % r2
        }

        # Expand the number of rows to match the number of relaxation IDs, and add the IDs.
        n = 0
        if hasattr(cdp, 'ri_ids'):
            # The number of IDs.
            n = len(cdp.ri_ids)

            # Add all the data.
            for i in range(n):
                # Set the IDs.
                id = cdp.ri_ids[i]
                self.element.InsertStringItem(i, str_to_gui(id))

                # Set the data types.
                self.element.SetStringItem(i, 1, str_to_gui(table[cdp.ri_type[id]]))

                # Set the frequencies.
                self.element.SetStringItem(i, 2, float_to_gui(cdp.spectrometer_frq[id]))


    def view_metadata(self, event=None):
        """Launch the metadata window.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Launch.
        Metadata_window(self.gui)


    def wizard_bruker(self, event):
        """Launch the Bruker Dynamics Centre data reading wizard.

        @param event:   The wx event.
        @type event:    wx event
        """

        # The wizard.
        self.wizard_exec(bruker=True)


    def wizard_exec(self, bruker=False):
        """Launch the Rx peak loading wizard.

        @keyword bruker:    A flag which if True will launch the Bruker Dynamics Centre data reading wizard and if False will launch the relaxation data reading wizard
        @type bruker:       bool
        """

        # Change the cursor to busy.
        wx.BeginBusyCursor()

        # The title.
        if bruker:
            title = "The Bruker Dynamics Centre data reading wizard"
        else:
            title = "The relaxation data reading wizard"

        # Initialise a wizard.
        self.wizard = Wiz_window(parent=self.gui, size_x=1000, size_y=800, title=title)
        self.page_indices = {}

        # The reading page.
        if bruker:
            page = uf_store['bruker.read'].create_page(self.wizard, sync=True)
        else:
            page = uf_store['relax_data.read'].create_page(self.wizard, sync=True)
        self.page_indices['read'] = self.wizard.add_page(page, skip_button=True, proceed_on_error=False)

        # The peak intensity type page.
        page = uf_store['relax_data.peak_intensity_type'].create_page(self.wizard, sync=True)
        self.page_indices['peak_intensity_type'] = self.wizard.add_page(page, apply_button=True, skip_button=True)
        page.on_display_post = self.wizard_update_int_type

        # The temperature calibration page.
        page = uf_store['relax_data.temp_calibration'].create_page(self.wizard, sync=True)
        self.page_indices['temp_calibration'] = self.wizard.add_page(page, apply_button=True, skip_button=True)
        page.on_display_post = self.wizard_update_temp_calibration

        # The temperature control page.
        page = uf_store['relax_data.temp_control'].create_page(self.wizard, sync=True)
        self.page_indices['temp_control'] = self.wizard.add_page(page, apply_button=True)
        page.on_display_post = self.wizard_update_temp_control

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()

        # Run the wizard.
        self.wizard.run()


    def wizard_relax_data(self, event):
        """Launch the relaxation data reading wizard.

        @param event:   The wx event.
        @type event:    wx event
        """

        # The wizard.
        self.wizard_exec(bruker=False)


    def wizard_update_int_type(self):
        """Update the relax_data.peak_intensity_type page based on previous data."""

        # The relax_data.peak_intensity_type page.
        page = self.wizard.get_page(self.page_indices['read'])

        # Get the Rx ID.
        id = page.uf_args['ri_id'].GetValue()

        # Set the ID in the relax_data.peak_intensity_type page.
        page = self.wizard.get_page(self.page_indices['peak_intensity_type'])
        page.uf_args['ri_id'].SetValue(value=id)


    def wizard_update_temp_calibration(self):
        """Update the relax_data.temp_calibration page based on previous data."""

        # The relax_data.temp_calibration page.
        page = self.wizard.get_page(self.page_indices['read'])

        # Get the Rx ID.
        id = page.uf_args['ri_id'].GetValue()

        # Set the ID in the relax_data.temp_calibration page.
        page = self.wizard.get_page(self.page_indices['temp_calibration'])
        page.uf_args['ri_id'].SetValue(value=id)


    def wizard_update_temp_control(self):
        """Update the relax_data.temp_control page based on previous data."""

        # The relax_data.temp_control page.
        page = self.wizard.get_page(self.page_indices['read'])

        # Get the Rx ID.
        id = page.uf_args['ri_id'].GetValue()

        # Set the ID in the relax_data.temp_control page.
        page = self.wizard.get_page(self.page_indices['temp_control'])
        page.uf_args['ri_id'].SetValue(value=id)
Пример #18
0
class Auto_model_free(Base_analysis):
    """The model-free auto-analysis GUI element."""
    def __init__(self,
                 parent,
                 id=-1,
                 pos=wx.Point(-1, -1),
                 size=wx.Size(-1, -1),
                 style=524288,
                 name='scrolledpanel',
                 gui=None,
                 analysis_name=None,
                 pipe_name=None,
                 pipe_bundle=None,
                 uf_exec=[],
                 data_index=None):
        """Build the automatic model-free protocol GUI element.

        @param parent:          The parent wx element.
        @type parent:           wx object
        @keyword id:            The unique ID number.
        @type id:               int
        @keyword pos:           The position.
        @type pos:              wx.Size object
        @keyword size:          The size.
        @type size:             wx.Size object
        @keyword style:         The style.
        @type style:            int
        @keyword name:          The name for the panel.
        @type name:             unicode
        @keyword gui:           The main GUI class.
        @type gui:              gui.relax_gui.Main instance
        @keyword analysis_name: The name of the analysis (the name in the tab part of the notebook).
        @type analysis_name:    str
        @keyword pipe_name:     The name of the original data pipe for this analysis.
        @type pipe_name:        str
        @keyword pipe_bundle:   The name of the data pipe bundle associated with this analysis.
        @type pipe_bundle:      str
        @keyword uf_exec:       The list of user function on_execute methods returned from the new analysis wizard.
        @type uf_exec:          list of methods
        @keyword data_index:    The index of the analysis in the relax data store (set to None if no data currently exists).
        @type data_index:       None or int
        """

        # Store the GUI main class.
        self.gui = gui

        # Init.
        self.init_flag = True

        # New data container.
        if data_index == None:
            # First create the data pipe if not already in existence.
            if not has_pipe(pipe_name):
                self.gui.interpreter.apply('pipe.create',
                                           pipe_name=pipe_name,
                                           pipe_type='mf',
                                           bundle=pipe_bundle)

            # Create the data pipe bundle if needed.
            if not has_bundle(pipe_bundle):
                self.gui.interpreter.apply('pipe.bundle',
                                           bundle=pipe_bundle,
                                           pipe=pipe_name)

            # Generate a storage container in the relax data store, and alias it for easy access.
            data_index = ds.relax_gui.analyses.add('model-free')

            # Store the analysis and pipe names.
            ds.relax_gui.analyses[data_index].analysis_name = analysis_name
            ds.relax_gui.analyses[data_index].pipe_name = pipe_name
            ds.relax_gui.analyses[data_index].pipe_bundle = pipe_bundle

            # Initialise the variables.
            ds.relax_gui.analyses[data_index].grid_inc = None
            ds.relax_gui.analyses[data_index].diff_tensor_grid_inc = {
                'sphere': 11,
                'prolate': 11,
                'oblate': 11,
                'ellipsoid': 6
            }
            ds.relax_gui.analyses[data_index].mc_sim_num = None
            ds.relax_gui.analyses[
                data_index].save_dir = self.gui.system_cwd_path
            ds.relax_gui.analyses[data_index].local_tm_models = [
                'tm0', 'tm1', 'tm2', 'tm3', 'tm4', 'tm5', 'tm6', 'tm7', 'tm8',
                'tm9'
            ]
            ds.relax_gui.analyses[data_index].mf_models = [
                'm0', 'm1', 'm2', 'm3', 'm4', 'm5', 'm6', 'm7', 'm8', 'm9'
            ]
            ds.relax_gui.analyses[data_index].max_iter = 30

        # Error checking.
        if ds.relax_gui.analyses[data_index].pipe_bundle == None:
            raise RelaxError("The pipe bundle must be supplied.")

        # Alias the data.
        self.data = ds.relax_gui.analyses[data_index]
        self.data_index = data_index

        # Backward compatibility.
        if not hasattr(self.data, 'local_tm_models'):
            self.data.local_tm_models = [
                'tm0', 'tm1', 'tm2', 'tm3', 'tm4', 'tm5', 'tm6', 'tm7', 'tm8',
                'tm9'
            ]
        if not hasattr(self.data, 'mf_models'):
            self.data.mf_models = [
                'm0', 'm1', 'm2', 'm3', 'm4', 'm5', 'm6', 'm7', 'm8', 'm9'
            ]

        # Initialise the mode selection window.
        self.mode_win = Protocol_mode_sel_window()

        # Register the method for updating the spin count for the completion of user functions.
        self.observer_register()

        # Execute the base class method to build the panel.
        super(Auto_model_free, self).__init__(parent,
                                              id=id,
                                              pos=pos,
                                              size=size,
                                              style=style,
                                              name=name)

    def _about(self, event=None):
        """The about window.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Initialise the dialog.
        self.about_dialog = About_window(self)

        # Show the dialog.
        if status.show_gui:
            self.about_dialog.Show()

    def activate(self):
        """Activate or deactivate certain elements of the analysis in response to the execution lock."""

        # Flag for enabling or disabling the elements.
        enable = False
        if not status.exec_lock.locked():
            enable = True

        # Activate or deactivate the elements.
        wx.CallAfter(self.field_results_dir.Enable, enable)
        wx.CallAfter(self.spin_systems.Enable, enable)
        wx.CallAfter(self.relax_data.Enable, enable)
        wx.CallAfter(self.button_dipole_pair.Enable, enable)
        wx.CallAfter(self.button_csa.Enable, enable)
        wx.CallAfter(self.button_isotope_heteronuc.Enable, enable)
        wx.CallAfter(self.button_isotope_proton.Enable, enable)
        wx.CallAfter(self.local_tm_model_field.Enable, enable)
        wx.CallAfter(self.mf_model_field.Enable, enable)
        wx.CallAfter(self.grid_inc.Enable, enable)
        wx.CallAfter(self.mc_sim_num.Enable, enable)
        wx.CallAfter(self.max_iter.Enable, enable)
        wx.CallAfter(self.mode.Enable, enable)
        wx.CallAfter(self.button_exec_relax.Enable, enable)

    def add_values(self, box):
        """Create and add the value.set buttons for the model-free analysis.

        @param box:     The box element to pack the GUI element into.
        @type box:      wx.BoxSizer instance
        """

        # Sizer.
        sizer = wx.BoxSizer(wx.HORIZONTAL)

        # Dipole-dipole relaxation setup button.
        self.button_dipole_pair = wx.lib.buttons.ThemedGenBitmapTextButton(
            self, -1, None, " Dipolar relaxation")
        self.button_dipole_pair.SetBitmapLabel(
            wx.Bitmap(fetch_icon("relax.dipole_pair", "22x22"),
                      wx.BITMAP_TYPE_ANY))
        self.button_dipole_pair.SetFont(font.normal)
        self.button_dipole_pair.SetSize((-1, 25))
        self.button_dipole_pair.SetToolTip(
            wx.ToolTip(
                "Define the magnetic dipole-dipole relaxation mechanism."))
        self.gui.Bind(wx.EVT_BUTTON, self.setup_dipole_pair,
                      self.button_dipole_pair)
        sizer.Add(self.button_dipole_pair, 1, wx.ALL | wx.EXPAND, 0)

        # CSA button.
        self.button_csa = wx.lib.buttons.ThemedGenBitmapTextButton(
            self, -1, None, " CSA relaxation")
        self.button_csa.SetBitmapLabel(
            wx.Bitmap(fetch_icon("relax.align_tensor", "22x22"),
                      wx.BITMAP_TYPE_ANY))
        self.button_csa.SetFont(font.normal)
        self.button_csa.SetSize((-1, 25))
        self.button_csa.SetToolTip(
            wx.ToolTip(
                "Define the Chemical Shift Anisotropy (CSA) relaxation mechanism via the value.set user function."
            ))
        self.gui.Bind(wx.EVT_BUTTON, self.value_set_csa, self.button_csa)
        sizer.Add(self.button_csa, 1, wx.ALL | wx.EXPAND, 0)

        # Isotope type button (heteronucleus).
        self.button_isotope_heteronuc = wx.lib.buttons.ThemedGenBitmapTextButton(
            self, -1, None, " X isotope")
        self.button_isotope_heteronuc.SetBitmapLabel(
            wx.Bitmap(fetch_icon("relax.nuclear_symbol", "22x22"),
                      wx.BITMAP_TYPE_ANY))
        self.button_isotope_heteronuc.SetFont(font.normal)
        self.button_isotope_heteronuc.SetSize((-1, 25))
        self.button_isotope_heteronuc.SetToolTip(
            wx.ToolTip(
                "Set the nuclear isotope types of the heteronuclear spins via the spin.isotope user function."
            ))
        self.gui.Bind(wx.EVT_BUTTON, self.spin_isotope_heteronuc,
                      self.button_isotope_heteronuc)
        sizer.Add(self.button_isotope_heteronuc, 1, wx.ALL | wx.EXPAND, 0)

        # Isotope type button (proton).
        self.button_isotope_proton = wx.lib.buttons.ThemedGenBitmapTextButton(
            self, -1, None, " H isotope")
        self.button_isotope_proton.SetBitmapLabel(
            wx.Bitmap(fetch_icon("relax.nuclear_symbol", "22x22"),
                      wx.BITMAP_TYPE_ANY))
        self.button_isotope_proton.SetFont(font.normal)
        self.button_isotope_proton.SetSize((-1, 25))
        self.button_isotope_proton.SetToolTip(
            wx.ToolTip(
                "Set the nuclear isotope types of the proton spins via the spin.isotope user function."
            ))
        self.gui.Bind(wx.EVT_BUTTON, self.spin_isotope_proton,
                      self.button_isotope_proton)
        sizer.Add(self.button_isotope_proton, 1, wx.ALL | wx.EXPAND, 0)

        # Add the element to the box.
        box.Add(sizer, 0, wx.ALL | wx.EXPAND, 0)

    def assemble_data(self):
        """Assemble the data required for the auto-analysis.

        See the docstring for auto_analyses.dauvernge_protocol for details.  All data is taken from the relax data store, so data upload from the GUI to there must have been previously performed.

        @return:    A container with all the data required for the auto-analysis.
        @rtype:     class instance, list of str
        """

        # The data container.
        data = Container()
        missing = []

        # The pipe name and bundle.
        data.pipe_name = self.data.pipe_name
        data.pipe_bundle = self.data.pipe_bundle

        # The model-free models (do not change these unless absolutely necessary).
        data.local_tm_models = self.local_tm_model_field.GetValue()
        data.mf_models = self.mf_model_field.GetValue()

        # Automatic looping over all rounds until convergence (must be a boolean value of True or False).
        data.conv_loop = True

        # Increment size.
        data.inc = gui_to_int(self.grid_inc.GetValue())
        if hasattr(self.data, 'diff_tensor_grid_inc'):
            data.diff_tensor_grid_inc = self.data.diff_tensor_grid_inc
        else:
            data.diff_tensor_grid_inc = {
                'sphere': 11,
                'prolate': 11,
                'oblate': 11,
                'ellipsoid': 6
            }

        # The number of Monte Carlo simulations to be used for error analysis at the end of the analysis.
        data.mc_sim_num = gui_to_int(self.mc_sim_num.GetValue())

        # Number of maximum iterations.
        data.max_iter = self.data.max_iter

        # Results directory.
        data.save_dir = self.data.save_dir

        # Check if sequence data is loaded
        if not exists_mol_res_spin_data():
            missing.append("Sequence data")

        # Relaxation data.
        if not hasattr(cdp, 'ri_ids') or len(cdp.ri_ids) == 0:
            missing.append("Relaxation data")

        # Insufficient data.
        if hasattr(cdp, 'ri_ids') and len(cdp.ri_ids) <= 3:
            missing.append(
                "Insufficient relaxation data, 4 or more data sets are essential for the execution of the dauvergne_protocol auto-analysis. Check that you have entered data for a least two spectrometer fields."
            )

        # Interatomic data containers.
        if not hasattr(cdp, 'interatomic') or len(cdp.interatomic) == 0:
            missing.append(
                "Interatomic data (for the dipole-dipole interaction)")

        # Get the mode.
        mode = gui_to_str(self.mode.GetValue())

        # Solve for all global models.
        if mode == 'Fully automated':
            # The global model list.
            data.global_models = [
                'local_tm', 'sphere', 'prolate', 'oblate', 'ellipsoid', 'final'
            ]

        # Any global model selected.
        else:
            data.global_models = [mode]

        # Check for vectors.
        vector_check = False
        if 'prolate' in data.global_models or 'oblate' in data.global_models or 'ellipsoid' in data.global_models:
            vector_check = True

        # Spin variables.
        for spin, spin_id in spin_loop(return_id=True):
            # Skip deselected spins.
            if not spin.select:
                continue

            # The message skeleton.
            msg = "Spin '%s' - %s (try the %s user function)." % (spin_id,
                                                                  "%s", "%s")

            # Test if the nuclear isotope type has been set.
            if not hasattr(spin, 'isotope') or spin.isotope == None:
                missing.append(msg % ("nuclear isotope data", "spin.isotope"))

            # Test if the CSA value has been set for the heteronuclei.
            if (hasattr(spin, 'isotope') and spin.isotope
                    in ['15N', '13C']) and (not hasattr(spin, 'csa')
                                            or spin.csa == None):
                missing.append(msg % ("CSA data", "value.set"))

        # Interatomic data container variables.
        for interatom in interatomic_loop():
            # Get the spin containers.
            spin1 = return_spin(spin_hash=interatom._spin_hash1)
            spin2 = return_spin(spin_hash=interatom._spin_hash2)

            # Skip deselected spins.
            if not spin1.select:
                continue
            if not spin2.select:
                continue

            # The message skeleton.
            msg = "Spin pair '%s' and '%s' - %s (try the %s user function)." % (
                interatom.spin_id1, interatom.spin_id2, "%s", "%s")

            # Test if the interatomic distance has been set.
            if not hasattr(interatom, 'r') or interatom.r == None:
                missing.append(msg % ("bond length data", "value.set"))

            # Test if the unit vectors have been loaded.
            if vector_check and (not hasattr(interatom, 'vector')
                                 or interatom.vector is None):
                missing.append(msg %
                               ("unit vectors", "interatom.unit_vectors"))

        # Return the container and list of missing data.
        return data, missing

    def build_left_box(self):
        """Construct the left hand box to pack into the main model-free box.

        @return:    The left hand box element containing the bitmap and about button to pack into the main model-free box.
        @rtype:     wx.BoxSizer instance
        """

        # Build the left hand box.
        left_box = wx.BoxSizer(wx.VERTICAL)

        # The images.
        bitmaps = [
            ANALYSIS_IMAGE_PATH + "model_free" + sep +
            "model_free_200x200.png", IMAGE_PATH + 'modelfree.png'
        ]

        # Add the model-free bitmap picture.
        for i in range(len(bitmaps)):
            # The bitmap.
            bitmap = wx.StaticBitmap(self, -1, bitmap_setup(bitmaps[i]))

            # Add it.
            left_box.Add(bitmap, 0, wx.ALL, 0)

        # A spacer.
        left_box.AddStretchSpacer()

        # A button sizer, with some initial spacing.
        button_sizer = wx.BoxSizer(wx.HORIZONTAL)

        # An about button.
        button = wx.lib.buttons.ThemedGenBitmapTextButton(
            self, -1, None, "About")
        button.SetBitmapLabel(
            wx.Bitmap(fetch_icon('oxygen.actions.help-about', "22x22"),
                      wx.BITMAP_TYPE_ANY))
        button.SetFont(font.normal)
        button.SetToolTip(
            wx.ToolTip("Information about this automatic analysis"))

        # Bind the click.
        self.Bind(wx.EVT_BUTTON, self._about, button)

        # A cursor for the button.
        if dep_check.wx_classic:
            cursor = wx.StockCursor(wx.CURSOR_QUESTION_ARROW)
        else:
            cursor = wx.Cursor(wx.CURSOR_QUESTION_ARROW)
        button.SetCursor(cursor)

        # Pack the button.
        button_sizer.Add(button, 0, 0, 0)
        left_box.Add(button_sizer, 0, wx.ALL, 0)

        # Return the packed box.
        return left_box

    def build_right_box(self):
        """Construct the right hand box to pack into the main model-free box.

        @return:    The right hand box element containing all model-free GUI elements (excluding the bitmap) to pack into the main model-free box.
        @rtype:     wx.BoxSizer instance
        """

        # Use a vertical packing of elements.
        box = wx.BoxSizer(wx.VERTICAL)

        # Add the frame title.
        self.add_title(box, "Model-free analysis")

        # Display the data pipe.
        Text_ctrl(
            box,
            self,
            text="The data pipe bundle:",
            default=self.data.pipe_bundle,
            tooltip=
            "This is the data pipe bundle associated with this analysis.",
            editable=False,
            width_text=self.width_text,
            width_button=self.width_button,
            spacer=self.spacer_horizontal)

        # Add the results directory GUI element.
        self.field_results_dir = Text_ctrl(
            box,
            self,
            text="Results directory:",
            icon=fetch_icon('oxygen.actions.document-open-folder', "16x16"),
            default=self.data.save_dir,
            tooltip=
            "The directory in which all automatically created files will be saved.",
            tooltip_button="Select the results directory.",
            fn=self.results_directory,
            button=True,
            width_text=self.width_text,
            width_button=self.width_button,
            spacer=self.spacer_horizontal)

        # Add the spin GUI element.
        self.add_spin_systems(box, self)

        # Add the relaxation data list GUI element, with spacing.
        box.AddSpacer(10)
        self.relax_data = Relax_data_list(gui=self.gui,
                                          parent=self,
                                          box=box,
                                          id=str(self.data_index))
        box.AddSpacer(10)

        # Add the value.set buttons.
        self.add_values(box)
        box.AddSpacer(10)

        # Add the local tau_m models GUI element, with spacing.
        self.local_tm_model_field = Local_tm_list(self, box)
        self.local_tm_model_field.set_value(self.data.local_tm_models)

        # Add the model-free models GUI element, with spacing.
        self.mf_model_field = Mf_list(self, box)
        self.mf_model_field.set_value(self.data.mf_models)

        # The optimisation settings.
        self.grid_inc = Spin_ctrl(
            box,
            self,
            text="Grid search increments:",
            default=11,
            min=1,
            max=100,
            tooltip=
            "This is the number of increments per dimension of the grid search performed prior to numerical optimisation.",
            width_text=self.width_text,
            width_button=self.width_button,
            spacer=self.spacer_horizontal)
        self.mc_sim_num = Spin_ctrl(
            box,
            self,
            text="Monte Carlo simulation number:",
            default=500,
            min=1,
            max=100000,
            tooltip=
            "This is the number of Monte Carlo simulations performed for error propagation and analysis.",
            width_text=self.width_text,
            width_button=self.width_button,
            spacer=self.spacer_horizontal)

        # Add maximum iteration selector.
        self.max_iter = Spin_ctrl(
            box,
            self,
            text="Maximum iterations:",
            default=self.data.max_iter,
            tooltip=
            "The maximum number of iterations for the protocol.  This is the limit for the global looping over the optimisation of the model-free models, model elimination, model selection and then optimisation of the diffusion tensor.",
            min=25,
            max=100,
            width_text=self.width_text,
            width_button=self.width_button,
            spacer=self.spacer_horizontal)

        # The calculation mode.
        self.mode = Text_ctrl(
            box,
            self,
            text="Protocol mode:",
            default='Fully automated',
            tooltip=
            "Select if the dauvergne_protocol analysis will be fully automated or whether the individual global models will be optimised separately.",
            tooltip_button="Open the protocol mode selection window.",
            icon=fetch_icon('oxygen.actions.system-run', "16x16"),
            fn=self.mode_dialog,
            editable=False,
            button=True,
            width_text=self.width_text,
            width_button=self.width_button,
            spacer=self.spacer_horizontal)

        # Stretchable spacing (with a minimal space).
        box.AddSpacer(30)
        box.AddStretchSpacer()

        # Add the execution GUI element.
        self.button_exec_relax = self.add_execute_analysis(box, self.execute)

        # Return the box.
        return box

    def delete(self):
        """Unregister the spin count from the user functions."""

        # Unregister the observer methods.
        self.observer_register(remove=True)

        # Clean up the relaxation data list object.
        self.relax_data.delete()

        # Destroy the dipole-dipole interaction wizard.
        if hasattr(self, 'dipole_wizard'):
            self.dipole_wizard.Destroy()
            del self.dipole_wizard

        # Destroy the mode selection window.
        self.mode_win.Destroy()
        del self.mode_win

        # Destroy the model list windows.
        self.local_tm_model_field.model_win.Destroy()
        del self.local_tm_model_field
        self.mf_model_field.model_win.Destroy()
        del self.mf_model_field

        # Destroy the missing data dialog, if present.
        if hasattr(self, 'missing_data'):
            self.missing_data.Destroy()
            del self.missing_data

    def execute(self, event=None):
        """Set up, execute, and process the automatic model-free protocol.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Flush the GUI interpreter internal queue to make sure all user functions are complete.
        self.gui.interpreter.flush()

        # relax execution lock.
        if status.exec_lock.locked():
            error_message("relax is currently executing.",
                          "relax execution lock")
            event.Skip()
            return

        # User warning to close windows.
        self.gui.close_windows()

        # Synchronise the frame data to the relax data store.
        self.sync_ds(upload=True)

        # Assemble all the data needed for the auto-analysis.
        data, missing = self.assemble_data()

        # Missing data.
        if len(missing):
            self.missing_data = Missing_data(missing)
            return

        # Display the relax controller, and go to the end of the log window.
        self.gui.show_controller(None)
        self.gui.controller.log_panel.on_goto_end(None)

        # Start the thread.
        self.thread = Execute_mf(self.gui, data, self.data_index)
        self.thread.start()

        # Terminate the event.
        event.Skip()

    def mode_dialog(self, event=None):
        """The calculation mode selection.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Show the model selector window.
        if status.show_gui:
            self.mode_win.ShowModal()

        # Set the model.
        self.mode.SetValue(str_to_gui(self.mode_win.select))

    def observer_register(self, remove=False):
        """Register and unregister methods with the observer objects.

        @keyword remove:    If set to True, then the methods will be unregistered.
        @type remove:       False
        """

        # Register.
        if not remove:
            status.observers.gui_uf.register(self.data.pipe_bundle,
                                             self.update_spin_count,
                                             method_name='update_spin_count')
            status.observers.exec_lock.register(self.data.pipe_bundle,
                                                self.activate,
                                                method_name='activate')

        # Unregister.
        else:
            # The model-free methods.
            status.observers.gui_uf.unregister(self.data.pipe_bundle)
            status.observers.exec_lock.unregister(self.data.pipe_bundle)

            # The embedded objects methods.
            self.relax_data.observer_register(remove=True)

    def results_directory(self, event=None):
        """The results directory selection.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # The dialog.
        dialog = RelaxDirDialog(parent=self,
                                message='Select the results directory',
                                defaultPath=self.field_results_dir.GetValue())

        # Show the dialog and catch if no file has been selected.
        if status.show_gui and dialog.ShowModal() != wx.ID_OK:
            # Don't do anything.
            return

        # The path (don't do anything if not set).
        path = gui_to_str(dialog.get_path())
        if not path:
            return

        # Store the path.
        self.data.save_dir = path

        # Place the path in the text box.
        self.field_results_dir.SetValue(str_to_gui(path))

    def setup_dipole_pair(self, event=None):
        """Create the wizard for the dipole-dipole interaction.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Change the cursor to busy.
        wx.BeginBusyCursor()

        # Destroy the dipole-dipole interaction wizard, if it exists.
        if hasattr(self, 'dipole_wizard'):
            self.dipole_wizard.Destroy()

        # Create the wizard.
        self.dipole_wizard = Wiz_window(
            parent=self.gui,
            size_x=1000,
            size_y=750,
            title="Dipole-dipole interaction setup")

        # Structural data.
        if not hasattr(cdp, 'structure'):
            # Create the PDB reading page.
            page = uf_store['structure.read_pdb'].create_page(
                self.dipole_wizard, sync=True)
            self.dipole_wizard.add_page(page, skip_button=True)

            # Create the position reading page.
            page = uf_store['structure.get_pos'].create_page(
                self.dipole_wizard, sync=True)
            self.dipole_wizard.add_page(page, skip_button=True)

        # Create the interatom.define page.
        page = uf_store['interatom.define'].create_page(self.dipole_wizard,
                                                        sync=True)
        page.SetValue('spin_id1', '@N')
        page.SetValue('spin_id2', '@H')
        self.dipole_wizard.add_page(page)

        # Create the interatom.set_dist page.
        page = uf_store['interatom.set_dist'].create_page(self.dipole_wizard,
                                                          sync=True)
        page.SetValue('spin_id1', '@N*')
        page.SetValue('spin_id2', '@H*')
        page.SetValue('ave_dist', NH_BOND_LENGTH)
        self.dipole_wizard.add_page(page)

        # Create the interatom.unit_vectors page.
        page = uf_store['interatom.unit_vectors'].create_page(
            self.dipole_wizard, sync=True)
        self.dipole_wizard.add_page(page)

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()

        # Execute the wizard.
        self.dipole_wizard.run()

    def spin_isotope_heteronuc(self, event=None):
        """Set the nuclear isotope types of the heteronuclear spins via the spin.isotope user function.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Call the user function.
        uf_store['spin.isotope'](isotope='15N', spin_id='@N*')

    def spin_isotope_proton(self, event=None):
        """Set the nuclear isotope types of the proton spins via the spin.isotope user function.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Call the user function.
        uf_store['spin.isotope'](isotope='1H', spin_id='@H*')

    def sync_ds(self, upload=False):
        """Synchronise the analysis frame and the relax data store, both ways.

        This method allows the frame information to be uploaded into the relax data store, or for the information in the relax data store to be downloaded by the frame.

        @keyword upload:    A flag which if True will cause the frame to send data to the relax data store.  If False, data will be downloaded from the relax data store to update the frame.
        @type upload:       bool
        """

        # The local tau_m models to use.
        if upload:
            self.data.local_tm_models = self.local_tm_model_field.GetValue()
        else:
            self.local_tm_model_field.set_value(self.data.local_tm_models)

        # The model-free models to use.
        if upload:
            self.data.mf_models = self.mf_model_field.GetValue()
        else:
            self.mf_model_field.set_value(self.data.mf_models)

        # The grid incs.
        if upload:
            self.data.grid_inc = gui_to_int(self.grid_inc.GetValue())
        elif hasattr(self.data, 'grid_inc'):
            self.grid_inc.SetValue(int(self.data.grid_inc))

        # The MC sim number.
        if upload:
            self.data.mc_sim_num = gui_to_int(self.mc_sim_num.GetValue())
        elif hasattr(self.data, 'mc_sim_num'):
            self.mc_sim_num.SetValue(int(self.data.mc_sim_num))

        # The results directory.
        if upload:
            self.data.save_dir = str(self.field_results_dir.GetValue())
        else:
            self.field_results_dir.SetValue(str_to_gui(self.data.save_dir))

        # Maximum iterations.
        if upload:
            self.data.max_iter = gui_to_int(self.max_iter.GetValue())
        else:
            self.max_iter.SetValue(int(self.data.max_iter))

    def value_set_csa(self, event=None):
        """Set the CSA via the value.set uf.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Get the default value.
        api = return_api()
        val = api.default_value('csa')

        # Call the user function.
        uf_store['value.set'](val=val, param='csa', spin_id='@N*')
Пример #19
0
    def __init__(self,
                 parent=None,
                 size_x=1000,
                 size_y=750,
                 title="Peak intensity loading wizard",
                 noe=False,
                 relax_fit=False,
                 relax_disp=False):
        """Set up the peak intensity loading wizard.

        @keyword parent:            The parent window.
        @type parent:               wx.Window instance
        @keyword size_x:            The width of the wizard.
        @type size_x:               int
        @keyword size_y:            The height of the wizard.
        @type size_y:               int
        @keyword title:             The title of the wizard dialog.
        @type title:                str
        @keyword noe:               A flag which when True will enable the steady-state NOE portions of the wizard.
        @type noe:                  bool
        @keyword relax_fit:         A flag which when True will enable the relaxation curve-fitting portions of the wizard.
        @type relax_fit:            bool
        @keyword relax_disp:        A flag which when True will enable the relaxation dispersion portions of the wizard.
        @type relax_disp:           bool
        """

        # Store the args.
        self.noe_flag = noe
        self.relax_fit_flag = relax_fit
        self.relax_disp_flag = relax_disp

        # Get the app and store the GUI instance.
        app = wx.GetApp()
        self.gui = app.gui

        # Execute the base class method.
        Wiz_window.__init__(self,
                            parent=self.gui,
                            size_x=size_x,
                            size_y=size_y,
                            title=title,
                            style=wx.DEFAULT_DIALOG_STYLE)

        # Change the cursor to busy.
        wx.BeginBusyCursor()

        # Initialise the page_indices structure.
        self.page_indices = {}

        # First check that at least a single spin is named!
        if not are_spins_named():
            # The message.
            msg = "No spins have been named.  Please use the spin.name user function first, otherwise it is unlikely that any data will be loaded from the peak intensity file.\n\nThis message can be ignored if the generic file format is used and spin names have not been specified.  Would you like to name the spins already loaded into the relax data store?"

            # Ask about naming spins, and add the spin.name user function page.
            if (status.show_gui and Question(
                    msg, title="Incomplete setup", size=(450, 250),
                    default=True).ShowModal()
                    == wx.ID_YES) or not status.show_gui:
                page = uf_store['spin.name'].create_page(self, sync=True)
                self.page_indices['name'] = self.add_page(
                    page, proceed_on_error=False)

        # The spectrum.read_intensities page.
        self.page_intensity = uf_store[
            'spectrum.read_intensities'].create_page(self, sync=True)
        self.page_indices['read'] = self.add_page(self.page_intensity,
                                                  skip_button=True,
                                                  proceed_on_error=False)

        # Error type selection page.
        self.page_error_type = Spectral_error_type_page(parent=self,
                                                        height_desc=520)
        self.page_indices['err_type'] = self.add_page(self.page_error_type,
                                                      apply_button=False)
        self.set_seq_next_fn(self.page_indices['err_type'],
                             self.wizard_page_after_error_type)

        # The spectrum.replicated page.
        page = uf_store['spectrum.replicated'].create_page(self, sync=True)
        self.page_indices['repl'] = self.add_page(page,
                                                  skip_button=True,
                                                  proceed_on_error=False)
        self.set_seq_next_fn(self.page_indices['repl'],
                             self.wizard_page_after_repl)
        page.on_init = self.wizard_update_repl

        # The spectrum.baseplane_rmsd page.
        page = uf_store['spectrum.baseplane_rmsd'].create_page(self, sync=True)
        self.page_indices['rmsd'] = self.add_page(page,
                                                  skip_button=True,
                                                  proceed_on_error=False)
        self.set_seq_next_fn(self.page_indices['rmsd'],
                             self.wizard_page_after_rmsd)
        page.on_init = self.wizard_update_rmsd

        # The spectrum.integration_points page.
        page = uf_store['spectrum.integration_points'].create_page(self,
                                                                   sync=True)
        self.page_indices['pts'] = self.add_page(page,
                                                 skip_button=True,
                                                 proceed_on_error=False)
        page.on_init = self.wizard_update_pts

        # NOE pages.
        if self.noe_flag:
            # The noe.spectrum_type page.
            page = uf_store['noe.spectrum_type'].create_page(self, sync=True)
            self.page_indices['spectrum_type'] = self.add_page(
                page, skip_button=False, proceed_on_error=False)
            page.on_display_post = self.wizard_update_noe_spectrum_type

        # Relaxation curve-fitting pages.
        if self.relax_fit_flag:
            # The relax_fit.relax_time page.
            page = uf_store['relax_fit.relax_time'].create_page(self,
                                                                sync=True)
            self.page_indices['relax_time'] = self.add_page(
                page, skip_button=False, proceed_on_error=False)
            page.on_init = self.wizard_update_relax_fit_relax_time

        # Relaxation dispersion pages.
        if self.relax_disp_flag:
            # The relax_disp.exp_type page.
            page = uf_store['relax_disp.exp_type'].create_page(self, sync=True)
            self.page_indices['exp_type'] = self.add_page(
                page, skip_button=True, proceed_on_error=False)
            page.on_init = self.wizard_update_relax_disp_exp_type

            # The spectrometer.frequency page.
            page = uf_store['spectrometer.frequency'].create_page(self,
                                                                  sync=True)
            self.page_indices['spectrometer_frequency'] = self.add_page(
                page, skip_button=True, proceed_on_error=False)
            page.on_init = self.wizard_update_spectrometer_frequency

            # The relax_disp.relax_time page.
            page = uf_store['relax_disp.relax_time'].create_page(self,
                                                                 sync=True)
            self.page_indices['relax_time'] = self.add_page(
                page, skip_button=True, proceed_on_error=False)
            page.on_init = self.wizard_update_relax_disp_relax_time
            self.set_seq_next_fn(self.page_indices['relax_time'],
                                 self.wizard_page_after_relax_time)

            # The relax_disp.cpmg_setup page.
            page = uf_store['relax_disp.cpmg_setup'].create_page(self,
                                                                 sync=True)
            self.page_indices['cpmg_setup'] = self.add_page(
                page, skip_button=True, proceed_on_error=False)
            page.on_init = self.wizard_update_relax_disp_cpmg_setup
            self.set_seq_next_fn(self.page_indices['cpmg_setup'],
                                 self.wizard_page_after_cpmg_setup)

            # The relax_disp.spin_lock_field page.
            page = uf_store['relax_disp.spin_lock_field'].create_page(
                self, sync=True)
            self.page_indices['spin_lock_field'] = self.add_page(
                page, skip_button=True, proceed_on_error=False)
            page.on_init = self.wizard_update_relax_disp_spin_lock_field

            # The relax_disp.spin_lock_offset page.
            page = uf_store['relax_disp.spin_lock_offset'].create_page(
                self, sync=True)
            self.page_indices['spin_lock_offset'] = self.add_page(
                page, skip_button=True, proceed_on_error=False)
            page.on_init = self.wizard_update_relax_disp_spin_lock_offset

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()

        # Run the wizard.
        self.run()
Пример #20
0
    def __init__(self, parent=None, size_x=1000, size_y=750, title="Peak intensity loading wizard", noe=False, relax_fit=False, relax_disp=False):
        """Set up the peak intensity loading wizard.

        @keyword parent:            The parent window.
        @type parent:               wx.Window instance
        @keyword size_x:            The width of the wizard.
        @type size_x:               int
        @keyword size_y:            The height of the wizard.
        @type size_y:               int
        @keyword title:             The title of the wizard dialog.
        @type title:                str
        @keyword noe:               A flag which when True will enable the steady-state NOE portions of the wizard.
        @type noe:                  bool
        @keyword relax_fit:         A flag which when True will enable the relaxation curve-fitting portions of the wizard.
        @type relax_fit:            bool
        @keyword relax_disp:        A flag which when True will enable the relaxation dispersion portions of the wizard.
        @type relax_disp:           bool
        """

        # Store the args.
        self.noe_flag = noe
        self.relax_fit_flag = relax_fit
        self.relax_disp_flag = relax_disp

        # Get the app and store the GUI instance.
        app = wx.GetApp()
        self.gui = app.gui

        # Execute the base class method.
        Wiz_window.__init__(self, parent=self.gui, size_x=size_x, size_y=size_y, title=title, style=wx.DEFAULT_DIALOG_STYLE)

        # Change the cursor to busy.
        wx.BeginBusyCursor()

        # Initialise the page_indices structure.
        self.page_indices = {}

        # First check that at least a single spin is named!
        if not are_spins_named():
            # The message.
            msg = "No spins have been named.  Please use the spin.name user function first, otherwise it is unlikely that any data will be loaded from the peak intensity file.\n\nThis message can be ignored if the generic file format is used and spin names have not been specified.  Would you like to name the spins already loaded into the relax data store?"

            # Ask about naming spins, and add the spin.name user function page.
            if (status.show_gui and Question(msg, title="Incomplete setup", size=(450, 250), default=True).ShowModal() == wx.ID_YES) or not status.show_gui:
                page = uf_store['spin.name'].create_page(self, sync=True)
                self.page_indices['name'] = self.add_page(page, proceed_on_error=False)

        # The spectrum.read_intensities page.
        self.page_intensity = uf_store['spectrum.read_intensities'].create_page(self, sync=True)
        self.page_indices['read'] = self.add_page(self.page_intensity, skip_button=True, proceed_on_error=False)

        # Error type selection page.
        self.page_error_type = Spectral_error_type_page(parent=self, height_desc=520)
        self.page_indices['err_type'] = self.add_page(self.page_error_type, apply_button=False)
        self.set_seq_next_fn(self.page_indices['err_type'], self.wizard_page_after_error_type)

        # The spectrum.replicated page.
        page = uf_store['spectrum.replicated'].create_page(self, sync=True)
        self.page_indices['repl'] = self.add_page(page, skip_button=True, proceed_on_error=False)
        self.set_seq_next_fn(self.page_indices['repl'], self.wizard_page_after_repl)
        page.on_init = self.wizard_update_repl

        # The spectrum.baseplane_rmsd page.
        page = uf_store['spectrum.baseplane_rmsd'].create_page(self, sync=True)
        self.page_indices['rmsd'] = self.add_page(page, skip_button=True, proceed_on_error=False)
        self.set_seq_next_fn(self.page_indices['rmsd'], self.wizard_page_after_rmsd)
        page.on_init = self.wizard_update_rmsd

        # The spectrum.integration_points page.
        page = uf_store['spectrum.integration_points'].create_page(self, sync=True)
        self.page_indices['pts'] = self.add_page(page, skip_button=True, proceed_on_error=False)
        page.on_init = self.wizard_update_pts

        # NOE pages.
        if self.noe_flag:
            # The noe.spectrum_type page.
            page = uf_store['noe.spectrum_type'].create_page(self, sync=True)
            self.page_indices['spectrum_type'] = self.add_page(page, skip_button=False, proceed_on_error=False)
            page.on_display_post = self.wizard_update_noe_spectrum_type

        # Relaxation curve-fitting pages.
        if self.relax_fit_flag:
            # The relax_fit.relax_time page.
            page = uf_store['relax_fit.relax_time'].create_page(self, sync=True)
            self.page_indices['relax_time'] = self.add_page(page, skip_button=False, proceed_on_error=False)
            page.on_init = self.wizard_update_relax_fit_relax_time

        # Relaxation dispersion pages.
        if self.relax_disp_flag:
            # The relax_disp.exp_type page.
            page = uf_store['relax_disp.exp_type'].create_page(self, sync=True)
            self.page_indices['exp_type'] = self.add_page(page, skip_button=True, proceed_on_error=False)
            page.on_init = self.wizard_update_relax_disp_exp_type

            # The spectrometer.frequency page.
            page = uf_store['spectrometer.frequency'].create_page(self, sync=True)
            self.page_indices['spectrometer_frequency'] = self.add_page(page, skip_button=True, proceed_on_error=False)
            page.on_init = self.wizard_update_spectrometer_frequency

            # The relax_disp.relax_time page.
            page = uf_store['relax_disp.relax_time'].create_page(self, sync=True)
            self.page_indices['relax_time'] = self.add_page(page, skip_button=True, proceed_on_error=False)
            page.on_init = self.wizard_update_relax_disp_relax_time
            self.set_seq_next_fn(self.page_indices['relax_time'], self.wizard_page_after_relax_time)

            # The relax_disp.cpmg_setup page.
            page = uf_store['relax_disp.cpmg_setup'].create_page(self, sync=True)
            self.page_indices['cpmg_setup'] = self.add_page(page, skip_button=True, proceed_on_error=False)
            page.on_init = self.wizard_update_relax_disp_cpmg_setup
            self.set_seq_next_fn(self.page_indices['cpmg_setup'], self.wizard_page_after_cpmg_setup)

            # The relax_disp.spin_lock_field page.
            page = uf_store['relax_disp.spin_lock_field'].create_page(self, sync=True)
            self.page_indices['spin_lock_field'] = self.add_page(page, skip_button=True, proceed_on_error=False)
            page.on_init = self.wizard_update_relax_disp_spin_lock_field

            # The relax_disp.spin_lock_offset page.
            page = uf_store['relax_disp.spin_lock_offset'].create_page(self, sync=True)
            self.page_indices['spin_lock_offset'] = self.add_page(page, skip_button=True, proceed_on_error=False)
            page.on_init = self.wizard_update_relax_disp_spin_lock_offset

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()

        # Run the wizard.
        self.run()
Пример #21
0
class Auto_model_free(Base_analysis):
    """The model-free auto-analysis GUI element."""

    def __init__(self, parent, id=-1, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=524288, name='scrolledpanel', gui=None, analysis_name=None, pipe_name=None, pipe_bundle=None, uf_exec=[], data_index=None):
        """Build the automatic model-free protocol GUI element.

        @param parent:          The parent wx element.
        @type parent:           wx object
        @keyword id:            The unique ID number.
        @type id:               int
        @keyword pos:           The position.
        @type pos:              wx.Size object
        @keyword size:          The size.
        @type size:             wx.Size object
        @keyword style:         The style.
        @type style:            int
        @keyword name:          The name for the panel.
        @type name:             unicode
        @keyword gui:           The main GUI class.
        @type gui:              gui.relax_gui.Main instance
        @keyword analysis_name: The name of the analysis (the name in the tab part of the notebook).
        @type analysis_name:    str
        @keyword pipe_name:     The name of the original data pipe for this analysis.
        @type pipe_name:        str
        @keyword pipe_bundle:   The name of the data pipe bundle associated with this analysis.
        @type pipe_bundle:      str
        @keyword uf_exec:       The list of user function on_execute methods returned from the new analysis wizard.
        @type uf_exec:          list of methods
        @keyword data_index:    The index of the analysis in the relax data store (set to None if no data currently exists).
        @type data_index:       None or int
        """

        # Store the GUI main class.
        self.gui = gui

        # Init.
        self.init_flag = True

        # New data container.
        if data_index == None:
            # First create the data pipe if not already in existence.
            if not has_pipe(pipe_name):
                self.gui.interpreter.apply('pipe.create', pipe_name=pipe_name, pipe_type='mf', bundle=pipe_bundle)

            # Create the data pipe bundle if needed.
            if not has_bundle(pipe_bundle):
                self.gui.interpreter.apply('pipe.bundle', bundle=pipe_bundle, pipe=pipe_name)

            # Generate a storage container in the relax data store, and alias it for easy access.
            data_index = ds.relax_gui.analyses.add('model-free')

            # Store the analysis and pipe names.
            ds.relax_gui.analyses[data_index].analysis_name = analysis_name
            ds.relax_gui.analyses[data_index].pipe_name = pipe_name
            ds.relax_gui.analyses[data_index].pipe_bundle = pipe_bundle

            # Initialise the variables.
            ds.relax_gui.analyses[data_index].grid_inc = None
            ds.relax_gui.analyses[data_index].diff_tensor_grid_inc = {'sphere': 11, 'prolate': 11, 'oblate': 11, 'ellipsoid': 6}
            ds.relax_gui.analyses[data_index].mc_sim_num = None
            ds.relax_gui.analyses[data_index].save_dir = self.gui.system_cwd_path
            ds.relax_gui.analyses[data_index].local_tm_models = ['tm0', 'tm1', 'tm2', 'tm3', 'tm4', 'tm5', 'tm6', 'tm7', 'tm8', 'tm9']
            ds.relax_gui.analyses[data_index].mf_models = ['m0', 'm1', 'm2', 'm3', 'm4', 'm5', 'm6', 'm7', 'm8', 'm9']
            ds.relax_gui.analyses[data_index].max_iter = 30

        # Error checking.
        if ds.relax_gui.analyses[data_index].pipe_bundle == None:
            raise RelaxError("The pipe bundle must be supplied.")

        # Alias the data.
        self.data = ds.relax_gui.analyses[data_index]
        self.data_index = data_index

        # Backward compatibility.
        if not hasattr(self.data, 'local_tm_models'):
            self.data.local_tm_models = ['tm0', 'tm1', 'tm2', 'tm3', 'tm4', 'tm5', 'tm6', 'tm7', 'tm8', 'tm9']
        if not hasattr(self.data, 'mf_models'):
            self.data.mf_models = ['m0', 'm1', 'm2', 'm3', 'm4', 'm5', 'm6', 'm7', 'm8', 'm9']

        # Initialise the mode selection window.
        self.mode_win = Protocol_mode_sel_window()

        # Register the method for updating the spin count for the completion of user functions.
        self.observer_register()

        # Execute the base class method to build the panel.
        super(Auto_model_free, self).__init__(parent, id=id, pos=pos, size=size, style=style, name=name)


    def _about(self, event=None):
        """The about window.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Initialise the dialog.
        self.about_dialog = About_window(self)

        # Show the dialog.
        if status.show_gui:
            self.about_dialog.Show()


    def activate(self):
        """Activate or deactivate certain elements of the analysis in response to the execution lock."""

        # Flag for enabling or disabling the elements.
        enable = False
        if not status.exec_lock.locked():
            enable = True

        # Activate or deactivate the elements.
        wx.CallAfter(self.field_results_dir.Enable, enable)
        wx.CallAfter(self.spin_systems.Enable, enable)
        wx.CallAfter(self.relax_data.Enable, enable)
        wx.CallAfter(self.button_dipole_pair.Enable, enable)
        wx.CallAfter(self.button_csa.Enable, enable)
        wx.CallAfter(self.button_isotope_heteronuc.Enable, enable)
        wx.CallAfter(self.button_isotope_proton.Enable, enable)
        wx.CallAfter(self.local_tm_model_field.Enable, enable)
        wx.CallAfter(self.mf_model_field.Enable, enable)
        wx.CallAfter(self.grid_inc.Enable, enable)
        wx.CallAfter(self.mc_sim_num.Enable, enable)
        wx.CallAfter(self.max_iter.Enable, enable)
        wx.CallAfter(self.mode.Enable, enable)
        wx.CallAfter(self.button_exec_relax.Enable, enable)


    def add_values(self, box):
        """Create and add the value.set buttons for the model-free analysis.

        @param box:     The box element to pack the GUI element into.
        @type box:      wx.BoxSizer instance
        """

        # Sizer.
        sizer = wx.BoxSizer(wx.HORIZONTAL)

        # Dipole-dipole relaxation setup button.
        self.button_dipole_pair = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, " Dipolar relaxation")
        self.button_dipole_pair.SetBitmapLabel(wx.Bitmap(fetch_icon("relax.dipole_pair", "22x22"), wx.BITMAP_TYPE_ANY))
        self.button_dipole_pair.SetFont(font.normal)
        self.button_dipole_pair.SetSize((-1, 25))
        self.button_dipole_pair.SetToolTipString("Define the magnetic dipole-dipole relaxation mechanism.")
        self.gui.Bind(wx.EVT_BUTTON, self.setup_dipole_pair, self.button_dipole_pair)
        sizer.Add(self.button_dipole_pair, 1, wx.ALL|wx.EXPAND, 0)

        # CSA button.
        self.button_csa = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, " CSA relaxation")
        self.button_csa.SetBitmapLabel(wx.Bitmap(fetch_icon("relax.align_tensor", "22x22"), wx.BITMAP_TYPE_ANY))
        self.button_csa.SetFont(font.normal)
        self.button_csa.SetSize((-1, 25))
        self.button_csa.SetToolTipString("Define the Chemical Shift Anisotropy (CSA) relaxation mechanism via the value.set user function.")
        self.gui.Bind(wx.EVT_BUTTON, self.value_set_csa, self.button_csa)
        sizer.Add(self.button_csa, 1, wx.ALL|wx.EXPAND, 0)

        # Isotope type button (heteronucleus).
        self.button_isotope_heteronuc = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, " X isotope")
        self.button_isotope_heteronuc.SetBitmapLabel(wx.Bitmap(fetch_icon("relax.nuclear_symbol", "22x22"), wx.BITMAP_TYPE_ANY))
        self.button_isotope_heteronuc.SetFont(font.normal)
        self.button_isotope_heteronuc.SetSize((-1, 25))
        self.button_isotope_heteronuc.SetToolTipString("Set the nuclear isotope types of the heteronuclear spins via the spin.isotope user function.")
        self.gui.Bind(wx.EVT_BUTTON, self.spin_isotope_heteronuc, self.button_isotope_heteronuc)
        sizer.Add(self.button_isotope_heteronuc, 1, wx.ALL|wx.EXPAND, 0)

        # Isotope type button (proton).
        self.button_isotope_proton = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, " H isotope")
        self.button_isotope_proton.SetBitmapLabel(wx.Bitmap(fetch_icon("relax.nuclear_symbol", "22x22"), wx.BITMAP_TYPE_ANY))
        self.button_isotope_proton.SetFont(font.normal)
        self.button_isotope_proton.SetSize((-1, 25))
        self.button_isotope_proton.SetToolTipString("Set the nuclear isotope types of the proton spins via the spin.isotope user function.")
        self.gui.Bind(wx.EVT_BUTTON, self.spin_isotope_proton, self.button_isotope_proton)
        sizer.Add(self.button_isotope_proton, 1, wx.ALL|wx.EXPAND, 0)

        # Add the element to the box.
        box.Add(sizer, 0, wx.ALL|wx.EXPAND, 0)


    def assemble_data(self):
        """Assemble the data required for the auto-analysis.

        See the docstring for auto_analyses.dauvernge_protocol for details.  All data is taken from the relax data store, so data upload from the GUI to there must have been previously performed.

        @return:    A container with all the data required for the auto-analysis.
        @rtype:     class instance, list of str
        """

        # The data container.
        data = Container()
        missing = []

        # The pipe name and bundle.
        data.pipe_name = self.data.pipe_name
        data.pipe_bundle = self.data.pipe_bundle

        # The model-free models (do not change these unless absolutely necessary).
        data.local_tm_models = self.local_tm_model_field.GetValue()
        data.mf_models = self.mf_model_field.GetValue()

        # Automatic looping over all rounds until convergence (must be a boolean value of True or False).
        data.conv_loop = True

        # Increment size.
        data.inc = gui_to_int(self.grid_inc.GetValue())
        if hasattr(self.data, 'diff_tensor_grid_inc'):
            data.diff_tensor_grid_inc = self.data.diff_tensor_grid_inc
        else:
            data.diff_tensor_grid_inc = {'sphere': 11, 'prolate': 11, 'oblate': 11, 'ellipsoid': 6}

        # The number of Monte Carlo simulations to be used for error analysis at the end of the analysis.
        data.mc_sim_num = gui_to_int(self.mc_sim_num.GetValue())

        # Number of maximum iterations.
        data.max_iter = self.data.max_iter

        # Results directory.
        data.save_dir = self.data.save_dir

        # Check if sequence data is loaded
        if not exists_mol_res_spin_data():
            missing.append("Sequence data")

        # Relaxation data.
        if not hasattr(cdp, 'ri_ids') or len(cdp.ri_ids) == 0:
            missing.append("Relaxation data")

        # Insufficient data.
        if hasattr(cdp, 'ri_ids') and len(cdp.ri_ids) <= 3:
            missing.append("Insufficient relaxation data, 4 or more data sets are essential for the execution of the dauvergne_protocol auto-analysis. Check that you have entered data for a least two spectrometer fields.")

        # Interatomic data containers.
        if not hasattr(cdp, 'interatomic') or len(cdp.interatomic) == 0:
            missing.append("Interatomic data (for the dipole-dipole interaction)")

        # Get the mode.
        mode = gui_to_str(self.mode.GetValue())

        # Solve for all global models.
        if mode == 'Fully automated':
            # The global model list.
            data.global_models = ['local_tm', 'sphere', 'prolate', 'oblate', 'ellipsoid', 'final']

        # Any global model selected.
        else:
            data.global_models = [mode]

        # Check for vectors.
        vector_check = False
        if 'prolate' in data.global_models or 'oblate' in data.global_models or 'ellipsoid' in data.global_models:
            vector_check = True

        # Spin variables.
        for spin, spin_id in spin_loop(return_id=True):
            # Skip deselected spins.
            if not spin.select:
                continue

            # The message skeleton.
            msg = "Spin '%s' - %s (try the %s user function)." % (spin_id, "%s", "%s")

            # Test if the nuclear isotope type has been set.
            if not hasattr(spin, 'isotope') or spin.isotope == None:
                missing.append(msg % ("nuclear isotope data", "spin.isotope"))

            # Test if the CSA value has been set for the heteronuclei.
            if (hasattr(spin, 'isotope') and spin.isotope in ['15N', '13C']) and (not hasattr(spin, 'csa') or spin.csa == None):
                missing.append(msg % ("CSA data", "value.set"))

        # Interatomic data container variables.
        for interatom in interatomic_loop():
            # Get the spin containers.
            spin1 = return_spin(interatom.spin_id1)
            spin2 = return_spin(interatom.spin_id2)

            # Skip deselected spins.
            if not spin1.select:
                continue
            if not spin2.select:
                continue

            # The message skeleton.
            msg = "Spin pair '%s' and '%s' - %s (try the %s user function)." % (interatom.spin_id1, interatom.spin_id2, "%s", "%s")

            # Test if the interatomic distance has been set.
            if not hasattr(interatom, 'r') or interatom.r == None:
                missing.append(msg % ("bond length data", "value.set"))

            # Test if the unit vectors have been loaded.
            if vector_check and (not hasattr(interatom, 'vector') or interatom.vector == None):
                missing.append(msg % ("unit vectors", "interatom.unit_vectors"))

        # Return the container and list of missing data.
        return data, missing


    def build_left_box(self):
        """Construct the left hand box to pack into the main model-free box.

        @return:    The left hand box element containing the bitmap and about button to pack into the main model-free box.
        @rtype:     wx.BoxSizer instance
        """

        # Build the left hand box.
        left_box = wx.BoxSizer(wx.VERTICAL)

        # The images.
        bitmaps = [ANALYSIS_IMAGE_PATH+"model_free"+sep+"model_free_200x200.png",
                   IMAGE_PATH+'modelfree.png']

        # Add the model-free bitmap picture.
        for i in range(len(bitmaps)):
            # The bitmap.
            bitmap = wx.StaticBitmap(self, -1, bitmap_setup(bitmaps[i]))

            # Add it.
            left_box.Add(bitmap, 0, wx.ALL, 0)

        # A spacer.
        left_box.AddStretchSpacer()

        # A button sizer, with some initial spacing.
        button_sizer = wx.BoxSizer(wx.HORIZONTAL)

        # An about button.
        button = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, "About")
        button.SetBitmapLabel(wx.Bitmap(fetch_icon('oxygen.actions.help-about', "22x22"), wx.BITMAP_TYPE_ANY))
        button.SetFont(font.normal)
        button.SetToolTipString("Information about this automatic analysis")

        # Bind the click.
        self.Bind(wx.EVT_BUTTON, self._about, button)

        # A cursor for the button.
        cursor = wx.StockCursor(wx.CURSOR_QUESTION_ARROW)
        button.SetCursor(cursor)

        # Pack the button.
        button_sizer.Add(button, 0, 0, 0)
        left_box.Add(button_sizer, 0, wx.ALL, 0)

        # Return the packed box.
        return left_box


    def build_right_box(self):
        """Construct the right hand box to pack into the main model-free box.

        @return:    The right hand box element containing all model-free GUI elements (excluding the bitmap) to pack into the main model-free box.
        @rtype:     wx.BoxSizer instance
        """

        # Use a vertical packing of elements.
        box = wx.BoxSizer(wx.VERTICAL)

        # Add the frame title.
        self.add_title(box, "Model-free analysis")

        # Display the data pipe.
        Text_ctrl(box, self, text="The data pipe bundle:", default=self.data.pipe_bundle, tooltip="This is the data pipe bundle associated with this analysis.", editable=False, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal)

        # Add the results directory GUI element.
        self.field_results_dir = Text_ctrl(box, self, text="Results directory:", icon=fetch_icon('oxygen.actions.document-open-folder', "16x16"), default=self.data.save_dir, tooltip="The directory in which all automatically created files will be saved.", tooltip_button="Select the results directory.", fn=self.results_directory, button=True, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal)

        # Add the spin GUI element.
        self.add_spin_systems(box, self)

        # Add the relaxation data list GUI element, with spacing.
        box.AddSpacer(10)
        self.relax_data = Relax_data_list(gui=self.gui, parent=self, box=box, id=str(self.data_index))
        box.AddSpacer(10)

        # Add the value.set buttons.
        self.add_values(box)
        box.AddSpacer(10)

        # Add the local tau_m models GUI element, with spacing.
        self.local_tm_model_field = Local_tm_list(self, box)
        self.local_tm_model_field.set_value(self.data.local_tm_models)

        # Add the model-free models GUI element, with spacing.
        self.mf_model_field = Mf_list(self, box)
        self.mf_model_field.set_value(self.data.mf_models)

        # The optimisation settings.
        self.grid_inc = Spin_ctrl(box, self, text="Grid search increments:", default=11, min=1, max=100, tooltip="This is the number of increments per dimension of the grid search performed prior to numerical optimisation.", width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal)
        self.mc_sim_num = Spin_ctrl(box, self, text="Monte Carlo simulation number:", default=500, min=1, max=100000, tooltip="This is the number of Monte Carlo simulations performed for error propagation and analysis.", width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal)

        # Add maximum iteration selector.
        self.max_iter = Spin_ctrl(box, self, text="Maximum iterations:", default=self.data.max_iter, tooltip="The maximum number of iterations for the protocol.  This is the limit for the global looping over the optimisation of the model-free models, model elimination, model selection and then optimisation of the diffusion tensor.", min=25, max=100, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal)

        # The calculation mode.
        self.mode = Text_ctrl(box, self, text="Protocol mode:", default='Fully automated', tooltip="Select if the dauvergne_protocol analysis will be fully automated or whether the individual global models will be optimised separately.", tooltip_button="Open the protocol mode selection window.", icon=fetch_icon('oxygen.actions.system-run', "16x16"), fn=self.mode_dialog, editable=False, button=True, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal)

        # Stretchable spacing (with a minimal space).
        box.AddSpacer(30)
        box.AddStretchSpacer()

        # Add the execution GUI element.
        self.button_exec_relax = self.add_execute_analysis(box, self.execute)

        # Return the box.
        return box


    def delete(self):
        """Unregister the spin count from the user functions."""

        # Unregister the observer methods.
        self.observer_register(remove=True)

        # Clean up the relaxation data list object.
        self.relax_data.delete()

        # Destroy the dipole-dipole interaction wizard.
        if hasattr(self, 'dipole_wizard'):
            self.dipole_wizard.Destroy()
            del self.dipole_wizard

        # Destroy the mode selection window.
        self.mode_win.Destroy()
        del self.mode_win

        # Destroy the model list windows.
        self.local_tm_model_field.model_win.Destroy()
        del self.local_tm_model_field
        self.mf_model_field.model_win.Destroy()
        del self.mf_model_field

        # Destroy the missing data dialog, if present.
        if hasattr(self, 'missing_data'):
            self.missing_data.Destroy()
            del self.missing_data


    def execute(self, event=None):
        """Set up, execute, and process the automatic model-free protocol.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Flush the GUI interpreter internal queue to make sure all user functions are complete.
        self.gui.interpreter.flush()

        # relax execution lock.
        if status.exec_lock.locked():
            error_message("relax is currently executing.", "relax execution lock")
            event.Skip()
            return

        # User warning to close windows.
        self.gui.close_windows()

        # Synchronise the frame data to the relax data store.
        self.sync_ds(upload=True)

        # Assemble all the data needed for the auto-analysis.
        data, missing = self.assemble_data()

        # Missing data.
        if len(missing):
            self.missing_data = Missing_data(missing)
            return

        # Display the relax controller, and go to the end of the log window.
        self.gui.show_controller(None)
        self.gui.controller.log_panel.on_goto_end(None)

        # Start the thread.
        self.thread = Execute_mf(self.gui, data, self.data_index)
        self.thread.start()

        # Terminate the event.
        event.Skip()


    def mode_dialog(self, event=None):
        """The calculation mode selection.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Show the model selector window.
        if status.show_gui:
            self.mode_win.ShowModal()

        # Set the model.
        self.mode.SetValue(str_to_gui(self.mode_win.select))


    def observer_register(self, remove=False):
        """Register and unregister methods with the observer objects.

        @keyword remove:    If set to True, then the methods will be unregistered.
        @type remove:       False
        """

        # Register.
        if not remove:
            status.observers.gui_uf.register(self.data.pipe_bundle, self.update_spin_count, method_name='update_spin_count')
            status.observers.exec_lock.register(self.data.pipe_bundle, self.activate, method_name='activate')

        # Unregister.
        else:
            # The model-free methods.
            status.observers.gui_uf.unregister(self.data.pipe_bundle)
            status.observers.exec_lock.unregister(self.data.pipe_bundle)

            # The embedded objects methods.
            self.relax_data.observer_register(remove=True)


    def results_directory(self, event=None):
        """The results directory selection.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # The dialog.
        dialog = RelaxDirDialog(parent=self, message='Select the results directory', defaultPath=self.field_results_dir.GetValue())

        # Show the dialog and catch if no file has been selected.
        if status.show_gui and dialog.ShowModal() != wx.ID_OK:
            # Don't do anything.
            return

        # The path (don't do anything if not set).
        path = gui_to_str(dialog.get_path())
        if not path:
            return

        # Store the path.
        self.data.save_dir = path

        # Place the path in the text box.
        self.field_results_dir.SetValue(str_to_gui(path))


    def setup_dipole_pair(self, event=None):
        """Create the wizard for the dipole-dipole interaction.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Change the cursor to busy.
        wx.BeginBusyCursor()

        # Destroy the dipole-dipole interaction wizard, if it exists.
        if hasattr(self, 'dipole_wizard'):
            self.dipole_wizard.Destroy()

        # Create the wizard.
        self.dipole_wizard = Wiz_window(parent=self.gui, size_x=1000, size_y=750, title="Dipole-dipole interaction setup")

        # Structural data.
        if not hasattr(cdp, 'structure'):
            # Create the PDB reading page.
            page = uf_store['structure.read_pdb'].create_page(self.dipole_wizard, sync=True)
            self.dipole_wizard.add_page(page, skip_button=True)

            # Create the position reading page.
            page = uf_store['structure.get_pos'].create_page(self.dipole_wizard, sync=True)
            self.dipole_wizard.add_page(page, skip_button=True)

        # Create the interatom.define page.
        page = uf_store['interatom.define'].create_page(self.dipole_wizard, sync=True)
        page.SetValue('spin_id1', '@N')
        page.SetValue('spin_id2', '@H')
        self.dipole_wizard.add_page(page)

        # Create the interatom.set_dist page.
        page = uf_store['interatom.set_dist'].create_page(self.dipole_wizard, sync=True)
        page.SetValue('spin_id1', '@N*')
        page.SetValue('spin_id2', '@H*')
        page.SetValue('ave_dist', NH_BOND_LENGTH)
        self.dipole_wizard.add_page(page)

        # Create the interatom.unit_vectors page.
        page = uf_store['interatom.unit_vectors'].create_page(self.dipole_wizard, sync=True)
        self.dipole_wizard.add_page(page)

        # Reset the cursor.
        if wx.IsBusy():
            wx.EndBusyCursor()

        # Execute the wizard.
        self.dipole_wizard.run()


    def spin_isotope_heteronuc(self, event=None):
        """Set the nuclear isotope types of the heteronuclear spins via the spin.isotope user function.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Call the user function.
        uf_store['spin.isotope'](isotope='15N', spin_id='@N*')


    def spin_isotope_proton(self, event=None):
        """Set the nuclear isotope types of the proton spins via the spin.isotope user function.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Call the user function.
        uf_store['spin.isotope'](isotope='1H', spin_id='@H*')


    def sync_ds(self, upload=False):
        """Synchronise the analysis frame and the relax data store, both ways.

        This method allows the frame information to be uploaded into the relax data store, or for the information in the relax data store to be downloaded by the frame.

        @keyword upload:    A flag which if True will cause the frame to send data to the relax data store.  If False, data will be downloaded from the relax data store to update the frame.
        @type upload:       bool
        """

        # The local tau_m models to use.
        if upload:
            self.data.local_tm_models = self.local_tm_model_field.GetValue()
        else:
            self.local_tm_model_field.set_value(self.data.local_tm_models)

        # The model-free models to use.
        if upload:
            self.data.mf_models = self.mf_model_field.GetValue()
        else:
            self.mf_model_field.set_value(self.data.mf_models)

        # The grid incs.
        if upload:
            self.data.grid_inc = gui_to_int(self.grid_inc.GetValue())
        elif hasattr(self.data, 'grid_inc'):
            self.grid_inc.SetValue(int(self.data.grid_inc))

        # The MC sim number.
        if upload:
            self.data.mc_sim_num = gui_to_int(self.mc_sim_num.GetValue())
        elif hasattr(self.data, 'mc_sim_num'):
            self.mc_sim_num.SetValue(int(self.data.mc_sim_num))

        # The results directory.
        if upload:
            self.data.save_dir = str(self.field_results_dir.GetValue())
        else:
            self.field_results_dir.SetValue(str_to_gui(self.data.save_dir))

        # Maximum iterations.
        if upload:
            self.data.max_iter = gui_to_int(self.max_iter.GetValue())
        else:
            self.max_iter.SetValue(int(self.data.max_iter))


    def value_set_csa(self, event=None):
        """Set the CSA via the value.set uf.

        @keyword event: The wx event.
        @type event:    wx event
        """

        # Get the default value.
        api = return_api()
        val = api.default_value('csa')

        # Call the user function.
        uf_store['value.set'](val=val, param='csa', spin_id='@N*')