source: trunk/GSASIIconstrGUI.py @ 848

Last change on this file since 848 was 848, checked in by vondreele, 12 years ago

move all class stuff in GSAIIphsGUI to GSASIIgrid.py
move all DData GUI stuff to GSASIIddataGUI.py - new module
more rigid body work

File size: 55.4 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIconstrGUI - constraint GUI routines
3########### SVN repository information ###################
4# $Date: 2012-12-05 15:38:26 -0600 (Wed, 05 Dec 2012) $
5# $Author: vondreele $
6# $Revision: 810 $
7# $URL: https://subversion.xor.aps.anl.gov/pyGSAS/trunk/GSASIIconstrGUI.py $
8# $Id: GSASIIconstrGUI.py 810 2012-12-05 21:38:26Z vondreele $
9########### SVN repository information ###################
10import sys
11import wx
12import wx.grid as wg
13import time
14import random as ran
15import numpy as np
16import numpy.ma as ma
17import os.path
18import GSASIIpath
19GSASIIpath.SetVersionNumber("$Revision: 810 $")
20import GSASIIElem as G2elem
21import GSASIIElemGUI as G2elemGUI
22import GSASIIstruct as G2str
23import GSASIImapvars as G2mv
24import GSASIIgrid as G2gd
25import GSASIIplot as G2plt
26VERY_LIGHT_GREY = wx.Colour(235,235,235)
27
28class MultiIntegerDialog(wx.Dialog):
29   
30    def __init__(self,parent,title,prompts,values):
31        wx.Dialog.__init__(self,parent,-1,title, 
32            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
33        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
34        self.values = values
35        self.prompts = prompts
36        self.Draw()
37       
38    def Draw(self):
39       
40        def OnValItem(event):
41            Obj = event.GetEventObject()
42            ind = Indx[Obj.GetId()]
43            try:
44                val = int(Obj.GetValue())
45                if val <= 0:
46                    raise ValueError
47            except ValueError:
48                val = self.values[ind]
49            self.values[ind] = val
50            Obj.SetValue('%d'%(val))
51           
52        self.panel.Destroy()
53        self.panel = wx.Panel(self)
54        mainSizer = wx.BoxSizer(wx.VERTICAL)
55        Indx = {}
56        for ival,[prompt,value] in enumerate(zip(self.prompts,self.values)):
57            mainSizer.Add(wx.StaticText(self.panel,-1,prompt),0,wx.ALIGN_CENTER)
58            valItem = wx.TextCtrl(self.panel,-1,value='%d'%(value),style=wx.TE_PROCESS_ENTER)
59            mainSizer.Add(valItem,0,wx.ALIGN_CENTER)
60            Indx[valItem.GetId()] = ival
61            valItem.Bind(wx.EVT_TEXT_ENTER,OnValItem)
62            valItem.Bind(wx.EVT_KILL_FOCUS,OnValItem)
63        OkBtn = wx.Button(self.panel,-1,"Ok")
64        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
65        CancelBtn = wx.Button(self.panel,-1,'Cancel')
66        CancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
67        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
68        btnSizer.Add((20,20),1)
69        btnSizer.Add(OkBtn)
70        btnSizer.Add(CancelBtn)
71        btnSizer.Add((20,20),1)
72        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
73        self.panel.SetSizer(mainSizer)
74        self.panel.Fit()
75        self.Fit()
76
77    def GetValues(self):
78        return self.values
79       
80    def OnOk(self,event):
81        parent = self.GetParent()
82        parent.Raise()
83        self.EndModal(wx.ID_OK)             
84       
85    def OnCancel(self,event):
86        parent = self.GetParent()
87        parent.Raise()
88        self.EndModal(wx.ID_CANCEL)
89       
90################################################################################
91#####  Constraints
92################################################################################           
93       
94def UpdateConstraints(G2frame,data):
95    '''Called when Constraints tree item is selected.
96    Displays the constraints in the data window
97    '''
98    if not data:
99        data.update({'Hist':[],'HAP':[],'Phase':[]})       #empty dict - fill it
100    Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree()
101    AtomDict = dict([Phases[phase]['pId'],Phases[phase]['Atoms']] for phase in Phases)
102    Natoms,atomIndx,phaseVary,phaseDict,pawleyLookup,FFtable,BLtable = G2str.GetPhaseData(Phases,Print=False)
103    phaseList = []
104    for item in phaseDict:
105        if item.split(':')[2] not in ['Ax','Ay','Az','Amul','AI/A','Atype','SHorder']:
106            phaseList.append(item)
107    phaseList.sort()
108    phaseAtNames = {}
109    phaseAtTypes = {}
110    TypeList = []
111    for item in phaseList:
112        Split = item.split(':')
113        if Split[2][:2] in ['AU','Af','dA']:
114            Id = int(Split[0])
115            phaseAtNames[item] = AtomDict[Id][int(Split[3])][0]
116            phaseAtTypes[item] = AtomDict[Id][int(Split[3])][1]
117            if phaseAtTypes[item] not in TypeList:
118                TypeList.append(phaseAtTypes[item])
119        else:
120            phaseAtNames[item] = ''
121            phaseAtTypes[item] = ''
122           
123    hapVary,hapDict,controlDict = G2str.GetHistogramPhaseData(Phases,Histograms,Print=False)
124    hapList = hapDict.keys()
125    hapList.sort()
126    histVary,histDict,controlDict = G2str.GetHistogramData(Histograms,Print=False)
127    histList = []
128    for item in histDict:
129        if item.split(':')[2] not in ['Omega','Type','Chi','Phi','Azimuth','Gonio. radius','Lam1','Lam2','Back']:
130            histList.append(item)
131    histList.sort()
132    Indx = {}
133    scope = {}                          #filled out later
134    G2frame.Page = [0,'phs']
135   
136    def GetPHlegends(Phases,Histograms):
137        plegend = '\n In p::name'
138        hlegend = '\n In :h:name'
139        phlegend = '\n In p:h:name'
140        for phase in Phases:
141            plegend += '\n p:: = '+str(Phases[phase]['pId'])+':: for '+phase
142            count = 0
143            for histogram in Phases[phase]['Histograms']:
144                if count < 3:
145                    phlegend += '\n p:h: = '+str(Phases[phase]['pId'])+':'+str(Histograms[histogram]['hId'])+': for '+phase+' in '+histogram
146                else:
147                    phlegend += '\n ... etc.'
148                    break
149                count += 1
150        count = 0
151        for histogram in Histograms:
152            if count < 3:
153                hlegend += '\n :h: = :'+str(Histograms[histogram]['hId'])+': for '+histogram
154            else:
155                hlegend += '\n ... etc.'
156                break
157            count += 1
158        return plegend,hlegend,phlegend
159       
160    def FindEquivVarb(name,nameList):
161        outList = []
162        phlist = []
163        items = name.split(':')
164        namelist = [items[2],]
165        if 'dA' in name:
166            namelist = ['dAx','dAy','dAz']
167        elif 'AU' in name:
168            namelist = ['AUiso','AU11','AU22','AU33','AU12','AU13','AU23']
169        for item in nameList:
170            keys = item.split(':')
171            if keys[0] not in phlist:
172                phlist.append(keys[0])
173            if keys[2] in namelist and item != name:
174                outList.append(item)
175        if items[1]:
176            for key in phlist:
177                outList.append(key+':all:'+items[2])
178        return outList
179       
180    def SelectVarbs(page,FrstVarb,varList,legend,constType):
181        '''Select variables used in Constraints after one variable has
182        been selected which determines the appropriate variables to be
183        used here. Then creates the constraint and adds it to the
184        constraints list.
185        Called from OnAddEquivalence, OnAddFunction & OnAddConstraint
186        '''
187        #future -  add 'all:all:name', '0:all:name', etc. to the varList
188        if page[1] == 'phs':
189            atchoice = [item+' for '+phaseAtNames[item] for item in varList]
190            atchoice += [FrstVarb+' for all']
191            atchoice += [FrstVarb+' for all '+atype for atype in TypeList]
192            dlg = wx.MultiChoiceDialog(G2frame,'Select more variables:'+legend,
193                'Constrain '+FrstVarb+' and...',atchoice)
194        else:
195            dlg = wx.MultiChoiceDialog(G2frame,'Select more variables:'+legend,
196                'Constrain '+FrstVarb+' and...',varList)
197        varbs = [FrstVarb,]
198        if dlg.ShowModal() == wx.ID_OK:
199            sel = dlg.GetSelections()
200            try:
201                for x in sel:
202                    if ':all:' in varList[x]:       #a histogram 'all' - supercedes any individual selection
203                        varbs = [FrstVarb,]
204                        items = varList[x].split(':')
205                        for item in varList:
206                            if items[0] == item.split(':')[0] and ':all:' not in item:
207                                varbs.append(item)
208                        break
209                    else:
210                        varbs.append(varList[x])
211            except IndexError:      # one of the 'all' chosen - supercedes any individual selection
212                varbs = [FrstVarb,]
213                Atypes = []
214                for x in sel:
215                    item = atchoice[x]
216                    if 'all' in item:
217                        Atypes.append(item.split('all')[1].strip())
218                if '' in Atypes:
219                    varbs += varList
220                else:
221                    for item in varList:
222                        if phaseAtTypes[item] in Atypes:
223                            varbs.append(item) 
224        dlg.Destroy()
225        if len(varbs) > 1:
226            if 'equivalence' in constType:
227                constr = [[1.0,FrstVarb]]
228                for item in varbs[1:]:
229                    constr += [[1.0,item]]
230                return [constr+[None,None,'e']]      # list of equivalent variables & mults
231            elif 'function' in constType:
232                constr = map(list,zip([1.0 for i in range(len(varbs))],varbs))
233                return [constr+[None,False,'f']]         #just one constraint
234            else:       #'constraint'
235                constr = map(list,zip([1.0 for i in range(len(varbs))],varbs))
236                return [constr+[1.0,None,'c']]          #just one constraint - default sum to one
237        return []
238
239    def CheckAddedConstraint(newcons):
240        '''Check a new constraint that has just been input.
241        If there is an error display a message and give the user a
242        choice to keep or discard the last entry (why keep? -- they
243        may want to delete something else or edit multipliers).
244        Since the varylist is not available, no warning messages
245        should be generated.
246        Returns True if constraint should be added
247        '''
248        allcons = []
249        for key in 'Hist','HAP','Phase':
250            allcons += data[key]
251        allcons += newcons
252        if not len(allcons): return True
253        G2mv.InitVars()   
254        constDictList,fixedList,ignored = G2str.ProcessConstraints(allcons)
255        errmsg, warnmsg = G2mv.CheckConstraints('',constDictList,fixedList)
256        if errmsg:
257            res = G2frame.ErrorDialog('Constraint Error',
258                'Error with newly added constraint:\n'+errmsg+
259                '\n\nDiscard newly added constraint?',parent=G2frame.dataFrame,
260                wtype=wx.YES_NO)
261            return res != wx.ID_YES
262        elif warnmsg:
263            print 'Unexpected contraint warning:\n',warnmsg
264        return True
265
266    def CheckChangedConstraint():
267        '''Check all constraints after an edit has been made.
268        If there is an error display a message and give the user a
269        choice to keep or discard the last edit.
270        Since the varylist is not available, no warning messages
271        should be generated.
272        Returns True if the edit should be retained
273        '''
274        allcons = []
275        for key in 'Hist','HAP','Phase':
276            allcons += data[key]
277        if not len(allcons): return True
278        G2mv.InitVars()   
279        constDictList,fixedList,ignored = G2str.ProcessConstraints(allcons)
280        errmsg, warnmsg = G2mv.CheckConstraints('',constDictList,fixedList)
281        if errmsg:
282            res = G2frame.ErrorDialog('Constraint Error',
283                'Error after editing constraint:\n'+errmsg+
284                '\n\nDiscard last constraint edit?',parent=G2frame.dataFrame,
285                wtype=wx.YES_NO)
286            return res != wx.ID_YES
287        elif warnmsg:
288            print 'Unexpected contraint warning:\n',warnmsg
289        return True
290             
291    def OnAddHold(event):
292        '''add a Hold constraint'''
293        for phase in Phases:
294            Phase = Phases[phase]
295            Atoms = Phase['Atoms']
296        constr = []
297        page = G2frame.Page
298        choice = scope[page[1]]
299        if page[1] == 'phs':
300            atchoice = [item+' for '+phaseAtNames[item] for item in choice[2]]
301            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],atchoice)
302        else:   
303            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],choice[2])
304        if dlg.ShowModal() == wx.ID_OK:
305            sel = dlg.GetSelection()
306            FrstVarb = choice[2][sel]
307            newcons = [[[0.0,FrstVarb],None,None,'h']]
308            if CheckAddedConstraint(newcons):
309                data[choice[3]] += newcons
310        dlg.Destroy()
311        choice[4]()
312       
313    def OnAddEquivalence(event):
314        '''add an Equivalence constraint'''
315        constr = []
316        page = G2frame.Page
317        choice = scope[page[1]]
318        if page[1] == 'phs':
319            atchoice = [item+' for '+phaseAtNames[item] for item in choice[2]]
320            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],atchoice)
321        else:   
322            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],choice[2])
323        if dlg.ShowModal() == wx.ID_OK:
324            sel = dlg.GetSelection()
325            FrstVarb = choice[2][sel]
326            moreVarb = FindEquivVarb(FrstVarb,choice[2])
327            newcons = SelectVarbs(page,FrstVarb,moreVarb,choice[1],'equivalence')
328            if len(newcons) > 0:
329                if CheckAddedConstraint(newcons):
330                    data[choice[3]] += newcons
331        dlg.Destroy()
332        choice[4]()
333   
334    def OnAddFunction(event):
335        '''add a Function (new variable) constraint'''
336        constr = []
337        page = G2frame.Page
338        choice = scope[page[1]]
339        if page[1] == 'phs':
340            atchoice = [item+' for '+phaseAtNames[item] for item in choice[2]]
341            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],atchoice)
342        else:   
343            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],choice[2])
344        if dlg.ShowModal() == wx.ID_OK:
345            sel = dlg.GetSelection()
346            FrstVarb = choice[2][sel]
347            moreVarb = FindEquivVarb(FrstVarb,choice[2])
348            newcons = SelectVarbs(page,FrstVarb,moreVarb,choice[1],'function')
349            if len(newcons) > 0:
350                if CheckAddedConstraint(newcons):
351                    data[choice[3]] += newcons
352        dlg.Destroy()
353        choice[4]()
354                       
355    def OnAddConstraint(event):
356        '''add a constraint equation to the constraints list'''
357        constr = []
358        page = G2frame.Page
359        choice = scope[page[1]]
360        if page[1] == 'phs':
361            atchoice = [item+' for '+phaseAtNames[item] for item in choice[2]]
362            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],atchoice)
363        else:   
364            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],choice[2])
365        if dlg.ShowModal() == wx.ID_OK:
366            sel = dlg.GetSelection()
367            FrstVarb = choice[2][sel]
368            moreVarb = FindEquivVarb(FrstVarb,choice[2])
369            newcons = SelectVarbs(page,FrstVarb,moreVarb,choice[1],'constraint')
370            if len(newcons) > 0:
371                if CheckAddedConstraint(newcons):
372                    data[choice[3]] += newcons
373        dlg.Destroy()
374        choice[4]()
375                       
376    def ConstSizer(name,pageDisplay):
377        '''This creates a sizer displaying all of the constraints entered
378        '''
379        constSizer = wx.FlexGridSizer(1,4,0,0)
380        maxlen = 70 # characters before wrapping a constraint
381        for Id,item in enumerate(data[name]):
382            eqString = ['',]
383            if item[-1] == 'h':
384                constSizer.Add((5,5),0)              # blank space for edit button
385                typeString = ' FIXED   '
386                eqString[-1] = item[0][1]+'   '
387            elif isinstance(item[-1],str):
388                constEdit = wx.Button(pageDisplay,-1,'Edit',style=wx.BU_EXACTFIT)
389                constEdit.Bind(wx.EVT_BUTTON,OnConstEdit)
390                constSizer.Add(constEdit)            # edit button
391                Indx[constEdit.GetId()] = [Id,name]
392                if item[-1] == 'f':
393                    for term in item[:-3]:
394                        if len(eqString[-1]) > maxlen:
395                            eqString.append(' ')
396                        m = term[0]
397                        if eqString[-1] != '':
398                            if m >= 0:
399                                eqString[-1] += ' + '
400                            else:
401                                eqString[-1] += ' - '
402                                m = abs(m)
403                        eqString[-1] += '%.3f*%s '%(m,term[1])
404                    typeString = ' NEWVAR  '
405                    eqString[-1] += ' = New Variable   '
406                elif item[-1] == 'c':
407                    for term in item[:-3]:
408                        if len(eqString[-1]) > maxlen:
409                            eqString.append(' ')
410                        if eqString[-1] != '':
411                            if term[0] > 0:
412                                eqString[-1] += ' + '
413                            else:
414                                eqString[-1] += ' - '
415                        eqString[-1] += '%.3f*%s '%(abs(term[0]),term[1])
416                    typeString = ' CONSTR  '
417                    eqString[-1] += ' = %.3f'%(item[-3])+'  '
418                elif item[-1] == 'e':
419                    for term in item[:-3]:
420                        if term[0] == 0: term[0] = 1.0
421                        if len(eqString[-1]) > maxlen:
422                            eqString.append(' ')
423                        if eqString[-1] == '':
424                            eqString[-1] += '%s '%(term[1])
425                            first = term[0]
426                        else:
427                            eqString[-1] += ' = %.3f*%s '%(first/term[0],term[1])
428                    typeString = ' EQUIV   '
429                else:
430                    print 'Unexpected constraint',item
431            else:
432                print 'Removing old-style constraints'
433                data[name] = []
434                return constSizer
435            constDel = wx.Button(pageDisplay,-1,'Delete',style=wx.BU_EXACTFIT)
436            constDel.Bind(wx.EVT_BUTTON,OnConstDel)
437            Indx[constDel.GetId()] = [Id,name]
438            constSizer.Add(constDel)             # delete button
439            constSizer.Add(wx.StaticText(pageDisplay,-1,typeString),0,wx.ALIGN_CENTER_VERTICAL)
440            EqSizer = wx.BoxSizer(wx.VERTICAL)
441            for s in eqString:
442                EqSizer.Add(wx.StaticText(pageDisplay,-1,s),0,wx.ALIGN_CENTER_VERTICAL)
443            constSizer.Add(EqSizer,0,wx.ALIGN_CENTER_VERTICAL)
444            # if item[-1] == 'f':
445            #     constRef = wx.CheckBox(pageDisplay,-1,label=' Refine?')
446            #     constRef.SetValue(item[-2])
447            #     constRef.Bind(wx.EVT_CHECKBOX,OnConstRef)
448            #     Indx[constRef.GetId()] = item
449            #     constSizer.Add(constRef)
450            # else:
451            #     constSizer.Add((5,5),0)
452        return constSizer
453               
454    # def OnConstRef(event):
455    #     Obj = event.GetEventObject()
456    #     Indx[Obj.GetId()][-2] = Obj.GetValue()
457       
458    def OnConstDel(event):
459        Obj = event.GetEventObject()
460        Id,name = Indx[Obj.GetId()]
461        del(data[name][Id])
462        OnPageChanged(None)       
463       
464    def OnConstEdit(event):
465        '''Called to edit an individual contraint by the Edit button'''
466        Obj = event.GetEventObject()
467        Id,name = Indx[Obj.GetId()]
468        sep = '*'
469        if data[name][Id][-1] == 'f':
470            items = data[name][Id][:-3]+[[],]
471            constType = 'New Variable'
472            lbl = 'Enter value for each term in constraint; sum = new variable'
473        elif data[name][Id][-1] == 'c':
474            items = data[name][Id][:-3]+[
475                [data[name][Id][-3],'fixed value ='],[]]
476            constType = 'Constraint'
477            lbl = 'Edit value for each term in constant constraint sum'
478        elif data[name][Id][-1] == 'e':
479            items = data[name][Id][:-3]+[[],]
480            constType = 'Equivalence'
481            lbl = 'The following terms are set to be equal:'
482            sep = '/'
483        else:
484            return
485        dlg = G2frame.ConstraintDialog(G2frame.dataFrame,constType,lbl,items,sep)
486        try:
487            if dlg.ShowModal() == wx.ID_OK:
488                prev = data[name][Id]
489                result = dlg.GetData()
490                if data[name][Id][-1] == 'c':
491                    data[name][Id][:-3] = result[:-2]
492                    data[name][Id][-3] = result[-2][0]
493                else:
494                    data[name][Id][:-3] = result[:-1]
495                if not CheckChangedConstraint():
496                    data[name][Id] = prev
497        except:
498            import traceback
499            print traceback.format_exc()
500        finally:
501            dlg.Destroy()           
502        OnPageChanged(None)                     
503   
504    def UpdateHAPConstr():
505        '''Responds to press on Histogram/Phase Constraints tab,
506        shows constraints in data window'''
507        HAPConstr.DestroyChildren()
508        HAPDisplay = wx.Panel(HAPConstr)
509        HAPSizer = wx.BoxSizer(wx.VERTICAL)
510        HAPSizer.Add((5,5),0)
511        HAPSizer.Add(ConstSizer('HAP',HAPDisplay))
512        HAPDisplay.SetSizer(HAPSizer,True)
513        Size = HAPSizer.GetMinSize()
514        Size[0] += 40
515        Size[1] = max(Size[1],250) + 20
516        HAPDisplay.SetSize(Size)
517        # scroll bar not working, at least not on Mac
518        HAPConstr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
519        Size[1] = min(Size[1],250)
520        G2frame.dataFrame.setSizePosLeft(Size)
521       
522    def UpdateHistConstr():
523        '''Responds to press on Histogram Constraints tab,
524        shows constraints in data window'''
525        HistConstr.DestroyChildren()
526        HistDisplay = wx.Panel(HistConstr)
527        HistSizer = wx.BoxSizer(wx.VERTICAL)
528        HistSizer.Add((5,5),0)       
529        HistSizer.Add(ConstSizer('Hist',HistDisplay))
530        HistDisplay.SetSizer(HistSizer,True)
531        Size = HistSizer.GetMinSize()
532        Size[0] += 40
533        Size[1] = max(Size[1],250) + 20
534        HistDisplay.SetSize(Size)
535        HistConstr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
536        Size[1] = min(Size[1],250)
537        G2frame.dataFrame.setSizePosLeft(Size)
538       
539    def UpdatePhaseConstr():
540        '''Responds to press on Phase Constraint tab,
541        shows constraints in data window'''
542        PhaseConstr.DestroyChildren()
543        PhaseDisplay = wx.Panel(PhaseConstr)
544        PhaseSizer = wx.BoxSizer(wx.VERTICAL)
545        PhaseSizer.Add((5,5),0)       
546        PhaseSizer.Add(ConstSizer('Phase',PhaseDisplay))
547        PhaseDisplay.SetSizer(PhaseSizer,True)
548        Size = PhaseSizer.GetMinSize()
549        Size[0] += 40
550        Size[1] = max(Size[1],250) + 20
551        PhaseDisplay.SetSize(Size)
552        PhaseConstr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
553        Size[1] = min(Size[1],250)
554        G2frame.dataFrame.setSizePosLeft(Size)
555   
556    def OnPageChanged(event):
557        if event:       #page change event!
558            page = event.GetSelection()
559        else:
560            page = G2frame.dataDisplay.GetSelection()
561        oldPage = G2frame.dataDisplay.ChangeSelection(page)
562        text = G2frame.dataDisplay.GetPageText(page)
563        if text == 'Histogram/Phase constraints':
564            G2frame.Page = [page,'hap']
565            UpdateHAPConstr()
566        elif text == 'Histogram constraints':
567            G2frame.Page = [page,'hst']
568            UpdateHistConstr()
569        elif text == 'Phase constraints':
570            G2frame.Page = [page,'phs']
571            UpdatePhaseConstr()
572
573    def SetStatusLine(text):
574        Status.SetStatusText(text)                                     
575       
576    plegend,hlegend,phlegend = GetPHlegends(Phases,Histograms)
577    scope = {'hst':['Histogram contraints:',hlegend,histList,'Hist',UpdateHistConstr],
578        'hap':['Histogram * Phase contraints:',phlegend,hapList,'HAP',UpdateHAPConstr],
579        'phs':['Phase contraints:',plegend,phaseList,'Phase',UpdatePhaseConstr]}
580    if G2frame.dataDisplay:
581        G2frame.dataDisplay.Destroy()
582    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ConstraintMenu)
583    G2frame.dataFrame.SetLabel('Constraints')
584    if not G2frame.dataFrame.GetStatusBar():
585        Status = G2frame.dataFrame.CreateStatusBar()
586    SetStatusLine('')
587   
588    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ConstraintMenu)
589    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddConstraint, id=G2gd.wxID_CONSTRAINTADD)
590    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddFunction, id=G2gd.wxID_FUNCTADD)
591    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddEquivalence, id=G2gd.wxID_EQUIVADD)
592    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddHold, id=G2gd.wxID_HOLDADD)
593    G2frame.dataDisplay = G2gd.GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
594   
595    PhaseConstr = wx.ScrolledWindow(G2frame.dataDisplay)
596    G2frame.dataDisplay.AddPage(PhaseConstr,'Phase constraints')
597    HAPConstr = wx.ScrolledWindow(G2frame.dataDisplay)
598    G2frame.dataDisplay.AddPage(HAPConstr,'Histogram/Phase constraints')
599    HistConstr = wx.ScrolledWindow(G2frame.dataDisplay)
600    G2frame.dataDisplay.AddPage(HistConstr,'Histogram constraints')
601    UpdatePhaseConstr()
602
603    G2frame.dataDisplay.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, OnPageChanged)
604    # validate all the constrants -- should not see any errors here normally
605    allcons = []
606    for key in 'Hist','HAP','Phase':
607        allcons += data[key]
608    if not len(allcons): return
609    G2mv.InitVars()   
610    constDictList,fixedList,ignored = G2str.ProcessConstraints(allcons)
611    errmsg, warnmsg = G2mv.CheckConstraints('',constDictList,fixedList)
612    if errmsg:
613        G2frame.ErrorDialog('Constraint Error','Error in constraints:\n'+errmsg,
614            parent=G2frame.dataFrame)
615    elif warnmsg:
616        print 'Unexpected contraint warning:\n',warnmsg
617       
618################################################################################
619#### Rigid bodies
620################################################################################
621
622def UpdateRigidBodies(G2frame,data):
623    '''Called when Rigid bodies tree item is selected.
624    Displays the rigid bodies in the data window
625    '''
626    if not data:
627        data.update({'Vector':{'AtInfo':{}},'Residue':{'AtInfo':{}},'Z-matrix':{'AtInfo':{}}})       #empty dict - fill it
628           
629    Indx = {}
630    plotDefaults = {'oldxy':[0.,0.],'Quaternion':[1.,0.,0.,0.],'cameraPos':30.,'viewDir':[0,0,1],}
631
632    def OnPageChanged(event):
633        if event:       #page change event!
634            page = event.GetSelection()
635        else:
636            page = G2frame.dataDisplay.GetSelection()
637        oldPage = G2frame.dataDisplay.ChangeSelection(page)
638        text = G2frame.dataDisplay.GetPageText(page)
639        if text == 'Vector rigid bodies':
640            G2frame.dataFrame.RigidBodyMenu.Remove(0)   #NB: wx.MenuBar.Replace gives error
641            G2frame.dataFrame.RigidBodyMenu.Insert(0,G2frame.dataFrame.VectorRBEdit,title='Edit')
642            G2frame.Page = [page,'vrb']
643            UpdateVectorRB()
644        elif text == 'Residue rigid bodies':
645            G2frame.dataFrame.RigidBodyMenu.Remove(0)
646            G2frame.dataFrame.RigidBodyMenu.Insert(0,G2frame.dataFrame.ResidueRBMenu,title='Edit')
647            G2frame.Page = [page,'rrb']
648            UpdateResidueRB()
649        elif text == 'Z-matrix rigid bodies':
650            G2frame.dataFrame.RigidBodyMenu.Remove(0)
651            G2frame.dataFrame.RigidBodyMenu.Insert(0,G2frame.dataFrame.ZMatrixRBMenu,title='Edit')
652            G2frame.Page = [page,'zrb']
653            UpdateZMatrixRB()
654           
655    def getMacroFile(macName):
656        defDir = os.path.join(os.path.split(__file__)[0],'GSASIImacros')
657        dlg = wx.FileDialog(G2frame,message='Choose '+macName+' rigid body macro file',
658            defaultDir=defDir,defaultFile="",wildcard="GSAS-II macro file (*.mac)|*.mac",
659            style=wx.OPEN | wx.CHANGE_DIR)
660        try:
661            if dlg.ShowModal() == wx.ID_OK:
662                macfile = dlg.GetPath()
663                macro = open(macfile,'Ur')
664                head = macro.readline()
665                if macName not in head:
666                    print head
667                    print '**** ERROR - wrong restraint macro file selected, try again ****'
668                    macro = []
669            else: # cancel was pressed
670                macro = []
671        finally:
672            dlg.Destroy()
673        return macro        #advanced past 1st line
674       
675    def getTextFile():
676        defDir = os.path.join(os.path.split(__file__)[0],'GSASIImacros')
677        dlg = wx.FileDialog(G2frame,message='Choose rigid body text file',
678            defaultDir=defDir,defaultFile="",wildcard="GSAS-II text file (*.txt)|*.txt",
679            style=wx.OPEN | wx.CHANGE_DIR)
680        try:
681            if dlg.ShowModal() == wx.ID_OK:
682                txtfile = dlg.GetPath()
683                text = open(txtfile,'Ur')
684            else: # cancel was pressed
685                text = []
686        finally:
687            dlg.Destroy()
688        return text
689       
690    def OnAddRigidBody(event):
691        page = G2frame.dataDisplay.GetSelection()
692        if 'Vector' in G2frame.dataDisplay.GetPageText(page):
693            AddVectorRB()
694        elif 'Residue' in G2frame.dataDisplay.GetPageText(page):
695            AddResidueRB()
696        elif 'Z-matrix' in G2frame.dataDisplay.GetPageText(page):
697            AddZMatrixRB()
698           
699    def OnImportRigidBody(event):
700        page = G2frame.dataDisplay.GetSelection()
701        if 'Vector' in G2frame.dataDisplay.GetPageText(page):
702            pass
703        elif 'Residue' in G2frame.dataDisplay.GetPageText(page):
704            ImportResidueRB()
705        elif 'Z-matrix' in G2frame.dataDisplay.GetPageText(page):
706            pass
707                       
708    def AddVectorRB():
709        AtInfo = data['Vector']['AtInfo']
710        dlg = MultiIntegerDialog(G2frame.dataDisplay,'New Rigid Body',['No. atoms','No. translations'],[1,1])
711        if dlg.ShowModal() == wx.ID_OK:
712            nAtoms,nTrans = dlg.GetValues()
713            vectorRB = data['Vector']
714            rbId = ran.randint(0,sys.maxint)
715            vecMag = [1.0 for i in range(nTrans)]
716            vecRef = [False for i in range(nTrans)]
717            vecVal = [np.zeros((nAtoms,3)) for j in range(nTrans)]
718            rbTypes = ['C' for i in range(nAtoms)]
719            Info = G2elem.GetAtomInfo('C')
720            AtInfo['C'] = [Info['Drad'],Info['Color']]
721            data['Vector'][rbId] = {'RBname':'UNKRB','VectMag':vecMag,
722                'VectRef':vecRef,'rbTypes':rbTypes,'rbVect':vecVal}
723        dlg.Destroy()
724        UpdateVectorRB()
725       
726    def AddResidueRB():
727        AtInfo = data['Residue']['AtInfo']
728        macro = getMacroFile('rigid body')
729        if not macro:
730            return
731        macStr = macro.readline()
732        while macStr:
733            items = macStr.split()
734            if 'I' == items[0]:
735                rbId = ran.randint(0,sys.maxint)
736                rbName = items[1]
737                rbTypes = []
738                rbXYZ = []
739                rbSeq = []
740                atNames = []
741                nAtms,nSeq,nOrig,mRef,nRef = [int(items[i]) for i in [2,3,4,5,6]]
742                for iAtm in range(nAtms):
743                    macStr = macro.readline().split()
744                    atName = macStr[0]
745                    atType = macStr[1]
746                    atNames.append(atName)
747                    rbXYZ.append([float(macStr[i]) for i in [2,3,4]])
748                    rbTypes.append(atType)
749                    if atType not in AtInfo:
750                        Info = G2elem.GetAtomInfo(atType)
751                        AtInfo[atType] = [Info['Drad'],Info['Color']]
752                rbXYZ = np.array(rbXYZ)-np.array(rbXYZ[nOrig-1])
753                for iSeq in range(nSeq):
754                    macStr = macro.readline().split()
755                    mSeq = int(macStr[0])
756                    for jSeq in range(mSeq):
757                        macStr = macro.readline().split()
758                        iBeg = int(macStr[0])-1
759                        iFin = int(macStr[1])-1
760                        angle = 0.0
761                        nMove = int(macStr[2])
762                        iMove = [int(macStr[i])-1 for i in range(3,nMove+3)]
763                        rbSeq.append([iBeg,iFin,angle,iMove])
764                data['Residue'][rbId] = {'RBname':rbName,'rbXYZ':rbXYZ,'rbTypes':rbTypes,
765                    'atNames':atNames,'rbRef':[nOrig-1,mRef-1,nRef-1],'rbSeq':rbSeq,'SelSeq':[0,0]}
766                print 'Rigid body '+rbName+' added'
767            macStr = macro.readline()
768        macro.close()
769        UpdateResidueRB()
770       
771    def ImportResidueRB():
772        AtInfo = data['Residue']['AtInfo']
773        text = getTextFile()
774        if not text:
775            return
776        rbId = ran.randint(0,sys.maxint)
777        rbTypes = []
778        rbXYZ = []
779        rbSeq = []
780        atNames = []
781        txtStr = text.readline()
782        items = txtStr.split()
783        while len(items):
784            atName = items[0]
785            atType = items[1]
786            atNames.append(atName)
787            rbXYZ.append([float(items[i]) for i in [2,3,4]])
788            rbTypes.append(atType)
789            if atType not in AtInfo:
790                Info = G2elem.GetAtomInfo(atType)
791                AtInfo[atType] = [Info['Drad'],Info['Color']]
792            txtStr = text.readline()
793            items = txtStr.split()
794        rbXYZ = np.array(rbXYZ)-np.array(rbXYZ[0])
795        data['Residue'][rbId] = {'RBname':'UNKRB','rbXYZ':rbXYZ,'rbTypes':rbTypes,
796            'atNames':atNames,'rbRef':[0,1,2],'rbSeq':[],'SelSeq':[0,0]}
797        print 'Rigid body UNKRB added'
798        text.close()
799        UpdateResidueRB()
800       
801    def FindNeighbors(Orig,XYZ,atTypes,atNames,AtInfo):
802        Radii = []
803        for Atype in atTypes:
804            Radii.append(AtInfo[Atype][0])
805        Radii = np.array(Radii)
806        Neigh = []
807        Dx = XYZ-XYZ[Orig]
808        dist = np.sqrt(np.sum(Dx**2,axis=1))
809        sumR = Radii[Orig]+Radii
810        IndB = ma.nonzero(ma.masked_greater(dist-0.85*sumR,0.))
811        for j in IndB[0]:
812            if j != Orig:
813                Neigh.append(atNames[j])
814        return Neigh
815       
816    def FindAllNeighbors(XYZ,atTypes,atNames,AtInfo):
817        NeighDict = {}
818        for iat,xyz in enumerate(atNames):
819            NeighDict[atNames[iat]] = FindNeighbors(iat,XYZ,atTypes,atNames,AtInfo)
820        return NeighDict
821       
822    def FindRiding(Orig,Pivot,NeighDict):
823        riding = [Orig,Pivot]
824        iAdd = 1
825        new = True
826        while new:
827            newAtms = NeighDict[riding[iAdd]]
828            for At in newAtms:
829                new = False
830                if At not in riding:
831                    riding.append(At)
832                    new = True
833            iAdd += 1
834            if iAdd < len(riding):
835                new = True
836        return riding[2:]
837                       
838    def OnDefineTorsSeq(event):
839        rbKeys = data['Residue'].keys()
840        rbKeys.remove('AtInfo')
841        rbNames = [data['Residue'][k]['RBname'] for k in rbKeys]
842        rbIds = dict(zip(rbNames,rbKeys))
843        rbNames.sort()
844        rbId = 0
845        if len(rbNames) > 1:
846            dlg = wx.SingleChoiceDialog(G2frame,'Select rigid body for torsion sequence','Torsion sequence',rbNames)
847            if dlg.ShowModal() == wx.ID_OK:
848                sel = dlg.GetSelection()
849                rbId = rbIds[rbNames[sel]]
850                rbData = data['Residue'][rbId]
851            dlg.Destroy()
852        else:
853            rbId = rbIds[rbNames[0]]
854            rbData = data['Residue'][rbId]
855        if not len(rbData):
856            return
857        atNames = rbData['atNames']
858        AtInfo = data['Residue']['AtInfo']
859        atTypes = rbData['rbTypes']
860        XYZ = rbData['rbXYZ']
861        neighDict = FindAllNeighbors(XYZ,atTypes,atNames,AtInfo)
862        TargList = []           
863        dlg = wx.SingleChoiceDialog(G2frame,'Select origin atom for torsion sequence','Origin atom',rbData['atNames'])
864        if dlg.ShowModal() == wx.ID_OK:
865            Orig = dlg.GetSelection()
866            xyz = XYZ[Orig]
867            TargList = neighDict[atNames[Orig]]
868        dlg.Destroy()
869        if not len(TargList):
870            return
871        dlg = wx.SingleChoiceDialog(G2frame,'Select pivot atom for torsion sequence','Pivot atom',TargList)
872        if dlg.ShowModal() == wx.ID_OK:
873            Piv = atNames.index(TargList[dlg.GetSelection()])
874            riding = FindRiding(atNames[Orig],atNames[Piv],neighDict)
875            Riding = []
876            for atm in riding:
877                Riding.append(atNames.index(atm))
878            rbData['rbSeq'].append([Orig,Piv,0.0,Riding])           
879        dlg.Destroy()
880        UpdateResidueRB()
881       
882
883    def AddZMatrixRB():
884        pass
885
886    def UpdateVectorRB():
887        AtInfo = data['Vector']['AtInfo']
888        SetStatusLine(' You may use e.g. "sind(60)", "cos(60)", "c60" or "s60" for a vector entry')
889        def rbNameSizer(rbId,rbData):
890
891            def OnRBName(event):
892                Obj = event.GetEventObject()
893                rbId = Indx[Obj.GetId()]
894                rbData['RBname'] = Obj.GetValue()
895               
896            def OnDelRB(event):
897                Obj = event.GetEventObject()
898                rbId = Indx[Obj.GetId()]
899                del data['Vector'][rbId]
900                wx.CallAfter(UpdateVectorRB)
901               
902            def OnPlotRB(event):
903                Obj = event.GetEventObject()
904                rbId = Indx[Obj.GetId()]
905                Obj.SetValue(False)
906                G2plt.PlotRigidBody(G2frame,'Vector',AtInfo,rbData,plotDefaults)
907           
908            nameSizer = wx.BoxSizer(wx.HORIZONTAL)
909            nameSizer.Add(wx.StaticText(VectorRBDisplay,-1,'Rigid body name: '),
910                0,wx.ALIGN_CENTER_VERTICAL)
911            RBname = wx.TextCtrl(VectorRBDisplay,-1,rbData['RBname'])
912            Indx[RBname.GetId()] = rbId
913            RBname.Bind(wx.EVT_TEXT_ENTER,OnRBName)
914            RBname.Bind(wx.EVT_KILL_FOCUS,OnRBName)
915            nameSizer.Add(RBname,0,wx.ALIGN_CENTER_VERTICAL)
916            nameSizer.Add((5,0),)
917            plotRB = wx.CheckBox(VectorRBDisplay,-1,'Plot?')
918            Indx[plotRB.GetId()] = rbId
919            plotRB.Bind(wx.EVT_CHECKBOX,OnPlotRB)
920            nameSizer.Add(plotRB,0,wx.ALIGN_CENTER_VERTICAL)
921            nameSizer.Add((5,0),)
922            delRB = wx.CheckBox(VectorRBDisplay,-1,'Delete?')
923            Indx[delRB.GetId()] = rbId
924            delRB.Bind(wx.EVT_CHECKBOX,OnDelRB)
925            nameSizer.Add(delRB,0,wx.ALIGN_CENTER_VERTICAL)
926            return nameSizer
927           
928        def rbVectMag(rbId,imag,rbData):
929           
930            def OnRBVectorMag(event):
931                Obj = event.GetEventObject()
932                rbId,imag = Indx[Obj.GetId()]
933                try:
934                    val = float(Obj.GetValue())
935                    if val <= 0.:
936                        raise ValueError
937                    rbData['VectMag'][imag] = val
938                except ValueError:
939                    pass
940                Obj.SetValue('%8.3f'%(val))
941                UpdateVectorRB()
942                G2plt.PlotRigidBody(G2frame,'Vector',AtInfo,data['Vector'][rbId],plotDefaults)
943               
944            def OnRBVectorRef(event):
945                Obj = event.GetEventObject()
946                rbId,imag = Indx[Obj.GetId()]
947                rbData['VectRef'][imag] = Obj.GetValue()
948                       
949            magSizer = wx.wx.BoxSizer(wx.HORIZONTAL)
950            magSizer.Add(wx.StaticText(VectorRBDisplay,-1,'Translation magnitude: '),
951                0,wx.ALIGN_CENTER_VERTICAL)
952            magValue = wx.TextCtrl(VectorRBDisplay,-1,'%8.3f'%(rbData['VectMag'][imag]))
953            Indx[magValue.GetId()] = [rbId,imag]
954            magValue.Bind(wx.EVT_TEXT_ENTER,OnRBVectorMag)
955            magValue.Bind(wx.EVT_KILL_FOCUS,OnRBVectorMag)
956            magSizer.Add(magValue,0,wx.ALIGN_CENTER_VERTICAL)
957            magSizer.Add((5,0),)
958            magref = wx.CheckBox(VectorRBDisplay,-1,label=' Refine?') 
959            magref.SetValue(rbData['VectRef'][imag])
960            magref.Bind(wx.EVT_CHECKBOX,OnRBVectorRef)
961            Indx[magref.GetId()] = [rbId,imag]
962            magSizer.Add(magref,0,wx.ALIGN_CENTER_VERTICAL)
963            return magSizer
964           
965        def rbVectors(rbId,imag,mag,XYZ,rbData):
966
967            def TypeSelect(event):
968                AtInfo = data['Vector']['AtInfo']
969                r,c = event.GetRow(),event.GetCol()
970                if vecGrid.GetColLabelValue(c) == 'Type':
971                    PE = G2elemGUI.PickElement(G2frame,oneOnly=True)
972                    if PE.ShowModal() == wx.ID_OK:
973                        if PE.Elem != 'None':
974                            El = PE.Elem.strip().lower().capitalize()
975                            if El not in AtInfo:
976                                Info = G2elem.GetAtomInfo(El)
977                                AtInfo[El] = [Info['Drad'],Info['Color']]
978                            rbData['rbTypes'][r] = El
979                            vecGrid.SetCellValue(r,c,El)
980                    PE.Destroy()
981                wx.CallAfter(UpdateVectorRB)
982
983            def ChangeCell(event):
984                r,c =  event.GetRow(),event.GetCol()
985                if r >= 0 and (0 <= c < 3):
986                    try:
987                        val = float(vecGrid.GetCellValue(r,c))
988                        rbData['rbVect'][imag][r][c] = val
989                    except ValueError:
990                        pass
991                wx.CallAfter(UpdateVectorRB)
992
993            vecSizer = wx.BoxSizer()
994            Types = 3*[wg.GRID_VALUE_FLOAT+':10,5',]+[wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,5',]
995            colLabels = ['Vector x','Vector y','Vector z','Type','Cart x','Cart y','Cart z']
996            table = []
997            rowLabels = []
998            for ivec,xyz in enumerate(rbData['rbVect'][imag]):
999                table.append(list(xyz)+[rbData['rbTypes'][ivec],]+list(XYZ[ivec]))
1000                rowLabels.append(str(ivec))
1001            vecTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
1002            vecGrid = G2gd.GSGrid(VectorRBDisplay)
1003            vecGrid.SetTable(vecTable, True)
1004            vecGrid.Bind(wg.EVT_GRID_CELL_CHANGE, ChangeCell)
1005            if not imag:
1006                vecGrid.Bind(wg.EVT_GRID_CELL_LEFT_DCLICK, TypeSelect)
1007            attr = wx.grid.GridCellAttr()
1008            attr.SetEditor(G2gd.GridFractionEditor(vecGrid))
1009            for c in range(3):
1010                vecGrid.SetColAttr(c, attr)
1011            for row in range(vecTable.GetNumberRows()):
1012                if imag:
1013                    vecGrid.SetCellStyle(row,3,VERY_LIGHT_GREY,True)                   
1014                for col in [4,5,6]:
1015                    vecGrid.SetCellStyle(row,col,VERY_LIGHT_GREY,True)
1016            vecGrid.SetMargins(0,0)
1017            vecGrid.AutoSizeColumns(False)
1018            vecSizer.Add(vecGrid)
1019            return vecSizer
1020       
1021        VectorRB.DestroyChildren()
1022        VectorRBDisplay = wx.Panel(VectorRB)
1023        VectorRBSizer = wx.BoxSizer(wx.VERTICAL)
1024        for rbId in data['Vector']:
1025            if rbId != 'AtInfo':
1026                rbData = data['Vector'][rbId]
1027                VectorRBSizer.Add(rbNameSizer(rbId,rbData),0)
1028                XYZ = np.array([[0.,0.,0.] for Ty in rbData['rbTypes']])
1029                for imag,mag in enumerate(rbData['VectMag']):
1030                    XYZ += mag*rbData['rbVect'][imag]
1031                    VectorRBSizer.Add(rbVectMag(rbId,imag,rbData),0)
1032                    VectorRBSizer.Add(rbVectors(rbId,imag,mag,XYZ,rbData),0)
1033                VectorRBSizer.Add((5,5),0)       
1034        VectorRBSizer.Layout()   
1035        VectorRBDisplay.SetSizer(VectorRBSizer,True)
1036        Size = VectorRBSizer.GetMinSize()
1037        Size[0] += 40
1038        Size[1] = max(Size[1],450) + 20
1039        VectorRBDisplay.SetSize(Size)
1040        VectorRB.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
1041        Size[1] = min(Size[1],450)
1042        G2frame.dataFrame.setSizePosLeft(Size)
1043       
1044    def UpdateResidueRB():
1045        AtInfo = data['Residue']['AtInfo']
1046        Indx = {}
1047
1048        def rbNameSizer(rbId,rbData):
1049
1050            def OnRBName(event):
1051                Obj = event.GetEventObject()
1052                rbId = Indx[Obj.GetId()]
1053                rbData['RBname'] = Obj.GetValue()
1054               
1055            def OnDelRB(event):
1056                Obj = event.GetEventObject()
1057                rbId = Indx[Obj.GetId()]
1058                del data['Residue'][rbId]
1059                wx.CallAfter(UpdateResidueRB)
1060               
1061            def OnPlotRB(event):
1062                Obj = event.GetEventObject()
1063                rbId = Indx[Obj.GetId()]
1064                Obj.SetValue(False)
1065                G2plt.PlotRigidBody(G2frame,'Residue',AtInfo,rbData,plotDefaults)
1066           
1067            nameSizer = wx.BoxSizer(wx.HORIZONTAL)
1068            nameSizer.Add(wx.StaticText(ResidueRBDisplay,-1,'Residue name: '),
1069                0,wx.ALIGN_CENTER_VERTICAL)
1070            RBname = wx.TextCtrl(ResidueRBDisplay,-1,rbData['RBname'])
1071            Indx[RBname.GetId()] = rbId
1072            RBname.Bind(wx.EVT_TEXT_ENTER,OnRBName)
1073            RBname.Bind(wx.EVT_KILL_FOCUS,OnRBName)
1074            nameSizer.Add(RBname,0,wx.ALIGN_CENTER_VERTICAL)
1075            nameSizer.Add((5,0),)
1076            plotRB = wx.CheckBox(ResidueRBDisplay,-1,'Plot?')
1077            Indx[plotRB.GetId()] = rbId
1078            plotRB.Bind(wx.EVT_CHECKBOX,OnPlotRB)
1079            nameSizer.Add(plotRB,0,wx.ALIGN_CENTER_VERTICAL)
1080            nameSizer.Add((5,0),)
1081            delRB = wx.CheckBox(ResidueRBDisplay,-1,'Delete?')
1082            Indx[delRB.GetId()] = rbId
1083            delRB.Bind(wx.EVT_CHECKBOX,OnDelRB)
1084            nameSizer.Add(delRB,0,wx.ALIGN_CENTER_VERTICAL)
1085            return nameSizer
1086           
1087        def rbResidues(rbId,XYZ,rbData):
1088           
1089            def TypeSelect(event):
1090                AtInfo = data['Residue']['AtInfo']
1091                r,c = event.GetRow(),event.GetCol()
1092                if vecGrid.GetColLabelValue(c) == 'Type':
1093                    PE = G2elemGUI.PickElement(G2frame,oneOnly=True)
1094                    if PE.ShowModal() == wx.ID_OK:
1095                        if PE.Elem != 'None':
1096                            El = PE.Elem.strip().lower().capitalize()
1097                            if El not in AtInfo:
1098                                Info = G2elem.GetAtomInfo(El)
1099                                AtInfo[El] = [Info['Drad']['Color']]
1100                            rbData['rbTypes'][r] = El
1101                            vecGrid.SetCellValue(r,c,El)
1102                    PE.Destroy()
1103
1104            def ChangeCell(event):
1105                r,c =  event.GetRow(),event.GetCol()
1106                if r >= 0 and (0 <= c < 3):
1107                    try:
1108                        val = float(vecGrid.GetCellValue(r,c))
1109                        rbData['rbVect'][imag][r][c] = val
1110                    except ValueError:
1111                        pass
1112
1113            vecSizer = wx.BoxSizer()
1114            Types = 2*[wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,5',]
1115            colLabels = ['Name','Type','Cart x','Cart y','Cart z']
1116            table = []
1117            rowLabels = []
1118            for ivec,xyz in enumerate(rbData['rbXYZ']):
1119                table.append([rbData['atNames'][ivec],]+[rbData['rbTypes'][ivec],]+list(xyz))
1120                rowLabels.append(str(ivec))
1121            vecTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
1122            vecGrid = G2gd.GSGrid(ResidueRBDisplay)
1123            vecGrid.SetTable(vecTable, True)
1124            vecGrid.Bind(wg.EVT_GRID_CELL_CHANGE, ChangeCell)
1125            vecGrid.Bind(wg.EVT_GRID_CELL_LEFT_DCLICK, TypeSelect)
1126            attr = wx.grid.GridCellAttr()
1127            attr.SetEditor(G2gd.GridFractionEditor(vecGrid))
1128            for c in range(3):
1129                vecGrid.SetColAttr(c, attr)
1130            for row in range(vecTable.GetNumberRows()):
1131                for col in range(5):
1132                    vecGrid.SetCellStyle(row,col,VERY_LIGHT_GREY,True)
1133            vecGrid.SetMargins(0,0)
1134            vecGrid.AutoSizeColumns(False)
1135            vecSizer.Add(vecGrid)
1136            return vecSizer
1137           
1138        def SeqSizer(angSlide,rbId,iSeq,Seq,atNames):
1139           
1140            def ChangeAngle(event):
1141                Obj = event.GetEventObject()
1142                rbId,Seq = Indx[Obj.GetId()]
1143                val = Seq[2]
1144                try:
1145                    val = float(Obj.GetValue())
1146                    Seq[2] = val
1147                except ValueError:
1148                    pass
1149                Obj.SetValue('%8.2f'%(val))
1150                G2plt.PlotRigidBody(G2frame,'Residue',AtInfo,data['Residue'][rbId],plotDefaults)
1151               
1152            def OnRadBtn(event):
1153                Obj = event.GetEventObject()
1154                Seq,iSeq,angId = Indx[Obj.GetId()]
1155                data['Residue'][rbId]['SelSeq'] = [iSeq,angId]
1156                angSlide.SetValue(int(100*Seq[2]))
1157           
1158            seqSizer = wx.FlexGridSizer(0,4,2,2)
1159            seqSizer.AddGrowableCol(3,0)
1160            iBeg,iFin,angle,iMove = Seq
1161            ang = wx.TextCtrl(ResidueRBDisplay,-1,'%8.2f'%(angle),size=(50,20))
1162            if not iSeq:
1163                radBt = wx.RadioButton(ResidueRBDisplay,-1,'',style=wx.RB_GROUP)
1164                data['Residue'][rbId]['SelSeq'] = [iSeq,ang.GetId()]
1165            else:
1166                radBt = wx.RadioButton(ResidueRBDisplay,-1,'')
1167            radBt.Bind(wx.EVT_RADIOBUTTON,OnRadBtn)                   
1168            seqSizer.Add(radBt)
1169            bond = wx.TextCtrl(ResidueRBDisplay,-1,'%s %s'%(atNames[iBeg],atNames[iFin]),size=(50,20))
1170            seqSizer.Add(bond,0,wx.ALIGN_CENTER_VERTICAL)
1171            Indx[radBt.GetId()] = [Seq,iSeq,ang.GetId()]
1172            Indx[ang.GetId()] = [rbId,Seq,ang]
1173            ang.Bind(wx.EVT_TEXT_ENTER,ChangeAngle)
1174            ang.Bind(wx.EVT_KILL_FOCUS,ChangeAngle)
1175            seqSizer.Add(ang,0,wx.ALIGN_CENTER_VERTICAL)
1176            atms = ''
1177            for i in iMove:   
1178                atms += ' %s,'%(atNames[i])
1179            moves = wx.TextCtrl(ResidueRBDisplay,-1,atms[:-1],size=(200,20))
1180            seqSizer.Add(moves,1,wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.RIGHT)
1181            return seqSizer
1182           
1183        def SlideSizer():
1184           
1185            def OnSlider(event):
1186                Obj = event.GetEventObject()
1187                rbData = Indx[Obj.GetId()]
1188                iSeq,angId = rbData['SelSeq']
1189                val = float(Obj.GetValue())/100.
1190                rbData['rbSeq'][iSeq][2] = val
1191                Indx[angId][2].SetValue('%8.2f'%(val))
1192                G2plt.PlotRigidBody(G2frame,'Residue',AtInfo,rbData,plotDefaults)
1193           
1194            slideSizer = wx.BoxSizer(wx.HORIZONTAL)
1195            slideSizer.Add(wx.StaticText(ResidueRBDisplay,-1,'Selected torsion angle:'),0)
1196            iSeq,angId = rbData['SelSeq']
1197            angSlide = wx.Slider(ResidueRBDisplay,-1,
1198                int(100*rbData['rbSeq'][iSeq][2]),0,36000,size=(200,20),
1199                style=wx.SL_HORIZONTAL)
1200            angSlide.Bind(wx.EVT_SLIDER, OnSlider)
1201            Indx[angSlide.GetId()] = rbData
1202            slideSizer.Add(angSlide,0)           
1203            return slideSizer,angSlide           
1204           
1205        ResidueRB.DestroyChildren()
1206        ResidueRBDisplay = wx.Panel(ResidueRB)
1207        ResidueRBSizer = wx.BoxSizer(wx.VERTICAL)
1208        rbKeys = data['Residue'].keys()
1209        rbKeys.remove('AtInfo')
1210        rbNames = [data['Residue'][k]['RBname'] for k in rbKeys]
1211        rbIds = dict(zip(rbNames,rbKeys))
1212        rbNames.sort()
1213        for name in rbNames:
1214            rbId = rbIds[name]
1215            rbData = data['Residue'][rbId]
1216            ResidueRBSizer.Add(rbNameSizer(rbId,rbData),0)
1217            XYZ = np.array([[0.,0.,0.] for Ty in rbData['rbTypes']])
1218            ResidueRBSizer.Add(rbResidues(rbId,XYZ,rbData),0)
1219            ResidueRBSizer.Add((5,5),0)
1220            if rbData['rbSeq']:
1221                slideSizer,angSlide = SlideSizer()
1222            ResidueRBSizer.Add(wx.StaticText(ResidueRBDisplay,-1,
1223                'Sel  Bond             Angle      Riding atoms'),
1224                0,wx.ALIGN_CENTER_VERTICAL)                       
1225            for iSeq,Seq in enumerate(rbData['rbSeq']):
1226                ResidueRBSizer.Add(SeqSizer(angSlide,rbId,iSeq,Seq,rbData['atNames']))
1227            if rbData['rbSeq']:
1228                ResidueRBSizer.Add(slideSizer,)
1229            ResidueRBSizer.Add(wx.StaticText(ResidueRBDisplay,-1,100*'-'))
1230
1231        ResidueRBSizer.Add((5,25),)
1232        ResidueRBSizer.Layout()   
1233        ResidueRBDisplay.SetSizer(ResidueRBSizer,True)
1234        Size = ResidueRBSizer.GetMinSize()
1235        Size[0] += 40
1236        Size[1] = max(Size[1],250) + 20
1237        ResidueRBDisplay.SetSize(Size)
1238        ResidueRB.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
1239        Size[1] = min(600,Size[1])
1240        G2frame.dataFrame.setSizePosLeft(Size)
1241       
1242    def UpdateZMatrixRB():
1243        ZMatrixRB.DestroyChildren()
1244        ZMatrixRBDisplay = wx.Panel(ZMatrixRB)
1245        ZMatrixRBSizer = wx.BoxSizer(wx.VERTICAL)
1246        ZMatrixRBSizer.Add((5,5),0)       
1247#        ZMatrixRBSizer.Add(ConstSizer('Phase',PhaseDisplay))
1248        ZMatrixRBSizer.Layout()   
1249        ZMatrixRBDisplay.SetSizer(ZMatrixRBSizer,True)
1250        Size = ZMatrixRBSizer.GetMinSize()
1251        Size[0] += 40
1252        Size[1] = max(Size[1],250) + 20
1253        ZMatrixRBDisplay.SetSize(Size)
1254        ZMatrixRB.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
1255#        Size[1] = min(Size[1],250)
1256        G2frame.dataFrame.setSizePosLeft(Size)
1257
1258    def SetStatusLine(text):
1259        Status.SetStatusText(text)                                     
1260
1261    if G2frame.dataDisplay:
1262        G2frame.dataDisplay.Destroy()
1263    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RigidBodyMenu)
1264    G2frame.dataFrame.SetLabel('Rigid bodies')
1265    if not G2frame.dataFrame.GetStatusBar():
1266        Status = G2frame.dataFrame.CreateStatusBar()
1267    SetStatusLine('')
1268
1269    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RigidBodyMenu)
1270    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddRigidBody, id=G2gd.wxID_RIGIDBODYADD)   
1271    G2frame.dataFrame.Bind(wx.EVT_MENU, OnImportRigidBody, id=G2gd.wxID_RIGIDBODYIMPORT)
1272    G2frame.dataFrame.Bind(wx.EVT_MENU, OnDefineTorsSeq, id=G2gd.wxID_RESIDUETORSSEQ)
1273    G2frame.dataDisplay = G2gd.GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
1274    G2frame.dataDisplay.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, OnPageChanged)
1275
1276    VectorRB = wx.ScrolledWindow(G2frame.dataDisplay)
1277    G2frame.dataDisplay.AddPage(VectorRB,'Vector rigid bodies')
1278    ResidueRB = wx.ScrolledWindow(G2frame.dataDisplay)
1279    G2frame.dataDisplay.AddPage(ResidueRB,'Residue rigid bodies')
1280    ZMatrixRB = wx.ScrolledWindow(G2frame.dataDisplay)
1281    G2frame.dataDisplay.AddPage(ZMatrixRB,'Z-matrix rigid bodies')
1282    UpdateVectorRB()
1283   
Note: See TracBrowser for help on using the repository browser.