Пример #1
0
class ApplicationPopup(AnalysisPopup):

    help_url = 'http://www.ccpn.ac.uk'

    allowedCallbackFuncnames = ('init', 'save', 'close')

    def __init__(self, root, programName='Extend-NMR Interface'):

        self.font = DEFAULT_FONT
        # Application object needed to store application-specific data with project
        self.application = Application(name=PROGRAM_NAME)
        self.versionInfo = 'Version' + VERSION
        self.ariaProjectFile = None
        self.doneAnalysisInfo = False

        self.updateFuncs = []
        self.projButtons = []

        self.ariaPaths = []
        self.isdPaths = []

        AnalysisPopup.__init__(self, root)

        self.program_name = PROGRAM_NAME
        self.setTitle(PROGRAM_NAME)

    def printAnalysisCommandLineInfo(self, event):

        if not self.doneAnalysisInfo:
            Analysis.printCommandLineInfo(self)
            self.doneAnalysisInfo = True

    def printCommandLineInfo(self):

        print """
 For program documentation see:
 http://www.extend-nmr.eu   
    """

    def body(self, guiParent):

        self.menus = {}
        self.menu_items = {}

        self.fixedActiveMenus = {}

        self.popups = {}

        self.callbacksDict = {}

        self.selected_objects = []

        self.menubar = menubar = Menu(guiParent)

        self.font = DEFAULT_FONT

        self.setProjectMenu()
        #

        menu = Menu(self.menubar, tearoff=0)
        menu.bind('<Button>', self.printAnalysisCommandLineInfo)
        self.menubar.add_cascade(label='CcpNmr Analysis',
                                 shortcut='C',
                                 menu=menu)
        self.menubar.add_command(label='FormatConverter',
                                 shortcut='F',
                                 command=self.runFormatConverter)

        self.menubar = menu
        self.initProject()
        self.setPeaksMenu()
        self.setMoleculeMenu()
        self.setAssignMenu()
        self.setResonanceMenu()
        self.setDataMenu()
        self.setStructureMenu()
        self.setChartMenu()
        self.setMacroMenu()
        self.setOtherMenu()
        self.setMenuState()  # need to do it again because of OtherMenu state

        # Help Submenu

        helpMenu = Menu(self.menubar, tearoff=0)
        helpMenu.add_command(label='Version',
                             shortcut='V',
                             command=self.showVersion)
        helpMenu.add_command(label='About',
                             shortcut='A',
                             command=self.showAbout)
        helpMenu.add_command(label='Help', shortcut='H', command=self.showHelp)

        menu.add_separator()
        menu.add_command(label='CCPN Updates',
                         shortcut='U',
                         image=self.iconRefresh,
                         compound='left',
                         command=self.updateAnalysis,
                         tipText='Get any new patches and updates to CcpNmr')
        menu.add_cascade(label='CCPN Help',
                         shortcut='H',
                         image=self.iconHelp,
                         compound='left',
                         menu=helpMenu)

        self.config(menu=menubar)

        # Ensure that the first row and column in popup expand
        guiParent.grid_rowconfigure(0, weight=1)
        guiParent.grid_columnconfigure(0, weight=1, minsize=200)
        frame = Frame(guiParent)  # Body widgets can be put in this frame
        frame.grid()

        softwareOpts = [
            'Extend-NMR', 'ARIA 2', 'Auremol', 'CING', ' ECI ', 'HADDOCK',
            ' ISD ', 'PRODECOMP'
        ]

        self.tabbedFrame = TabbedFrame(guiParent,
                                       options=softwareOpts,
                                       toggleOff=False,
                                       selected=0,
                                       callback=self.toggleTab)
        self.tabbedFrame.grid(row=0, column=0, sticky='nsew')

        frames = self.tabbedFrame.frames

        # Logos
        ccpnDir = getTopDirectory()

        imageDir = os.path.join(ccpnDir, 'python', 'extendNmr', 'images')

        imageFile = os.path.join(imageDir, 'Fp6Logo.gif')
        self.fp6Logo = Tkinter.PhotoImage(file=imageFile)
        imageFile = os.path.join(imageDir, 'CingLogo.gif')
        self.cingLogo = Tkinter.PhotoImage(file=imageFile)
        imageFile = os.path.join(imageDir, 'AriaLogo.gif')
        self.ariaLogo = Tkinter.PhotoImage(file=imageFile)
        imageFile = os.path.join(imageDir, 'IsdLogo.gif')
        self.isdLogo = Tkinter.PhotoImage(file=imageFile)
        imageFile = os.path.join(imageDir, 'HaddockLogo.gif')
        self.haddockLogo = Tkinter.PhotoImage(file=imageFile)
        imageFile = os.path.join(imageDir, 'AuremolLogo.gif')
        self.auremolLogo = Tkinter.PhotoImage(file=imageFile)
        imageFile = os.path.join(imageDir, 'CcpnLogo.gif')
        self.ccpnLogo = Tkinter.PhotoImage(file=imageFile)
        imageFile = os.path.join(imageDir, 'ProdecompLogo.gif')
        self.prodecompLogo = Tkinter.PhotoImage(file=imageFile)
        imageFile = os.path.join(imageDir, 'MddLogo.gif')
        self.mddLogo = Tkinter.PhotoImage(file=imageFile)
        imageFile = os.path.join(imageDir, 'BrukerLogo.gif')
        self.brukerLogo = Tkinter.PhotoImage(file=imageFile)
        imageFile = os.path.join(imageDir, 'MsdLogo.gif')
        self.msdLogo = Tkinter.PhotoImage(file=imageFile)

        self.initExtendNmr(frames[0])

        self.initAria(frames[1])

        self.initAuremol(frames[2])

        self.initCing(frames[3])

        self.initEci(frames[4])

        self.initHaddock(frames[5])

        self.initIsd(frames[6])

        self.initProdecomp(frames[7])

        self.initProject(self.project)

        if not self.project:
            for button in self.projButtons:
                button.disable()

        self.geometry('680x670')

    def setProjectMenu(self):
        ProjectMenu = 'Project'

        # Imports submenu

        importsMenu = Menu(self.menubar, tearoff=False)
        importsMenu.add_command(label='Via Format Converter',
                                shortcut='F',
                                command=self.runFormatConverter)
        importsMenu.add_command(label='NMR-STAR 2.1.1',
                                command=self.importNmrStar211)
        importsMenu.add_command(label='NMR-STAR 3.1',
                                shortcut='N',
                                command=self.importNmrStar31)
        importsMenu.add_command(label='PDB 3.20',
                                shortcut='P',
                                command=self.importPdb)
        importsMenu.add_command(label='Coordinates (PDB-style)',
                                shortcut='C',
                                command=self.importCoordinates)

        # Preferences submenu

        fontsMenu = FontMenu(self.menubar,
                             self.selectFont,
                             sizes=(8, 10, 12),
                             doItalic=False,
                             doBoldItalic=False,
                             tearoff=0)

        prefsMenu = Menu(self.menubar, tearoff=False)
        prefsMenu.add_cascade(
            label='Fonts',
            shortcut='F',
            image=self.iconFont,
            compound='left',
            menu=fontsMenu,
            tipText='Select font to use in the graphical interface')
        prefsMenu.add_command(label='Colour Schemes',
                              image=self.iconTable,
                              compound='left',
                              shortcut='C',
                              tipText='Edit and create colour schemes',
                              command=self.editColorSchemes)
        prefsMenu.add_command(
            label='Residue Codes',
            image=self.iconTable,
            compound='left',
            shortcut='R',
            tipText=
            'User-specified codes that override the standard residue names',
            command=self.editResidueCodes)
        prefsMenu.add_command(label='User Options',
                              image=self.iconTable,
                              compound='left',
                              shortcut='U',
                              tipText='General options for Analysis behaviour',
                              command=self.editProfiles)

        #

        menu = Menu(self.menubar, tearoff=0)
        menu.add_command(
            label='New',
            shortcut='N',
            image=self.iconNewWindow,
            compound='left',
            command=self.newProject,
            tipText='Create a new, blank CCPN project (closes any open project)'
        )
        menu.add_command(
            label='Open Project',
            shortcut='O',
            image=self.iconOpen,
            compound='left',
            command=self.openProject,
            tipText=
            'Open a new CCPN project by selecting a project directory on disk')
        menu.add_command(
            label='Open Spectra',
            shortcut='p',
            image=self.iconOpenFile,
            compound='left',
            command=self.openSpectrum,
            tipText=
            'Open spectrum data fom disk, creating a default CCPN project if needed'
        )
        menu.add_command(label='Save',
                         shortcut='S',
                         image=self.iconSave,
                         compound='left',
                         command=self.saveProject,
                         tipText='Save the current CCPN project on disk')
        menu.add_command(
            label='Save As',
            shortcut='A',
            image=self.iconSaveAs,
            compound='left',
            command=self.saveAsProject,
            tipText=
            'Save the current CCPN project under a different name (project directory)'
        )
        menu.add_cascade(label='Import',
                         shortcut='I',
                         image=self.iconImport,
                         compound='left',
                         menu=importsMenu)
        menu.add_command(label='Close',
                         shortcut='C',
                         image=self.iconClose,
                         compound='left',
                         command=self.closeProject,
                         tipText='Close the current CCPN project')
        menu.add_command(
            label='Quit',
            shortcut='Q',
            image=self.iconQuit,
            compound='left',
            command=self.quit,
            tipText='Quit Extend-NMR, closing any open CCPN project')
        menu.add_separator()
        menu.add_cascade(label='Preferences',
                         shortcut='P',
                         image=self.iconPrefs,
                         compound='left',
                         menu=prefsMenu)
        menu.add_command(
            label='Validate',
            shortcut='V',
            image=self.iconTool,
            compound='left',
            command=self.validateProject,
            tipText=
            'Check the current CCPN project for data model consistency errors')
        menu.add_command(
            label='Backup',
            shortcut='B',
            image=self.iconTool,
            compound='left',
            command=self.backupProject,
            tipText='Setup options for automated backup of CCPN project data')
        menu.add_command(
            label='Archive',
            shortcut='r',
            image=self.iconTool,
            compound='left',
            command=self.archiveProject,
            tipText=
            'Save the current CCPN project in an archived form, e.g. tar gzipped'
        )

        self.menubar.add_cascade(label=ProjectMenu, shortcut='j', menu=menu)
        self.menus[ProjectMenu] = menu
        self.menu_items[ProjectMenu] = [
            'New',
            'Open Project',
            'Open Spectra',
            'Save',
            'Save As',
            'Import',
            'Close',
            'Quit',
            'Preferences',
            'Validate',
            'Backup',
            'Archive',
        ]

        # Menus that area ctive in absence of a project
        #for ii in (0,1,2,7,13,15):
        for ii in (
                0,
                1,
                2,
                7,
        ):
            self.fixedActiveMenus[(ProjectMenu, ii)] = True

    def setPopupGeometries(self):

        for key in self.popups.keys():
            popup = self.popups[key]
            if not key.startswith(window_popup_prefix):  # bit of a hack
                not self.setPopupGeometry(popup, key)

    def toggleTab(self, index):

        if (index > 0) and not self.project:
            showWarning('Warning', 'No active project', parent=self)
            self.tabbedFrame.select(0)
            return

        frame = self.tabbedFrame.frames[index]
        if hasattr(frame, 'printOutDocString'):
            print frame.printOutDocString
            # only print it once
            del frame.printOutDocString

    def initCing(self, frame):

        frame.grid_columnconfigure(0, weight=1)
        frame.grid_rowconfigure(1, weight=1)

        canvas = Tkinter.Canvas(frame, width=702, height=77)
        canvas.grid(row=0, column=0, sticky='ew')
        canvas.create_image(0, 0, anchor='nw', image=self.cingLogo)

        cingFrame = CingFrame(frame, self)
        cingFrame.grid(row=1, column=0, sticky='nsew')

        #self.projButtons.extend(cingFrame.buttonBar.buttons)
        self.updateFuncs.append(cingFrame.updateAll)

    def initProdecomp(self, frame):

        frame.grid_columnconfigure(0, weight=1)
        frame.grid_rowconfigure(1, weight=1)
        frame.configure(bg='#FFFFFF')

        canvas = Tkinter.Canvas(frame, width=1024, height=90, bg='#FFFFFF')
        canvas.grid(row=0, column=0, sticky='ew')
        canvas.create_image(0, 0, anchor='nw', image=self.prodecompLogo)

        prodecompFrame = ProdecompFrame(frame,
                                        basePopup=self,
                                        ccpnProject=self.project)
        prodecompFrame.grid(row=1, column=0, sticky='nsew')

        # set printOutDocString:
        frame.printOutDocString = prodecompFrame.printOutDocString

        #self.projButtons.extend(isdFrame.buttons)
        self.updateFuncs.append(prodecompFrame.updateAll)

    def initAuremol(self, frame):

        frame.expandGrid(1, 0)

        refText = """Gronwald W, Brunner K, Kirchhofer R, Nasser A, Trenner J, Ganslmeier B,
Riepl H, Ried A, Scheiber J, Elsner R, Neidig K-P, Kalbitzer HR

AUREMOL, a New Program for the Automated Structure Elucidation of
Biological Macromolecules. Bruker Reports 2004; 154/155: 11-14
    """

        canvas = Tkinter.Canvas(frame, width=700, height=160, bg='#FFFFFF')
        canvas.grid(row=0, column=0, sticky='ew')
        canvas.create_image(12, 12, anchor='nw', image=self.auremolLogo)
        canvas.create_text(200, 10, anchor='nw', text=refText)

        auremolFrame = AuremolFrame(frame, self.project, grid=(1, 0))

        #self.projButtons.extend(isdFrame.buttons)
        self.updateFuncs.append(auremolFrame.updateAll)

    def initEci(self, frame):

        frame.grid_columnconfigure(0, weight=1)
        frame.grid_rowconfigure(1, weight=1)
        frame.parent = self  # For notifiers
        frame.configure(bg='#FFFFFF')

        canvas = Tkinter.Canvas(frame,
                                width=800,
                                height=73,
                                bd=3,
                                bg='#FFFFFF')
        canvas.grid(row=0, column=0, sticky='ew')
        canvas.create_image(10, 10, anchor='nw', image=self.msdLogo)

        eciFrame = EntryCompletionFrame(frame, basePopup=self)
        eciFrame.grid(row=1, column=0, sticky='nsew')

        #self.projButtons.extend(isdFrame.buttons)
        self.updateFuncs.append(eciFrame.updateAll)

    def initHaddock(self, frame):

        frame.grid_columnconfigure(0, weight=1)
        frame.grid_rowconfigure(1, weight=1)
        frame.parent = self  # For notifiers

        canvas = Tkinter.Canvas(frame, width=753, height=92)
        canvas.grid(row=0, column=0, sticky='ew')
        canvas.create_image(0, 0, anchor='nw', image=self.haddockLogo)

        haddockFrame = HaddockFrame(frame, self.project)
        haddockFrame.grid(row=1, column=0, sticky='nsew')

        #self.projButtons.extend(isdFrame.buttons)
        self.updateFuncs.append(haddockFrame.updateAll)

    def initIsd(self, frame):

        global isd

        frame.grid_columnconfigure(0, weight=1)
        frame.grid_rowconfigure(1, weight=1)

        frame.configure(bg='#FFFFFF')

        canvas = Tkinter.Canvas(frame,
                                width=800,
                                height=91,
                                bd=3,
                                bg='#FFFFFF')
        canvas.grid(row=0, column=0, sticky='ew', padx=0)
        canvas.create_image(0, 0, anchor='nw', image=self.isdLogo)

        isdFrame = IsdFrame(frame, self.project)
        isdFrame.grid(row=1, column=0, sticky='nsew')

        self.isd = isdFrame
        isd = self.isd

        #self.projButtons.extend(isdFrame.buttons)
        self.updateFuncs.append(isdFrame.updateAll)

    def initExtendNmr(self, frame):

        row = 0
        frame.config(bd=5)
        canvas = Tkinter.Canvas(frame,
                                width=640,
                                height=600,
                                bg='#FFFFFF',
                                bd=5)
        canvas.grid(row=row, column=0, sticky='nsew')
        canvas.create_image(15, 15, anchor='nw', image=self.fp6Logo)
        canvas.create_image(330, 15, anchor='nw', image=self.prodecompLogo)
        canvas.create_image(330, 115, anchor='nw', image=self.mddLogo)
        canvas.create_image(20, 200, anchor='nw', image=self.ccpnLogo)
        canvas.create_image(230, 220, anchor='nw', image=self.msdLogo)
        canvas.create_image(450, 200, anchor='nw', image=self.brukerLogo)
        canvas.create_image(5, 310, anchor='nw', image=self.isdLogo)
        canvas.create_image(230, 300, anchor='nw', image=self.ariaLogo)
        canvas.create_image(450, 290, anchor='nw', image=self.auremolLogo)
        canvas.create_image(5, 420, anchor='nw', image=self.haddockLogo)
        canvas.create_image(5, 520, anchor='nw', image=self.cingLogo)

        #row += 1
        #l1 = Label(frame, text='Welcome to the Extend NMR suite')
        #l1.grid(row=row, column=0, sticky='ew')

    def initAria(self, frame):

        welcomeMessage = \
        """ARIA Version 2.3. Authors: Benjamin Bardiaux, Michael Habeck,
Jens Linge, Therese Malliavin, Sean O'Donoghue, Wolfgang Rieping,
and Michael Nilges.

Rieping W., Habeck M., Bardiaux B., Bernard A., Malliavin T.E.,
Nilges M.(2007) ARIA2: automated NOE assignment and data
integration in NMR structure calculation. Bioinformatics 23:381-382"""

        frame.grid_columnconfigure(0, weight=1)
        frame.grid_rowconfigure(1, weight=1)

        canvas = Tkinter.Canvas(frame, width=700, height=114, bg='#FFFFFF')
        canvas.grid(row=0, column=0, sticky='ew')
        canvas.create_image(0, 0, anchor='nw', image=self.ariaLogo)
        canvas.create_text(250, 10, anchor='nw', text=welcomeMessage)

        ariaFrame = AriaFrame(frame, self)
        ariaFrame.grid(row=1, column=0, sticky='nsew')

        self.projButtons.extend(ariaFrame.buttons)
        self.updateFuncs.append(ariaFrame.updateAll)

    def openPopup(self, popup_name, clazz, oldStyle=False, *args, **kw):

        popup = self.popups.get(popup_name)

        if (popup):
            popup.open()
        else:
            if self.project:
                analysisProfile = self.analysisProfile
            else:
                analysisProfile = None

            if analysisProfile:
                if popup_name.startswith(window_popup_prefix):  # bit of a hack
                    transient = analysisProfile.transientWindows
                else:
                    transient = analysisProfile.transientDialogs
            else:
                transient = True

            name = popup_name

            if (oldStyle):
                popup = self.popups[popup_name] = clazz(self,
                                                        transient=transient,
                                                        *args,
                                                        **kw)
            else:
                popup = self.popups[popup_name] = clazz(self,
                                                        project=self.project,
                                                        popup_name=name,
                                                        transient=transient,
                                                        *args,
                                                        **kw)
            # above automatically opens popup

        return popup

    def initProject(self, project=None):

        AnalysisPopup.initProject(self, project, False)

        self.project = project
        if project:
            for i, func in enumerate(self.updateFuncs):
                func(project)

            for button in self.projButtons:
                button.enable()

        else:
            for button in self.projButtons:
                button.disable()

    def setupSoftware(self):

        return

        project = self.project

        methodStore = project.currentMethodStore or \
                      project.findFirstMethodStore() or \
                      project.newMethodStore(name=project.name)

        software = methodStore.findFirstSoftware(name=PROGRAM_NAME,
                                                 version=VERSION)
        if not software:
            software = methodStore.newSoftware(name=PROGRAM_NAME,
                                               version=VERSION)

        software.task = 'data pipeline'
        software.vendorName = 'The Extend-NMR Project'
        #software.vendorAddress = ''
        software.vendorWebAddress = 'http://www.extend-nmr.eu'
