source: trunk/GSASIIconstrGUI.py @ 854

Last change on this file since 854 was 854, checked in by vondreele, 9 years ago

more rigid body stuff

File size: 61.7 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    global resList
630    Indx = {}
631    resList = []
632    plotDefaults = {'oldxy':[0.,0.],'Quaternion':[1.,0.,0.,0.],'cameraPos':30.,'viewDir':[0,0,1],}
633
634    def OnPageChanged(event):
635        global resList
636        resList = []
637        if event:       #page change event!
638            page = event.GetSelection()
639        else:
640            page = G2frame.dataDisplay.GetSelection()
641        oldPage = G2frame.dataDisplay.ChangeSelection(page)
642        text = G2frame.dataDisplay.GetPageText(page)
643        if text == 'Vector rigid bodies':
644            G2frame.dataFrame.RigidBodyMenu.Remove(0)   #NB: wx.MenuBar.Replace gives error
645            G2frame.dataFrame.RigidBodyMenu.Insert(0,G2frame.dataFrame.VectorRBEdit,title='Edit')
646            G2frame.Page = [page,'vrb']
647            UpdateVectorRB()
648        elif text == 'Residue rigid bodies':
649            G2frame.dataFrame.RigidBodyMenu.Remove(0)
650            G2frame.dataFrame.RigidBodyMenu.Insert(0,G2frame.dataFrame.ResidueRBMenu,title='Edit')
651            G2frame.Page = [page,'rrb']
652            UpdateResidueRB()
653        elif text == 'Z-matrix rigid bodies':
654            G2frame.dataFrame.RigidBodyMenu.Remove(0)
655            G2frame.dataFrame.RigidBodyMenu.Insert(0,G2frame.dataFrame.ZMatrixRBMenu,title='Edit')
656            G2frame.Page = [page,'zrb']
657            UpdateZMatrixRB()
658           
659    def getMacroFile(macName):
660        defDir = os.path.join(os.path.split(__file__)[0],'GSASIImacros')
661        dlg = wx.FileDialog(G2frame,message='Choose '+macName+' rigid body macro file',
662            defaultDir=defDir,defaultFile="",wildcard="GSAS-II macro file (*.mac)|*.mac",
663            style=wx.OPEN | wx.CHANGE_DIR)
664        try:
665            if dlg.ShowModal() == wx.ID_OK:
666                macfile = dlg.GetPath()
667                macro = open(macfile,'Ur')
668                head = macro.readline()
669                if macName not in head:
670                    print head
671                    print '**** ERROR - wrong restraint macro file selected, try again ****'
672                    macro = []
673            else: # cancel was pressed
674                macro = []
675        finally:
676            dlg.Destroy()
677        return macro        #advanced past 1st line
678       
679    def getTextFile():
680        defDir = os.path.join(os.path.split(__file__)[0],'GSASIImacros')
681        dlg = wx.FileDialog(G2frame,'Choose rigid body text file', '.', '',
682            "GSAS-II text file (*.txt)|*.txt|XYZ file (*.xyz)|*.xyz|"
683            "Sybyl mol2 file (*.mol2)|*.mol2|PDB file (*.pdb;*.ent)|*.pdb;*.ent",
684            wx.OPEN | wx.CHANGE_DIR)
685        try:
686            if dlg.ShowModal() == wx.ID_OK:
687                txtfile = dlg.GetPath()
688                ext = os.path.splitext(txtfile)[1]
689                text = open(txtfile,'Ur')
690            else: # cancel was pressed
691                ext = ''
692                text = []
693        finally:
694            dlg.Destroy()
695        if 'ent' in ext:
696            ext = '.pdb'
697        return text,ext.lower()
698       
699    def OnAddRigidBody(event):
700        page = G2frame.dataDisplay.GetSelection()
701        if 'Vector' in G2frame.dataDisplay.GetPageText(page):
702            AddVectorRB()
703        elif 'Residue' in G2frame.dataDisplay.GetPageText(page):
704            AddResidueRB()
705           
706    def OnImportRigidBody(event):
707        page = G2frame.dataDisplay.GetSelection()
708        if 'Vector' in G2frame.dataDisplay.GetPageText(page):
709            pass
710        elif 'Residue' in G2frame.dataDisplay.GetPageText(page):
711            ImportResidueRB()
712           
713    def AddVectorRB():
714        AtInfo = data['Vector']['AtInfo']
715        dlg = MultiIntegerDialog(G2frame.dataDisplay,'New Rigid Body',['No. atoms','No. translations'],[1,1])
716        if dlg.ShowModal() == wx.ID_OK:
717            nAtoms,nTrans = dlg.GetValues()
718            vectorRB = data['Vector']
719            rbId = ran.randint(0,sys.maxint)
720            vecMag = [1.0 for i in range(nTrans)]
721            vecRef = [False for i in range(nTrans)]
722            vecVal = [np.zeros((nAtoms,3)) for j in range(nTrans)]
723            rbTypes = ['C' for i in range(nAtoms)]
724            Info = G2elem.GetAtomInfo('C')
725            AtInfo['C'] = [Info['Drad'],Info['Color']]
726            data['Vector'][rbId] = {'RBname':'UNKRB','VectMag':vecMag,'rbXYZ':np.zeros((nAtoms,3)),
727                'VectRef':vecRef,'rbTypes':rbTypes,'rbVect':vecVal,'useCount':0}
728        dlg.Destroy()
729        UpdateVectorRB()
730       
731    def AddResidueRB():
732        AtInfo = data['Residue']['AtInfo']
733        macro = getMacroFile('rigid body')
734        if not macro:
735            return
736        macStr = macro.readline()
737        while macStr:
738            items = macStr.split()
739            if 'I' == items[0]:
740                rbId = ran.randint(0,sys.maxint)
741                rbName = items[1]
742                rbTypes = []
743                rbXYZ = []
744                rbSeq = []
745                atNames = []
746                nAtms,nSeq,nOrig,mRef,nRef = [int(items[i]) for i in [2,3,4,5,6]]
747                for iAtm in range(nAtms):
748                    macStr = macro.readline().split()
749                    atName = macStr[0]
750                    atType = macStr[1]
751                    atNames.append(atName)
752                    rbXYZ.append([float(macStr[i]) for i in [2,3,4]])
753                    rbTypes.append(atType)
754                    if atType not in AtInfo:
755                        Info = G2elem.GetAtomInfo(atType)
756                        AtInfo[atType] = [Info['Drad'],Info['Color']]
757                rbXYZ = np.array(rbXYZ)-np.array(rbXYZ[nOrig-1])
758                for iSeq in range(nSeq):
759                    macStr = macro.readline().split()
760                    mSeq = int(macStr[0])
761                    for jSeq in range(mSeq):
762                        macStr = macro.readline().split()
763                        iBeg = int(macStr[0])-1
764                        iFin = int(macStr[1])-1
765                        angle = 0.0
766                        nMove = int(macStr[2])
767                        iMove = [int(macStr[i])-1 for i in range(3,nMove+3)]
768                        rbSeq.append([iBeg,iFin,angle,iMove])
769                data['Residue'][rbId] = {'RBname':rbName,'rbXYZ':rbXYZ,'rbTypes':rbTypes,
770                    'atNames':atNames,'rbRef':[nOrig-1,mRef-1,nRef-1,True],'rbSeq':rbSeq,
771                    'SelSeq':[0,0],'useCount':0}
772                print 'Rigid body '+rbName+' added'
773            macStr = macro.readline()
774        macro.close()
775        UpdateResidueRB()
776       
777    def ImportResidueRB():
778        AtInfo = data['Residue']['AtInfo']
779        text,ext = getTextFile()
780        if not text:
781            return
782        rbId = ran.randint(0,sys.maxint)
783        rbTypes = []
784        rbXYZ = []
785        rbSeq = []
786        atNames = []
787        txtStr = text.readline()
788        if 'xyz' in ext:
789            txtStr = text.readline()
790            txtStr = text.readline()
791        elif 'mol2' in ext:
792            while 'ATOM' not in txtStr:
793                txtStr = text.readline()
794            txtStr = text.readline()
795        elif 'pdb' in ext:
796            while 'ATOM' not in txtStr[:6] and 'HETATM' not in txtStr[:6]:
797                txtStr = text.readline()
798                print txtStr
799        items = txtStr.split()
800        while len(items):
801            if 'txt' in ext:
802                atName = items[0]
803                atType = items[1]
804                rbXYZ.append([float(items[i]) for i in [2,3,4]])
805            elif 'xyz' in ext:
806                atType = items[0]
807                rbXYZ.append([float(items[i]) for i in [1,2,3]])
808                atName = atType+str(len(rbXYZ))
809            elif 'mol2' in ext:
810                atType = items[1]
811                atName = items[1]+items[0]
812                rbXYZ.append([float(items[i]) for i in [2,3,4]])
813            elif 'pdb' in ext:
814                atType = items[-1]
815                atName = items[2]
816                xyz = txtStr[30:55].split()                   
817                rbXYZ.append([float(x) for x in xyz])
818            atNames.append(atName)
819            rbTypes.append(atType)
820            if atType not in AtInfo:
821                Info = G2elem.GetAtomInfo(atType)
822                AtInfo[atType] = [Info['Drad'],Info['Color']]
823            txtStr = text.readline()
824            if 'mol2' in ext and 'BOND' in txtStr:
825                break
826            if 'pdb' in ext and ('ATOM' not in txtStr[:6] and 'HETATM' not in txtStr[:6]):
827                break
828            items = txtStr.split()
829        rbXYZ = np.array(rbXYZ)-np.array(rbXYZ[0])
830        data['Residue'][rbId] = {'RBname':'UNKRB','rbXYZ':rbXYZ,'rbTypes':rbTypes,
831            'atNames':atNames,'rbRef':[0,1,2,False],'rbSeq':[],'SelSeq':[0,0],'useCount':0}
832        print 'Rigid body UNKRB added'
833        text.close()
834        UpdateResidueRB()
835       
836    def FindNeighbors(Orig,XYZ,atTypes,atNames,AtInfo):
837        Radii = []
838        for Atype in atTypes:
839            Radii.append(AtInfo[Atype][0])
840        Radii = np.array(Radii)
841        Neigh = []
842        Dx = XYZ-XYZ[Orig]
843        dist = np.sqrt(np.sum(Dx**2,axis=1))
844        sumR = Radii[Orig]+Radii
845        IndB = ma.nonzero(ma.masked_greater(dist-0.85*sumR,0.))
846        for j in IndB[0]:
847            if j != Orig:
848                Neigh.append(atNames[j])
849        return Neigh
850       
851    def FindAllNeighbors(XYZ,atTypes,atNames,AtInfo):
852        NeighDict = {}
853        for iat,xyz in enumerate(atNames):
854            NeighDict[atNames[iat]] = FindNeighbors(iat,XYZ,atTypes,atNames,AtInfo)
855        return NeighDict
856       
857    def FindRiding(Orig,Pivot,NeighDict):
858        riding = [Orig,Pivot]
859        iAdd = 1
860        new = True
861        while new:
862            newAtms = NeighDict[riding[iAdd]]
863            for At in newAtms:
864                new = False
865                if At not in riding:
866                    riding.append(At)
867                    new = True
868            iAdd += 1
869            if iAdd < len(riding):
870                new = True
871        return riding[2:]
872                       
873    def OnDefineTorsSeq(event):
874        rbKeys = data['Residue'].keys()
875        rbKeys.remove('AtInfo')
876        rbNames = [data['Residue'][k]['RBname'] for k in rbKeys]
877        rbIds = dict(zip(rbNames,rbKeys))
878        rbNames.sort()
879        rbId = 0
880        if len(rbNames) > 1:
881            dlg = wx.SingleChoiceDialog(G2frame,'Select rigid body for torsion sequence','Torsion sequence',rbNames)
882            if dlg.ShowModal() == wx.ID_OK:
883                sel = dlg.GetSelection()
884                rbId = rbIds[rbNames[sel]]
885                rbData = data['Residue'][rbId]
886            dlg.Destroy()
887        else:
888            rbId = rbIds[rbNames[0]]
889            rbData = data['Residue'][rbId]
890        if not len(rbData):
891            return
892        atNames = rbData['atNames']
893        AtInfo = data['Residue']['AtInfo']
894        atTypes = rbData['rbTypes']
895        XYZ = rbData['rbXYZ']
896        neighDict = FindAllNeighbors(XYZ,atTypes,atNames,AtInfo)
897        TargList = []           
898        dlg = wx.SingleChoiceDialog(G2frame,'Select origin atom for torsion sequence','Origin atom',rbData['atNames'])
899        if dlg.ShowModal() == wx.ID_OK:
900            Orig = dlg.GetSelection()
901            xyz = XYZ[Orig]
902            TargList = neighDict[atNames[Orig]]
903        dlg.Destroy()
904        if not len(TargList):
905            return
906        dlg = wx.SingleChoiceDialog(G2frame,'Select pivot atom for torsion sequence','Pivot atom',TargList)
907        if dlg.ShowModal() == wx.ID_OK:
908            Piv = atNames.index(TargList[dlg.GetSelection()])
909            riding = FindRiding(atNames[Orig],atNames[Piv],neighDict)
910            Riding = []
911            for atm in riding:
912                Riding.append(atNames.index(atm))
913            rbData['rbSeq'].append([Orig,Piv,0.0,Riding])           
914        dlg.Destroy()
915        UpdateResidueRB()
916       
917
918    def UpdateVectorRB(Scroll=0):
919        AtInfo = data['Vector']['AtInfo']
920        refChoice = {}
921        SetStatusLine(' You may use e.g. "sind(60)", "cos(60)", "c60" or "s60" for a vector entry')
922        def rbNameSizer(rbId,rbData):
923
924            def OnRBName(event):
925                Obj = event.GetEventObject()
926                rbId = Indx[Obj.GetId()]
927                rbData['RBname'] = Obj.GetValue()
928               
929            def OnDelRB(event):
930                Obj = event.GetEventObject()
931                rbId = Indx[Obj.GetId()]
932                del data['Vector'][rbId]
933                wx.CallAfter(UpdateVectorRB)
934               
935            def OnPlotRB(event):
936                Obj = event.GetEventObject()
937                rbId = Indx[Obj.GetId()]
938                Obj.SetValue(False)
939                G2plt.PlotRigidBody(G2frame,'Vector',AtInfo,rbData,plotDefaults)
940           
941            nameSizer = wx.BoxSizer(wx.HORIZONTAL)
942            nameSizer.Add(wx.StaticText(VectorRBDisplay,-1,'Rigid body name: '),
943                0,wx.ALIGN_CENTER_VERTICAL)
944            RBname = wx.TextCtrl(VectorRBDisplay,-1,rbData['RBname'])
945            Indx[RBname.GetId()] = rbId
946            RBname.Bind(wx.EVT_TEXT_ENTER,OnRBName)
947            RBname.Bind(wx.EVT_KILL_FOCUS,OnRBName)
948            nameSizer.Add(RBname,0,wx.ALIGN_CENTER_VERTICAL)
949            nameSizer.Add((5,0),)
950            plotRB = wx.CheckBox(VectorRBDisplay,-1,'Plot?')
951            Indx[plotRB.GetId()] = rbId
952            plotRB.Bind(wx.EVT_CHECKBOX,OnPlotRB)
953            nameSizer.Add(plotRB,0,wx.ALIGN_CENTER_VERTICAL)
954            nameSizer.Add((5,0),)
955            if not rbData['useCount']:
956                delRB = wx.CheckBox(VectorRBDisplay,-1,'Delete?')
957                Indx[delRB.GetId()] = rbId
958                delRB.Bind(wx.EVT_CHECKBOX,OnDelRB)
959                nameSizer.Add(delRB,0,wx.ALIGN_CENTER_VERTICAL)
960            return nameSizer
961           
962        def rbRefAtmSizer(rbId,rbData):
963           
964            def OnRefSel(event):
965                Obj = event.GetEventObject()
966                iref = Indx[Obj.GetId()]
967                sel = Obj.GetValue()
968                rbData['rbRef'][iref] = atNames.index(sel)
969           
970            refAtmSizer = wx.BoxSizer(wx.HORIZONTAL)
971            atNames = [name+str(i) for i,name in enumerate(rbData['rbTypes'])]
972            rbRef = rbData.get('rbRef',[0,1,2,False])
973            rbData['rbRef'] = rbRef
974            if rbData['useCount']:
975                refAtmSizer.Add(wx.StaticText(VectorRBDisplay,-1,
976                    'Orientation reference atoms A-B-C: %s, %s, %s'%(atNames[rbRef[0]], \
977                     atNames[rbRef[1]],atNames[rbRef[2]])),0)
978            else:
979                refAtmSizer.Add(wx.StaticText(VectorRBDisplay,-1,
980                    'Orientation reference atoms A-B-C: '),0,wx.ALIGN_CENTER_VERTICAL)
981                for i in range(3):
982                    choices = [atNames[j] for j in refChoice[rbId][i]]
983                    refSel = wx.ComboBox(VectorRBDisplay,-1,value='',
984                        choices=choices,style=wx.CB_READONLY|wx.CB_DROPDOWN)
985                    refSel.SetValue(atNames[rbRef[i]])
986                    refSel.Bind(wx.EVT_COMBOBOX, OnRefSel)
987                    Indx[refSel.GetId()] = i
988                    refAtmSizer.Add(refSel,0,wx.ALIGN_CENTER_VERTICAL)
989            return refAtmSizer
990                       
991        def rbVectMag(rbId,imag,rbData):
992           
993            def OnRBVectorMag(event):
994                Obj = event.GetEventObject()
995                rbId,imag = Indx[Obj.GetId()]
996                try:
997                    val = float(Obj.GetValue())
998                    if val <= 0.:
999                        raise ValueError
1000                    rbData['VectMag'][imag] = val
1001                except ValueError:
1002                    pass
1003                Obj.SetValue('%8.3f'%(val))
1004                wx.CallAfter(UpdateVectorRB,VectorRB.GetScrollPos(wx.VERTICAL))
1005                G2plt.PlotRigidBody(G2frame,'Vector',AtInfo,data['Vector'][rbId],plotDefaults)
1006               
1007            def OnRBVectorRef(event):
1008                Obj = event.GetEventObject()
1009                rbId,imag = Indx[Obj.GetId()]
1010                rbData['VectRef'][imag] = Obj.GetValue()
1011                       
1012            magSizer = wx.wx.BoxSizer(wx.HORIZONTAL)
1013            magSizer.Add(wx.StaticText(VectorRBDisplay,-1,'Translation magnitude: '),
1014                0,wx.ALIGN_CENTER_VERTICAL)
1015            magValue = wx.TextCtrl(VectorRBDisplay,-1,'%8.3f'%(rbData['VectMag'][imag]))
1016            Indx[magValue.GetId()] = [rbId,imag]
1017            magValue.Bind(wx.EVT_TEXT_ENTER,OnRBVectorMag)
1018            magValue.Bind(wx.EVT_KILL_FOCUS,OnRBVectorMag)
1019            magSizer.Add(magValue,0,wx.ALIGN_CENTER_VERTICAL)
1020            magSizer.Add((5,0),)
1021            magref = wx.CheckBox(VectorRBDisplay,-1,label=' Refine?') 
1022            magref.SetValue(rbData['VectRef'][imag])
1023            magref.Bind(wx.EVT_CHECKBOX,OnRBVectorRef)
1024            Indx[magref.GetId()] = [rbId,imag]
1025            magSizer.Add(magref,0,wx.ALIGN_CENTER_VERTICAL)
1026            return magSizer
1027           
1028        def rbVectors(rbId,imag,mag,XYZ,rbData):
1029
1030            def TypeSelect(event):
1031                AtInfo = data['Vector']['AtInfo']
1032                r,c = event.GetRow(),event.GetCol()
1033                if vecGrid.GetColLabelValue(c) == 'Type':
1034                    PE = G2elemGUI.PickElement(G2frame,oneOnly=True)
1035                    if PE.ShowModal() == wx.ID_OK:
1036                        if PE.Elem != 'None':
1037                            El = PE.Elem.strip().lower().capitalize()
1038                            if El not in AtInfo:
1039                                Info = G2elem.GetAtomInfo(El)
1040                                AtInfo[El] = [Info['Drad'],Info['Color']]
1041                            rbData['rbTypes'][r] = El
1042                            vecGrid.SetCellValue(r,c,El)
1043                    PE.Destroy()
1044                wx.CallAfter(UpdateVectorRB,VectorRB.GetScrollPos(wx.VERTICAL))
1045
1046            def ChangeCell(event):
1047                r,c =  event.GetRow(),event.GetCol()
1048                if r >= 0 and (0 <= c < 3):
1049                    try:
1050                        val = float(vecGrid.GetCellValue(r,c))
1051                        rbData['rbVect'][imag][r][c] = val
1052                    except ValueError:
1053                        pass
1054                G2plt.PlotRigidBody(G2frame,'Vector',AtInfo,data['Vector'][rbId],plotDefaults)
1055                wx.CallAfter(UpdateVectorRB,VectorRB.GetScrollPos(wx.VERTICAL))
1056
1057            vecSizer = wx.BoxSizer()
1058            Types = 3*[wg.GRID_VALUE_FLOAT+':10,5',]+[wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,5',]
1059            colLabels = ['Vector x','Vector y','Vector z','Type','Cart x','Cart y','Cart z']
1060            table = []
1061            rowLabels = []
1062            for ivec,xyz in enumerate(rbData['rbVect'][imag]):
1063                table.append(list(xyz)+[rbData['rbTypes'][ivec],]+list(XYZ[ivec]))
1064                rowLabels.append(str(ivec))
1065            vecTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
1066            vecGrid = G2gd.GSGrid(VectorRBDisplay)
1067            vecGrid.SetTable(vecTable, True)
1068            vecGrid.Bind(wg.EVT_GRID_CELL_CHANGE, ChangeCell)
1069            if not imag:
1070                vecGrid.Bind(wg.EVT_GRID_CELL_LEFT_DCLICK, TypeSelect)
1071            attr = wx.grid.GridCellAttr()
1072            attr.SetEditor(G2gd.GridFractionEditor(vecGrid))
1073            for c in range(3):
1074                vecGrid.SetColAttr(c, attr)
1075            for row in range(vecTable.GetNumberRows()):
1076                if imag:
1077                    vecGrid.SetCellStyle(row,3,VERY_LIGHT_GREY,True)                   
1078                for col in [4,5,6]:
1079                    vecGrid.SetCellStyle(row,col,VERY_LIGHT_GREY,True)
1080            vecGrid.SetMargins(0,0)
1081            vecGrid.AutoSizeColumns(False)
1082            vecSizer.Add(vecGrid)
1083            return vecSizer
1084       
1085        def FillRefChoice(rbId,rbData):
1086            choiceIds = [i for i in range(len(rbData['rbTypes']))]
1087           
1088            rbRef = rbData.get('rbRef',[0,1,2,False])
1089            for i in range(3):
1090                choiceIds.remove(rbRef[i])
1091            refChoice[rbId] = [choiceIds[:],choiceIds[:],choiceIds[:]]
1092            for i in range(3):
1093                refChoice[rbId][i].append(rbRef[i])
1094                refChoice[rbId][i].sort()     
1095           
1096        VectorRB.DestroyChildren()
1097        VectorRBDisplay = wx.Panel(VectorRB)
1098        VectorRBSizer = wx.BoxSizer(wx.VERTICAL)
1099        for rbId in data['Vector']:
1100            if rbId != 'AtInfo':
1101                rbData = data['Vector'][rbId]
1102                FillRefChoice(rbId,rbData)
1103                VectorRBSizer.Add(rbNameSizer(rbId,rbData),0)
1104                VectorRBSizer.Add(rbRefAtmSizer(rbId,rbData),0)
1105                XYZ = np.array([[0.,0.,0.] for Ty in rbData['rbTypes']])
1106                for imag,mag in enumerate(rbData['VectMag']):
1107                    XYZ += mag*rbData['rbVect'][imag]
1108                    VectorRBSizer.Add(rbVectMag(rbId,imag,rbData),0)
1109                    VectorRBSizer.Add(rbVectors(rbId,imag,mag,XYZ,rbData),0)
1110                VectorRBSizer.Add((5,5),0)
1111                data['Vector'][rbId]['rbXYZ'] = XYZ       
1112        VectorRBSizer.Layout()   
1113        VectorRBDisplay.SetSizer(VectorRBSizer,True)
1114        Size = VectorRBSizer.GetMinSize()
1115        Size[0] += 40
1116        Size[1] = max(Size[1],450) + 20
1117        VectorRBDisplay.SetSize(Size)
1118        VectorRB.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
1119        VectorRB.SetScrollPos(wx.VERTICAL,Scroll)
1120        Size[1] = min(Size[1],450)
1121        G2frame.dataFrame.setSizePosLeft(Size)
1122       
1123    def UpdateResidueRB():
1124        AtInfo = data['Residue']['AtInfo']
1125        refChoice = {}
1126
1127        def rbNameSizer(rbId,rbData):
1128
1129            def OnRBName(event):
1130                Obj = event.GetEventObject()
1131                rbId = Indx[Obj.GetId()]
1132                rbData['RBname'] = Obj.GetValue()
1133               
1134            def OnDelRB(event):
1135                Obj = event.GetEventObject()
1136                rbId = Indx[Obj.GetId()]
1137                del data['Residue'][rbId]
1138                wx.CallAfter(UpdateResidueRB)
1139               
1140            def OnPlotRB(event):
1141                Obj = event.GetEventObject()
1142                rbId = Indx[Obj.GetId()]
1143                Obj.SetValue(False)
1144                G2plt.PlotRigidBody(G2frame,'Residue',AtInfo,rbData,plotDefaults)
1145           
1146            nameSizer = wx.BoxSizer(wx.HORIZONTAL)
1147            nameSizer.Add(wx.StaticText(ResidueRBDisplay,-1,'Residue name: '),
1148                0,wx.ALIGN_CENTER_VERTICAL)
1149            RBname = wx.TextCtrl(ResidueRBDisplay,-1,rbData['RBname'])
1150            Indx[RBname.GetId()] = rbId
1151            RBname.Bind(wx.EVT_TEXT_ENTER,OnRBName)
1152            RBname.Bind(wx.EVT_KILL_FOCUS,OnRBName)
1153            nameSizer.Add(RBname,0,wx.ALIGN_CENTER_VERTICAL)
1154            nameSizer.Add((5,0),)
1155            plotRB = wx.CheckBox(ResidueRBDisplay,-1,'Plot?')
1156            Indx[plotRB.GetId()] = rbId
1157            plotRB.Bind(wx.EVT_CHECKBOX,OnPlotRB)
1158            nameSizer.Add(plotRB,0,wx.ALIGN_CENTER_VERTICAL)
1159            nameSizer.Add((5,0),)
1160            if not rbData['useCount']:
1161                delRB = wx.CheckBox(ResidueRBDisplay,-1,'Delete?')
1162                Indx[delRB.GetId()] = rbId
1163                delRB.Bind(wx.EVT_CHECKBOX,OnDelRB)
1164                nameSizer.Add(delRB,0,wx.ALIGN_CENTER_VERTICAL)
1165            return nameSizer
1166           
1167        def rbResidues(rbId,rbData):
1168           
1169            def TypeSelect(event):
1170                AtInfo = data['Residue']['AtInfo']
1171                r,c = event.GetRow(),event.GetCol()
1172                if vecGrid.GetColLabelValue(c) == 'Type':
1173                    PE = G2elemGUI.PickElement(G2frame,oneOnly=True)
1174                    if PE.ShowModal() == wx.ID_OK:
1175                        if PE.Elem != 'None':
1176                            El = PE.Elem.strip().lower().capitalize()
1177                            if El not in AtInfo:
1178                                Info = G2elem.GetAtomInfo(El)
1179                                AtInfo[El] = [Info['Drad']['Color']]
1180                            rbData['rbTypes'][r] = El
1181                            vecGrid.SetCellValue(r,c,El)
1182                    PE.Destroy()
1183
1184            def ChangeCell(event):
1185                r,c =  event.GetRow(),event.GetCol()
1186                if r >= 0 and (0 <= c < 3):
1187                    try:
1188                        val = float(vecGrid.GetCellValue(r,c))
1189                        rbData['rbVect'][imag][r][c] = val
1190                    except ValueError:
1191                        pass
1192                       
1193            def RowSelect(event):
1194                r,c =  event.GetRow(),event.GetCol()
1195                if c < 0:                   #only row clicks
1196                    for vecgrid in resList:
1197                        vecgrid.ClearSelection()
1198                    vecGrid.SelectRow(r,True)
1199
1200            def OnRefSel(event):
1201                Obj = event.GetEventObject()
1202                iref,res = Indx[Obj.GetId()]
1203                sel = Obj.GetValue()
1204                ind = atNames.index(sel)
1205                rbData['rbRef'][iref] = ind
1206                if not iref:     #origin change
1207                    rbXYZ = rbData['rbXYZ']
1208                    rbXYZ -= rbXYZ[ind]
1209                    res.ClearSelection()
1210                    resTable = res.GetTable()
1211                    for r in range(res.GetNumberRows()):
1212                        row = resTable.GetRowValues(r)
1213                        row[2:4] = rbXYZ[r]
1214                        resTable.SetRowValues(r,row)
1215                    res.ForceRefresh()
1216                    G2plt.PlotRigidBody(G2frame,'Residue',AtInfo,rbData,plotDefaults)
1217               
1218            Types = 2*[wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,5',]
1219            colLabels = ['Name','Type','Cart x','Cart y','Cart z']
1220            table = []
1221            rowLabels = []
1222            for ivec,xyz in enumerate(rbData['rbXYZ']):
1223                table.append([rbData['atNames'][ivec],]+[rbData['rbTypes'][ivec],]+list(xyz))
1224                rowLabels.append(str(ivec))
1225            vecTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
1226            vecGrid = G2gd.GSGrid(ResidueRBDisplay)
1227            Indx[vecGrid.GetId()] = rbId
1228            resList.append(vecGrid)
1229            vecGrid.SetTable(vecTable, True)
1230            vecGrid.Bind(wg.EVT_GRID_CELL_CHANGE, ChangeCell)
1231            vecGrid.Bind(wg.EVT_GRID_CELL_LEFT_DCLICK, TypeSelect)
1232            vecGrid.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK, RowSelect)
1233            attr = wx.grid.GridCellAttr()
1234            attr.SetEditor(G2gd.GridFractionEditor(vecGrid))
1235            for c in range(3):
1236                vecGrid.SetColAttr(c, attr)
1237            for row in range(vecTable.GetNumberRows()):
1238                for col in range(5):
1239                    vecGrid.SetCellStyle(row,col,VERY_LIGHT_GREY,True)
1240            vecGrid.SetMargins(0,0)
1241            vecGrid.AutoSizeColumns(False)
1242            vecSizer = wx.BoxSizer()
1243            vecSizer.Add(vecGrid)
1244           
1245            refAtmSizer = wx.BoxSizer(wx.HORIZONTAL)
1246            atNames = rbData['atNames']
1247            rbRef = rbData['rbRef']
1248            if rbData['rbRef'][3] or rbData['useCount']:
1249                refAtmSizer.Add(wx.StaticText(ResidueRBDisplay,-1,
1250                    'Orientation reference atoms A-B-C: %s, %s, %s'%(atNames[rbRef[0]], \
1251                     atNames[rbRef[1]],atNames[rbRef[2]])),0)
1252            else:
1253                refAtmSizer.Add(wx.StaticText(ResidueRBDisplay,-1,
1254                    'Orientation reference atoms A-B-C: '),0,wx.ALIGN_CENTER_VERTICAL)
1255                for i in range(3):
1256                    choices = [atNames[j] for j in refChoice[rbId][i]]
1257                    refSel = wx.ComboBox(ResidueRBDisplay,-1,value='',
1258                        choices=choices,style=wx.CB_READONLY|wx.CB_DROPDOWN)
1259                    refSel.SetValue(atNames[rbRef[i]])
1260                    refSel.Bind(wx.EVT_COMBOBOX, OnRefSel)
1261                    Indx[refSel.GetId()] = [i,vecGrid]
1262                    refAtmSizer.Add(refSel,0,wx.ALIGN_CENTER_VERTICAL)
1263           
1264            mainSizer = wx.BoxSizer(wx.VERTICAL)
1265            mainSizer.Add(refAtmSizer)
1266            mainSizer.Add(vecSizer)
1267            return mainSizer
1268           
1269        def SeqSizer(angSlide,rbId,iSeq,Seq,atNames):
1270           
1271            def ChangeAngle(event):
1272                Obj = event.GetEventObject()
1273                rbId,Seq = Indx[Obj.GetId()][:2]
1274                val = Seq[2]
1275                try:
1276                    val = float(Obj.GetValue())
1277                    Seq[2] = val
1278                except ValueError:
1279                    pass
1280                Obj.SetValue('%8.2f'%(val))
1281                G2plt.PlotRigidBody(G2frame,'Residue',AtInfo,data['Residue'][rbId],plotDefaults)
1282               
1283            def OnRadBtn(event):
1284                Obj = event.GetEventObject()
1285                Seq,iSeq,angId = Indx[Obj.GetId()]
1286                data['Residue'][rbId]['SelSeq'] = [iSeq,angId]
1287                angSlide.SetValue(int(100*Seq[2]))
1288           
1289            seqSizer = wx.FlexGridSizer(0,4,2,2)
1290            seqSizer.AddGrowableCol(3,0)
1291            iBeg,iFin,angle,iMove = Seq
1292            ang = wx.TextCtrl(ResidueRBDisplay,-1,'%8.2f'%(angle),size=(50,20))
1293            if not iSeq:
1294                radBt = wx.RadioButton(ResidueRBDisplay,-1,'',style=wx.RB_GROUP)
1295                data['Residue'][rbId]['SelSeq'] = [iSeq,ang.GetId()]
1296            else:
1297                radBt = wx.RadioButton(ResidueRBDisplay,-1,'')
1298            radBt.Bind(wx.EVT_RADIOBUTTON,OnRadBtn)                   
1299            seqSizer.Add(radBt)
1300            bond = wx.TextCtrl(ResidueRBDisplay,-1,'%s %s'%(atNames[iBeg],atNames[iFin]),size=(50,20))
1301            seqSizer.Add(bond,0,wx.ALIGN_CENTER_VERTICAL)
1302            Indx[radBt.GetId()] = [Seq,iSeq,ang.GetId()]
1303            Indx[ang.GetId()] = [rbId,Seq,ang]
1304            ang.Bind(wx.EVT_TEXT_ENTER,ChangeAngle)
1305            ang.Bind(wx.EVT_KILL_FOCUS,ChangeAngle)
1306            seqSizer.Add(ang,0,wx.ALIGN_CENTER_VERTICAL)
1307            atms = ''
1308            for i in iMove:   
1309                atms += ' %s,'%(atNames[i])
1310            moves = wx.TextCtrl(ResidueRBDisplay,-1,atms[:-1],size=(200,20))
1311            seqSizer.Add(moves,1,wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.RIGHT)
1312            return seqSizer
1313           
1314        def SlideSizer():
1315           
1316            def OnSlider(event):
1317                Obj = event.GetEventObject()
1318                rbData = Indx[Obj.GetId()]
1319                iSeq,angId = rbData['SelSeq']
1320                val = float(Obj.GetValue())/100.
1321                rbData['rbSeq'][iSeq][2] = val
1322                Indx[angId][2].SetValue('%8.2f'%(val))
1323                G2plt.PlotRigidBody(G2frame,'Residue',AtInfo,rbData,plotDefaults)
1324           
1325            slideSizer = wx.BoxSizer(wx.HORIZONTAL)
1326            slideSizer.Add(wx.StaticText(ResidueRBDisplay,-1,'Selected torsion angle:'),0)
1327            iSeq,angId = rbData['SelSeq']
1328            angSlide = wx.Slider(ResidueRBDisplay,-1,
1329                int(100*rbData['rbSeq'][iSeq][2]),0,36000,size=(200,20),
1330                style=wx.SL_HORIZONTAL)
1331            angSlide.Bind(wx.EVT_SLIDER, OnSlider)
1332            Indx[angSlide.GetId()] = rbData
1333            slideSizer.Add(angSlide,0)           
1334            return slideSizer,angSlide
1335           
1336        def FillRefChoice(rbId,rbData):
1337            choiceIds = [i for i in range(len(rbData['atNames']))]
1338            for seq in rbData['rbSeq']:
1339                for i in seq[3]:
1340                    try:
1341                        choiceIds.remove(i)
1342                    except ValueError:
1343                        pass
1344            rbRef = rbData['rbRef']
1345            for i in range(3):
1346                try:
1347                    choiceIds.remove(rbRef[i])
1348                except ValueError:
1349                    pass
1350            refChoice[rbId] = [choiceIds[:],choiceIds[:],choiceIds[:]]
1351            for i in range(3):
1352                refChoice[rbId][i].append(rbRef[i])
1353                refChoice[rbId][i].sort()     
1354           
1355        ResidueRB.DestroyChildren()
1356        ResidueRBDisplay = wx.Panel(ResidueRB)
1357        ResidueRBSizer = wx.BoxSizer(wx.VERTICAL)
1358        rbKeys = data['Residue'].keys()
1359        rbKeys.remove('AtInfo')
1360        rbNames = [data['Residue'][k]['RBname'] for k in rbKeys]
1361        rbIds = dict(zip(rbNames,rbKeys))
1362        rbNames.sort()
1363        for name in rbNames:
1364            rbId = rbIds[name]
1365            rbData = data['Residue'][rbId]
1366            FillRefChoice(rbId,rbData)
1367            ResidueRBSizer.Add(rbNameSizer(rbId,rbData),0)
1368            ResidueRBSizer.Add(rbResidues(rbId,rbData),0)
1369            ResidueRBSizer.Add((5,5),0)
1370            if rbData['rbSeq']:
1371                slideSizer,angSlide = SlideSizer()
1372            if len(rbData['rbSeq']):
1373                ResidueRBSizer.Add(wx.StaticText(ResidueRBDisplay,-1,
1374                    'Sel  Bond             Angle      Riding atoms'),
1375                    0,wx.ALIGN_CENTER_VERTICAL)                       
1376            for iSeq,Seq in enumerate(rbData['rbSeq']):
1377                ResidueRBSizer.Add(SeqSizer(angSlide,rbId,iSeq,Seq,rbData['atNames']))
1378            if rbData['rbSeq']:
1379                ResidueRBSizer.Add(slideSizer,)
1380            ResidueRBSizer.Add(wx.StaticText(ResidueRBDisplay,-1,100*'-'))
1381
1382        ResidueRBSizer.Add((5,25),)
1383        ResidueRBSizer.Layout()   
1384        ResidueRBDisplay.SetSizer(ResidueRBSizer,True)
1385        Size = ResidueRBSizer.GetMinSize()
1386        Size[0] += 40
1387        Size[1] = max(Size[1],450) + 20
1388        ResidueRBDisplay.SetSize(Size)
1389        ResidueRB.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
1390        Size[1] = min(600,Size[1])
1391        G2frame.dataFrame.setSizePosLeft(Size)
1392       
1393    def SetStatusLine(text):
1394        Status.SetStatusText(text)                                     
1395
1396    if G2frame.dataDisplay:
1397        G2frame.dataDisplay.Destroy()
1398    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RigidBodyMenu)
1399    G2frame.dataFrame.SetLabel('Rigid bodies')
1400    if not G2frame.dataFrame.GetStatusBar():
1401        Status = G2frame.dataFrame.CreateStatusBar()
1402    SetStatusLine('')
1403
1404    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RigidBodyMenu)
1405    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddRigidBody, id=G2gd.wxID_RIGIDBODYADD)   
1406    G2frame.dataFrame.Bind(wx.EVT_MENU, OnImportRigidBody, id=G2gd.wxID_RIGIDBODYIMPORT)
1407    G2frame.dataFrame.Bind(wx.EVT_MENU, OnDefineTorsSeq, id=G2gd.wxID_RESIDUETORSSEQ)
1408    G2frame.dataDisplay = G2gd.GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
1409    G2frame.dataDisplay.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, OnPageChanged)
1410
1411    VectorRB = wx.ScrolledWindow(G2frame.dataDisplay)
1412    G2frame.dataDisplay.AddPage(VectorRB,'Vector rigid bodies')
1413    ResidueRB = wx.ScrolledWindow(G2frame.dataDisplay)
1414    G2frame.dataDisplay.AddPage(ResidueRB,'Residue rigid bodies')
1415    UpdateVectorRB()
1416   
Note: See TracBrowser for help on using the repository browser.