Пример #2
0
class RelaxationAnalysisPopup(BasePopup):

  def __init__(self, parent, *args, **kw):
    
    self.guiParent = parent
    self.t1List = None
    self.t2List = None
    self.noeList = None
    self.waiting = False
   
    BasePopup.__init__(self, parent, title="Relaxation Analyses", **kw)

    periodicTable = self.project.currentChemElementStore
    
    nitrogen = periodicTable.findFirstChemElement(elementSymbol='N')
    hydrogen = periodicTable.findFirstChemElement(elementSymbol='H')

  def body(self, guiFrame):

    self.geometry('700x840')
    
    guiFrame.expandGrid(1,0)
    
    # Top frame
    
    frame = Frame(guiFrame, grid=(0,0))
    frame.expandGrid(None,8)
    
    label = Label(frame, text=u' %s List:' % T1, grid=(0,0))
    self.t1Pulldown = PulldownList(frame, callback=self.selectT1List, grid=(0,1))
    
    label = Label(frame, text=u'  %s List:' % T2, grid=(0,2))
    self.t2Pulldown = PulldownList(frame, callback=self.selectT2List, grid=(0,3))
    
    label = Label(frame, text='  NOE List:', grid=(0,4))
    self.noePulldown = PulldownList(frame, callback=self.selectNoeList, grid=(0,5))
 
    label = Label(frame, text='  Spectrometer Freq (MHz):', grid=(0,6))
    self.sfEntry = FloatEntry(frame, grid=(0,7), text=600.00, width=6)

    UtilityButtonList(frame, grid=(0,9), sticky='e')
    
    # Tabs
    
    options = [u'%s vs %s Scatter' % (T1, T2),
               u'%s,%s & NOE Graphs' % (T1, T2) ,
               u'%s/%s Graph' % (T1, T2),
               u'%s Estimate Graph' % S2,
               'Options']
    self.tabbedFrame = TabbedFrame(guiFrame, options=options,
                                   callback=self.toggleTab, grid=(1,0))
    frameA, frameD, frameC, frameE, frameB = self.tabbedFrame.frames

    # T1 vs T2 Graph

    frameA.expandGrid(0,0)
 
    self.t1t2Graph = T1VersesT2Plot(frameA, grid=(0,0))

    # T1 & T2 Graph

    frameD.expandGrid(0,0)
    frameD.expandGrid(1,0)
    frameD.expandGrid(2,0)
 
    self.t1Graph = MeasurementPlot(frameD, T1, grid=(0,0))
    self.t2Graph = MeasurementPlot(frameD, T2, grid=(1,0))
    self.noeGraph = NoePlot(frameD, 'NOE', grid=(2,0))

    # T1 over T2 Graph

    frameC.expandGrid(0,0)
 
    self.t1t2GraphB = T1OverT2Plot(frameC, grid=(0,0))
    
    # Order params graph
    
    frameE.expandGrid(0,0)
    frameE.expandGrid(1,0)
    frameE.expandGrid(2,0)
    
    self.s2Graph = ScrolledGraph(frameE, title=u'%s vs Residue Sequence' % S2,
                                 xLabel='Residue number', yLabel=S2,
                                 width=500, height=150, graphType='histogram', 
                                 xGrid=True, yGrid=False, grid=(0,0),
                                 dataColors=['#0000A0','#808000'],
                                 dataNames=['Isotropic',])

    self.teGraph = ScrolledGraph(frameE, title=u'%s vs Residue Sequence' % Te,
                                 xLabel='Residue number', yLabel=u'%s (ps)' % Te,
                                 width=500, height=150, graphType='histogram',
                                 xGrid=True, yGrid=False, grid=(1,0),
                                 dataColors=['#008000',])
                                 
    self.rexGraph = ScrolledGraph(frameE, title=u'%s vs Residue Sequence' % 'Rex',
                                  xLabel='Residue number', yLabel='Rex',
                                  width=500, height=150, graphType='histogram',
                                  xGrid=True, yGrid=False, grid=(2,0),
                                  dataColors=['#900000',])
    
    # Options
    
    frameB.expandGrid(4,2)
    
    frame = LabelFrame(frameB, text='Physical Params', grid=(0,0))
    frame.expandGrid(None,3)
   
    label = Label(frame, text=u'N-H bond length (\u00C5)', grid=(0,0))
    self.lenNhEntry = FloatEntry(frame, text=1.015, grid=(0,1), width=8)

    label = Label(frame, text=u'Internal correlation\ntime, \u03C4e (ps)', grid=(1,0))
    self.ictEntry = FloatEntry(frame, text=50.0, grid=(1,1), width=8)
    
    label = Label(frame, text=u'15N Chemical Shift\nAnisotopy,\u0394N (ppm)',
                  grid=(2,0))
    self.csaNEntry = FloatEntry(frame, text=-160.0, grid=(2,1), width=8)
    
    frame = LabelFrame(frameB, text=u'%s vs %s Scatter' % (T1, T2), grid=(1,0))
    
    label = Label(frame, text='Max cluster difference (ms):', grid=(0,0))
    self.clusterDictEntry = FloatEntry(frame, text=20.0, grid=(0,1), width=8)    

    label = Label(frame, text='Min cluster size:', grid=(1,0))
    self.clusterSizeEntry = FloatEntry(frame, text=5, grid=(1,1), width=8)    

    label = Label(frame, text=u'Min graph %s (ms):' % T1, grid=(2,0))
    self.minT1Entry = FloatEntry(frame, text=300.0, grid=(2,1), width=8)    

    label = Label(frame, text=u'Max graph %s (ms):' % T1, grid=(3,0))
    self.maxT1Entry = FloatEntry(frame, text=1000.0, grid=(3,1), width=8)    

    label = Label(frame, text=u'Min graph %s (ms):' % T2, grid=(4,0))
    self.minT2Entry = FloatEntry(frame, text=0.0, grid=(4,1), width=8)    

    label = Label(frame, text=u'Max graph %s (ms):' % T2, grid=(5,0))
    self.maxT2Entry = FloatEntry(frame, text=600.0, grid=(5,1), width=8)    
    
    frame = LabelFrame(frameB, text=u'%s Contours' % S2, grid=(0,1))
    frame.expandGrid(4,3)

    label = Label(frame, text='(Order Parameter Lines)',
                  grid=(0,0), gridSpan=(1,2))

    label = Label(frame, text='Min value:', grid=(1,0))
    self.minS2Entry = FloatEntry(frame, text=0.3, grid=(1,1), width=8)
    
    label = Label(frame, text='Max value:', grid=(2,0))
    self.maxS2Entry = FloatEntry(frame, text=1.0, grid=(2,1), width=8)
    
    label = Label(frame, text='Step:', grid=(3,0))
    self.stepS2Entry = FloatEntry(frame, text=0.1, grid=(3,1), width=8)

    frame = LabelFrame(frameB, text=u'\u03C4m Contours', grid=(1,1))
    frame.expandGrid(4,3)

    label = Label(frame, text='(Rotational Correlation Time Lines)',
                  grid=(0,0), gridSpan=(1,2))
                  
    label = Label(frame, text='Min value (ns):', grid=(1,0))
    self.minRctEntry = FloatEntry(frame, text=5.0, grid=(1,1), width=8)
    
    label = Label(frame, text='Max value (ns):', grid=(2,0))
    self.maxRctEntry = FloatEntry(frame, text=14.0, grid=(2,1), width=8)
    
    label = Label(frame, text='Step (ns):', grid=(3,0))
    self.stepRctEntry = FloatEntry(frame, text=1.0, grid=(3,1), width=8)

    # Bottom frame
 
    texts = [u'Show %s Table' % T1,u'Show %s Table' % T2, u'Estimate %s' % S2]
    commands = [self.showT1List, self.showT2List, self.mc]
    buttonList = ButtonList(guiFrame, grid=(2,0), texts=texts, commands=commands)

    # Update

    self.updateRelaxationLists()

    self.drawAfter()

    self.administerNotifiers(self.registerNotify)
  
  def open(self):
  
    self.updateRelaxationLists()
    self.drawAfter()
  
    BasePopup.open(self)
  
  def destroy(self):
  
    self.administerNotifiers(self.unregisterNotify)
    
    BasePopup.destroy(self)
  
  def getSanitisedParams(self):
  
     cDist = self.clusterDictEntry.get() or 0.0
     lenNh = max(min(self.lenNhEntry.get() or 1.015, 1.2), 0.8)
     ict = self.ictEntry.get() or 0.0
     csaN = self.csaNEntry.get() or -180.0
     
     if csaN > 0:
       csaN *= -1.0
     
     minS2 = max(min(self.minS2Entry.get() or 0.0, 0.9), 0.0)
     maxS2 = max(min(self.maxS2Entry.get() or 1.0, 1.0), 0.1)
     
     if minS2 > maxS2:
       maxS2, minS2 = minS2, maxS2
     
     stepS2 = max(self.stepS2Entry.get() or 0.1, (maxS2-minS2)/100)
     
     minRct = self.minRctEntry.get()
     maxRct = self.maxRctEntry.get()
     
     if minRct > maxRct:
       maxRct, minRct = minRct, maxRct
     
     stepRct = max(self.stepRctEntry.get() or 0.1, (maxRct-minRct)/100)
     
     cluster = max(abs(self.clusterSizeEntry.get() or 10), 1)
     
     minT1 = self.minT1Entry.get() or 300.0
     maxT1 = self.maxT1Entry.get() or 1000.0
     minT2 = self.minT2Entry.get() or 0.0
     maxT2 = self.maxT2Entry.get() or 600.0
   
     
     if minT1 < 0:
       minT1 = 0.0

     if minT2 < 0:
       minT2 = 0.0


     if maxT1 < 0:
       maxT1 = 0.0

     if maxT2 < 0:
       maxT2 = 0.0


     if minT1 > maxT1:
       minT1, maxT1 = maxT1, minT1
       
     if minT2 > maxT2:
       minT2, maxT2 = maxT2, minT2


     if minT1 == maxT1:
       maxT1 += 100
     if minT2 == maxT2:
       maxT2 += 100
     
     
     self.clusterSizeEntry.set(cluster)
     self.minT1Entry.set(minT1)
     self.maxT1Entry.set(maxT1)
     self.minT2Entry.set(minT2)
     self.maxT2Entry.set(maxT2)
     self.clusterDictEntry.set(cDist)
     self.lenNhEntry.set(lenNh)
     self.ictEntry.set(ict)
     self.csaNEntry.set(csaN)
     self.minS2Entry.set(minS2)
     self.maxS2Entry.set(maxS2)
     self.stepS2Entry.set(stepS2)
     self.minRctEntry.set(minRct)
     self.maxRctEntry.set(maxRct)
     self.stepRctEntry.set(stepRct)
     
     paramsS2 = (minS2, maxS2, stepS2)
     paramsRct = (minRct, maxRct, stepRct)
     tBounds = (minT1, maxT1, minT2, maxT2)

     return cluster, cDist, lenNh, ict, csaN,  paramsS2, paramsRct, tBounds

  def administerNotifiers(self, notifyFunc):
  
    for func in ('__init__', 'delete','setName'):
      for clazz in ('ccp.nmr.Nmr.T1List','ccp.nmr.Nmr.T2List'):
        notifyFunc(self.updateRelaxationLists,clazz, func)

    for func in ('__init__', 'delete', 'setValue'):
      notifyFunc(self.updateMeasurementAfter,'ccp.nmr.Nmr.T1', func)
      notifyFunc(self.updateMeasurementAfter,'ccp.nmr.Nmr.T2', func)

  def showT1List(self):
  
    if self.t1List:
      self.guiParent.editMeasurements(self.t1List)

  def showT2List(self):
  
    if self.t2List:
      self.guiParent.editMeasurements(self.t2List)

  def toggleTab(self, index):
  
    if index == 0:
      self.drawAfter()

  def updateMeasurementAfter(self, measurement):
  
    if measurement.parentList in (self.t1List, self.t2List):
      self.drawAfter()
  
  def updateRelaxationLists(self, obj=None):
  
    mLists = self.nmrProject.sortedMeasurementLists()
    

    # T1
    t1List = self.t1List
    t1Lists = [ml for ml in mLists if ml.className == 'T1List']

    index = 0
    names = []
    
    if t1Lists:
      if t1List not in t1Lists:
        t1List = t1Lists[0]
      
      index = t1Lists.index(t1List)
      names = [ml.name or 'List %d' % ml.serial for ml in t1Lists]
    
    else:
      t1List = None
      
    self.selectT1List(t1List)
    self.t1Pulldown.setup(names, t1Lists, index)


    # T2
    t2List = self.t2List
    t2Lists = [ml for ml in mLists if ml.className == 'T2List']
    
    index = 0
    names = []
    
    if t2Lists:
      if t2List not in t2Lists:
        t2List = t2Lists[0]
      
      index = t2Lists.index(t2List)
      names = [ml.name or 'List %d' % ml.serial for ml in t2Lists]
    
    else:
      t2List = None
      
    self.selectT2List(t2List)
    self.t2Pulldown.setup(names, t2Lists, index)
    
    
    # NOE
    noeList = self.noeList
    noeLists = [ml for ml in mLists if ml.className == 'NoeList']
    
    index = 0
    names = []
    
    if noeLists:
      if noeList not in noeLists:
        noeList = noeLists[0]
      
      index = noeLists.index(noeList)
      names = [ml.name or 'List %d' % ml.serial for ml in noeLists]
    
    else:
      noeList = None
      
    self.selectNoeList(noeList)
    self.noePulldown.setup(names, noeLists, index)


  def drawAfter(self):
  
    if self.waiting:
      return
      
    self.waiting = True
    self.after_idle(self.draw)

  def selectT1List(self, t1List):
  
    if t1List is not self.t1List:
      self.t1List = t1List
      self.sfEntry.set(t1List.sf)
      values = [m.value for m in t1List.measurements]
      values.sort()
      minVal = self.minT1Entry.get()
      maxVal = self.maxT1Entry.get()
      minVal0 = values[0]*MS_UNIT_MULTIPLIERS[t1List.unit]
      maxVal0 = values[-1]*MS_UNIT_MULTIPLIERS[t1List.unit]

      if minVal0 < minVal:
        self.minT1Entry.set(max(minVal0 - 100, 0))
      
      if maxVal0 > maxVal:
        self.maxT1Entry.set(maxVal0 + 100)
      
      self.drawAfter()
    
  
  def selectT2List(self, t2List):
  
    if t2List is not self.t2List:
      self.t2List = t2List
      self.sfEntry.set(t2List.sf)
      values = [m.value for m in t2List.measurements]
      values.sort()
      values.sort()
      minVal = self.minT2Entry.get()
      maxVal = self.maxT2Entry.get()
      minVal0 = values[0]*MS_UNIT_MULTIPLIERS[t2List.unit]
      maxVal0 = values[-1]*MS_UNIT_MULTIPLIERS[t2List.unit]

      if minVal0 < minVal:
        self.minT2Entry.set(max(minVal0 - 50, 0))
      
      if maxVal0 > maxVal:
        self.maxT2Entry.set(maxVal0 + 50)
      
      self.drawAfter()
  
  
  def selectNoeList(self, noeList):
  
    if noeList is not self.noeList:
      self.noeList = noeList
      self.sfEntry.set(noeList.sf)
      
      #self.drawAfter()

  def draw(self):
  
    params = self.getSanitisedParams()
    
    cSize, cDist, lenNh, ict, csaN, paramsS2, paramsRct, tBounds = params
 
    sf = abs(self.sfEntry.get() or 500.010)
    
    self.t1t2Graph.update(self.t1List, self.t2List, cSize, cDist, sf, lenNh,
                          ict, csaN, paramsS2, paramsRct, tBounds)
                          
    self.t1t2GraphB.update(self.t1List, self.t2List)
    
    self.t1Graph.update(self.t1List)
    self.t2Graph.update(self.t2List)
    self.noeGraph.update(self.noeList)
      
    self.waiting = False


  def mc(self):
  
    sf = abs(self.sfEntry.get() or 500.010)
    
    if not self.t1List and self.t2List:
      return
    
    chains = set([])
    t1t2Points = {}
    resonancesT1 = {}
    resonancesNoe = {}
    residueResonances = {}

    t1Unit = MS_UNIT_MULTIPLIERS[self.t1List.unit]
    t2Unit = MS_UNIT_MULTIPLIERS[self.t2List.unit]
    
    
    if self.noeList:
      for noe in self.noeList.measurements:
        for resonance in noe.resonances:
          resonancesNoe[resonance] = noe
    
    for t1 in self.t1List.measurements:
      resonancesT1[t1.resonance] = t1
       
    for t2 in self.t2List.measurements:
      resonance = t2.resonance
      if not resonance.resonanceSet:
        continue
      
      residue = resonance.resonanceSet.findFirstAtomSet().findFirstAtom().residue
      
      t1 = resonancesT1.get(resonance)
      noe = resonancesNoe.get(resonance)
      
      if t1 and noe:
        t1t2Points[residue] = 1e-3*t1Unit*t1.value, 1e-3*t2Unit*t2.value, noe.value
        chains.add(residue.chain)
        residueResonances[residue] = resonance
      
      if t1:
        t1t2Points[residue] = 1e-3*t1Unit*t1.value, 1e-3*t2Unit*t2.value, None
        chains.add(residue.chain)
        residueResonances[residue] = resonance
     
    for chain in chains:
      residues = chain.sortedResidues()
      t1Values = []
      t2Values = []
      noeValues = []
      n = len(residues)
      n2 = n-1
      jj = range(n)
      s2Best = [0.0] * n
      teBest = [0.0] * n
      rexBest = [0.0] * n
      
      print ''
      
      for residue in residues:
        t1,t2, noe = t1t2Points.get(residue, (None, None, None))
        t1Values.append(t1)
        t2Values.append(t2)
        noeValues.append(noe)
      
      t1s = [v for v in t1Values if v]
      t2s = [v for v in t2Values if v]
      noes = [v for v in noeValues if v]
      
      m = len(t1s)
      
      t1 = sum(t1s)/float(m)
      t2 = sum(t2s)/float(m)
      noe = sum(noes)/float(m)
      
      t12 = [v/t2s[i] for i, v in enumerate(t1s) if v]
      t12m = sum(t12)/float(len(t12))
      deltas = [abs(v-t12m)/t12m for v in t12]
      w = [1.0/(v*v) for v in deltas]
      
      t1 = sum([ t1s[j]*w[j] for j in range(m)])/sum(w)
      t2 = sum([ t2s[j]*w[j] for j in range(m)])/sum(w)
      
      if noes:
        noe = sum([ noes[j]*w[j] for j in range(m)])/sum(w)
      else:
        noe = None

      i, ensemble = self.fitT1T2(t1, t2, noe, sf, tmFix=None, teFix=None, s2Fix=None,
                                 tmMin=1e-9, tmMax=100e-9, teMin=1e-12, teMax=1e-10,
                                 rexFix=0.0)
      ensemble.sort()
      score, s2, te0, tm0, rex, t1t, t2t, noet = ensemble[0]
 
      data = (s2, te0*1e12, tm0*1e9, rex, t1, t1t, t2, t2t, noe or 0.0, noet,  score, i)
      print 'Mean A S2:%5.3f Te:%5.1f Tm:%5.3f Rex:%5.3f T1:%5.3f %5.3f T2:%5.3f %5.3f NOE:%5.3f %5.3f %e %6d' % data
      
      rexCheck = 999 # 1.40 * t1/t2
       
      # Prior is mean, then region 
   
      for j in jj:
        t1 = t1Values[j]
        t2 = t2Values[j]
        noe = noeValues[j]
        if t1 is None:
          continue
         
        residue = residues[j]
        print '%3d%s' %  (residue.seqCode, residue.ccpCode),
        
        i, ensemble = self.fitT1T2(t1, t2, noe, sf, tmFix=tm0, teFix=None, s2Fix=None,
                                   tmMin=tm0*0.1, tmMax=tm0*5, teMin=te0/100, teMax=te0*20,
                                   rexFix=0.0, rexMax=15.0)
        ensemble.sort()
        score, s2, te, tm, rex, t1t, t2t, noet = ensemble[0]
        
        if s2 > 0.995:
          i, ensemble = self.fitT1T2(t1, t2, noe, sf, tmFix=tm0, teFix=None, s2Fix=None,
                                     teMin=te/10, teMax=te*10,
                                     rexFix=None, rexMax=15.0)
          ensemble.sort()
          score, s2, te, tm, rex, t1t, t2t, noet = ensemble[0]
         
          
        teBest[j] = te
        s2Best[j] = s2
        rexBest[j] = rex
 
        data = (s2, te*1e12, tm*1e9, rex, t1, t1t, t2, t2t, noe or 0.0, noet, score, i)
        print 'S2:%5.3f Te:%5.1f Tm:%5.3f Rex:%5.3f T1:%5.3f %5.3f T2:%5.3f %5.3f NOE:%5.3f %5.3f %e %6d' % data

      dataSet1 = []
      dataSet2 = []
      dataSet3 = []
      for j in jj:
        residue = residues[j]
        resonance = residueResonances.get(residue)
        
        if not resonance:
          continue
        
        dataSet1.append((residue.seqCode, s2Best[j]))
        dataSet2.append((residue.seqCode, teBest[j]*1e9))
        dataSet3.append((residue.seqCode, rexBest[j]))
        
      self.s2Graph.update([dataSet1,])
      self.teGraph.update([dataSet2,])
      self.rexGraph.update([dataSet3,])
      
      self.tabbedFrame.select(3)

  def fitT1T2(self, t1, t2, noe, sf, tmFix=None, teFix=None, s2Fix=None,
              tmMin=1e-9, tmMax=100e-9, teMin=1e-12, teMax=1e-9,
              rexFix=None, rexMax=15.0, niter=10000):
    
    # Could have multiple sf
    
    rNH = 1.015
    csaN = 160*1e-6 # 160 ppm
    omegaH = sf * 2 * PI * 1e6 # Rad/s
    omegaN = omegaH * GAMMA_N/GAMMA_H
    gammaHN = GAMMA_H/GAMMA_N
     
    A = REDUCED_PERM_VACUUM * REDUCED_PLANK * GAMMA_N * GAMMA_H * 1e30 # Cubic Angstrom adjust
    A /= rNH**3.0
    A = A*A/4.0
    C = omegaN * omegaN * csaN * csaN 
    C /= 3.0
    
    # Init params
    if s2Fix is None:
      s2Start = [x*0.05 for x in range(1,20)]
    else:
      s2Start = [s2Fix,]
    
    if teFix is None:
      teStart = [x*1e-12 for x in [10,30,70,100,300,700,1000]]
    else:
      teStart = [teFix,]
    
    if tmFix is None:
      tmStart = [x*1e-9 for x in range(1,30)]
    else:
      tmStart = [tmFix,]
    
    if rexFix is None:
      rexStart = [float(x) for x in range(int(rexMax))]
    else:
      rexStart = [rexFix,]
    
    # Init ensemble of solutions
    ensemble = []
    for s2 in s2Start:
      for te in teStart:
        for tm in tmStart:
          for rex in rexStart:
             ensemble.append((None, s2, te, tm, rex))
   
    
    # Init scores
    for k, (score, s2, te, tm, rex) in enumerate(ensemble):
      jH   = getSpectralDensity(s2, tm, te, omegaH)
      jN   = getSpectralDensity(s2, tm, te, omegaN)
      jHpN = getSpectralDensity(s2, tm, te, omegaH+omegaN)
      jHmN = getSpectralDensity(s2, tm, te, omegaH-omegaN)
      j0   = getSpectralDensity(s2, tm, te, 0.0)
 
      r1 = A*( (3*jN) + (6*jHpN) + jHmN ) + C*jN
      r2 = 0.5*A*( (4*j0) + (3*jN) + (6*jHpN) + (6*jH) + jHmN ) + C*( 2*j0/3.0 + 0.5*jN ) + rex
 
      t1p = 1.0/r1
      t2p = 1.0/r2
 
 
      d1 = (t1p-t1)/t1
      d2 = (t2p-t2)/t2
 
      score = (d1*d1) + (d2*d2)
      
      if noe is None:
        noep = 0.0
        
      else:
        noep = 1.0 + ( A * gammaHN * t1 * ((6*jHpN)-jHmN) )
        dn = (noep-noe)/2.0
        score += (dn*dn) 
      
      ensemble[k] = (score, s2, te, tm, rex, t1p, t2p, noep)
      
      # Matrix
      # 
      # Pred    Jh        
      # R1
      # R2
      # NOE
      #   r = 1.0/rct + 1.0/ict 
      #   t = 1.0/r
      #   j = (s2*rct) / (1.0 + w*w*rct*rct)
      #   j += ((1.0-s2)*t) / (1.0 + w*w*t*t)
      #       
      #   return j*0.4
    
    ensemble.sort()
    ensemble = ensemble[:10]
    ensembleSize = len(ensemble)
         
    bestScore = 1e99
    
    for i in xrange(niter):
 
      f = i/float(niter)
      f = exp(-10.0*f)
      # Mutate
 
      ensemble.sort()
      prevScore, s2, te, tm, rex, t1p, t2p, noep = ensemble[-1] #Biggest is worst
 
      if ensemble[0][0] < 1e-10:
        break
 
      if not s2Fix:
        #d = ((random() + 0.618 - 1.0) * f) + 1.0
        d = ((random() - 0.382) * f) + 1.0
        s2 = max(0.0, min(1.0, s2*d))
 
      if not tmFix:
        d = ((random() - 0.382) * f) + 1.0
        tm = max(tmMin, min(tmMax, tm*d))
      
      if not teFix:
        d = ((random() - 0.382) * f) + 1.0 
        te = max(teMin, min(teMax, te*d))

      d = ((random() - 0.382) * f) + 1.0 
      rex = max(0.0, min(rexMax, rex*d))
 
      jH   = getSpectralDensity(s2, tm, te, omegaH)
      jN   = getSpectralDensity(s2, tm, te, omegaN)
      jHpN = getSpectralDensity(s2, tm, te, omegaH+omegaN)
      jHmN = getSpectralDensity(s2, tm, te, omegaH-omegaN)
      j0   = getSpectralDensity(s2, tm, te, 0.0)

      r1 = A*( (3*jN) + (6*jHpN) + jHmN ) + C*jN
      r2 = 0.5*A*( (4*j0) + (3*jN) + (6*jHpN) + (6*jH) + jHmN ) + C*( 2*j0/3.0 + 0.5*jN ) + rex
 
      t1p = 1.0/r1
      t2p = 1.0/r2
 
      d1 = (t1p-t1)/t1
      d2 = (t2p-t2)/t2
 
      score = (d1*d1) + (d2*d2)
      if noe is None:
        noep = 0.0
      else:
        noep = 1.0 + ( A * gammaHN * t1 * ((6*jHpN)-jHmN) )
        dn = (noep-noe)/2.0
        score += (dn*dn) 
      
      ratio = exp(prevScore-score)
                      
      if ratio > 1.0: # random():
        ensemble[-1] = (score, s2, te, tm, rex, t1p, t2p, noep)
      else:
        k = randint(0,ensembleSize-1)
        score, s2, te, tm, rex, t1p, t2p, noep = ensemble[k]
        ensemble[-1] = (score, s2, te, tm, rex, t1p, t2p, noep)
    
      
      if score < bestScore:
        bestScore = score
    
    #print bestScore, ', '.join(['%.3e' % x[0] for x in ensemble])
        
    return i, ensemble