source: trunk/GSASIIconstrGUI.py @ 835

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

more work on rigid bodies
fixes for crash in selecting wavelengths

File size: 41.0 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 GSASIIphsGUI as G2phG
23import GSASIIstruct as G2str
24import GSASIImapvars as G2mv
25import GSASIIgrid as G2gd
26import GSASIIplot as G2plt
27VERY_LIGHT_GREY = wx.Colour(235,235,235)
28
29class MultiIntegerDialog(wx.Dialog):
30   
31    def __init__(self,parent,title,prompts,values):
32        wx.Dialog.__init__(self,parent,-1,title, 
33            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
34        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
35        self.values = values
36        self.prompts = prompts
37        self.Draw()
38       
39    def Draw(self):
40       
41        def OnValItem(event):
42            Obj = event.GetEventObject()
43            ind = Indx[Obj.GetId()]
44            try:
45                val = int(Obj.GetValue())
46                if val <= 0:
47                    raise ValueError
48            except ValueError:
49                val = self.values[ind]
50            self.values[ind] = val
51            Obj.SetValue('%d'%(val))
52           
53        self.panel.Destroy()
54        self.panel = wx.Panel(self)
55        mainSizer = wx.BoxSizer(wx.VERTICAL)
56        Indx = {}
57        for ival,[prompt,value] in enumerate(zip(self.prompts,self.values)):
58            mainSizer.Add(wx.StaticText(self.panel,-1,prompt),0,wx.ALIGN_CENTER)
59            valItem = wx.TextCtrl(self.panel,-1,value='%d'%(value),style=wx.TE_PROCESS_ENTER)
60            mainSizer.Add(valItem,0,wx.ALIGN_CENTER)
61            Indx[valItem.GetId()] = ival
62            valItem.Bind(wx.EVT_TEXT_ENTER,OnValItem)
63            valItem.Bind(wx.EVT_KILL_FOCUS,OnValItem)
64        OkBtn = wx.Button(self.panel,-1,"Ok")
65        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
66        CancelBtn = wx.Button(self.panel,-1,'Cancel')
67        CancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
68        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
69        btnSizer.Add((20,20),1)
70        btnSizer.Add(OkBtn)
71        btnSizer.Add(CancelBtn)
72        btnSizer.Add((20,20),1)
73        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
74        self.panel.SetSizer(mainSizer)
75        self.panel.Fit()
76        self.Fit()
77
78    def GetValues(self):
79        return self.values
80       
81    def OnOk(self,event):
82        parent = self.GetParent()
83        parent.Raise()
84        self.EndModal(wx.ID_OK)             
85       
86    def OnCancel(self,event):
87        parent = self.GetParent()
88        parent.Raise()
89        self.EndModal(wx.ID_CANCEL)
90       
91################################################################################
92#####  Constraints
93################################################################################           
94       
95def UpdateConstraints(G2frame,data):
96    '''Called when Constraints tree item is selected.
97    Displays the constraints in the data window
98    '''
99    if not data:
100        data.update({'Hist':[],'HAP':[],'Phase':[]})       #empty dict - fill it
101    Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree()
102    AtomDict = dict([Phases[phase]['pId'],Phases[phase]['Atoms']] for phase in Phases)
103    Natoms,atomIndx,phaseVary,phaseDict,pawleyLookup,FFtable,BLtable = G2str.GetPhaseData(Phases,Print=False)
104    phaseList = []
105    for item in phaseDict:
106        if item.split(':')[2] not in ['Ax','Ay','Az','Amul','AI/A','Atype','SHorder']:
107            phaseList.append(item)
108    phaseList.sort()
109    phaseAtNames = {}
110    phaseAtTypes = {}
111    TypeList = []
112    for item in phaseList:
113        Split = item.split(':')
114        if Split[2][:2] in ['AU','Af','dA']:
115            Id = int(Split[0])
116            phaseAtNames[item] = AtomDict[Id][int(Split[3])][0]
117            phaseAtTypes[item] = AtomDict[Id][int(Split[3])][1]
118            if phaseAtTypes[item] not in TypeList:
119                TypeList.append(phaseAtTypes[item])
120        else:
121            phaseAtNames[item] = ''
122            phaseAtTypes[item] = ''
123           
124    hapVary,hapDict,controlDict = G2str.GetHistogramPhaseData(Phases,Histograms,Print=False)
125    hapList = hapDict.keys()
126    hapList.sort()
127    histVary,histDict,controlDict = G2str.GetHistogramData(Histograms,Print=False)
128    histList = []
129    for item in histDict:
130        if item.split(':')[2] not in ['Omega','Type','Chi','Phi','Azimuth','Gonio. radius','Lam1','Lam2','Back']:
131            histList.append(item)
132    histList.sort()
133    Indx = {}
134    scope = {}                          #filled out later
135    G2frame.Page = [0,'phs']
136   
137    def GetPHlegends(Phases,Histograms):
138        plegend = '\n In p::name'
139        hlegend = '\n In :h:name'
140        phlegend = '\n In p:h:name'
141        for phase in Phases:
142            plegend += '\n p:: = '+str(Phases[phase]['pId'])+':: for '+phase
143            count = 0
144            for histogram in Phases[phase]['Histograms']:
145                if count < 3:
146                    phlegend += '\n p:h: = '+str(Phases[phase]['pId'])+':'+str(Histograms[histogram]['hId'])+': for '+phase+' in '+histogram
147                else:
148                    phlegend += '\n ... etc.'
149                    break
150                count += 1
151        count = 0
152        for histogram in Histograms:
153            if count < 3:
154                hlegend += '\n :h: = :'+str(Histograms[histogram]['hId'])+': for '+histogram
155            else:
156                hlegend += '\n ... etc.'
157                break
158            count += 1
159        return plegend,hlegend,phlegend
160       
161    def FindEquivVarb(name,nameList):
162        outList = []
163        phlist = []
164        items = name.split(':')
165        namelist = [items[2],]
166        if 'dA' in name:
167            namelist = ['dAx','dAy','dAz']
168        elif 'AU' in name:
169            namelist = ['AUiso','AU11','AU22','AU33','AU12','AU13','AU23']
170        for item in nameList:
171            keys = item.split(':')
172            if keys[0] not in phlist:
173                phlist.append(keys[0])
174            if keys[2] in namelist and item != name:
175                outList.append(item)
176        if items[1]:
177            for key in phlist:
178                outList.append(key+':all:'+items[2])
179        return outList
180       
181    def SelectVarbs(page,FrstVarb,varList,legend,constType):
182        '''Select variables used in Constraints after one variable has
183        been selected which determines the appropriate variables to be
184        used here. Then creates the constraint and adds it to the
185        constraints list.
186        Called from OnAddEquivalence, OnAddFunction & OnAddConstraint
187        '''
188        #future -  add 'all:all:name', '0:all:name', etc. to the varList
189        if page[1] == 'phs':
190            atchoice = [item+' for '+phaseAtNames[item] for item in varList]
191            atchoice += [FrstVarb+' for all']
192            atchoice += [FrstVarb+' for all '+atype for atype in TypeList]
193            dlg = wx.MultiChoiceDialog(G2frame,'Select more variables:'+legend,
194                'Constrain '+FrstVarb+' and...',atchoice)
195        else:
196            dlg = wx.MultiChoiceDialog(G2frame,'Select more variables:'+legend,
197                'Constrain '+FrstVarb+' and...',varList)
198        varbs = [FrstVarb,]
199        if dlg.ShowModal() == wx.ID_OK:
200            sel = dlg.GetSelections()
201            try:
202                for x in sel:
203                    if ':all:' in varList[x]:       #a histogram 'all' - supercedes any individual selection
204                        varbs = [FrstVarb,]
205                        items = varList[x].split(':')
206                        for item in varList:
207                            if items[0] == item.split(':')[0] and ':all:' not in item:
208                                varbs.append(item)
209                        break
210                    else:
211                        varbs.append(varList[x])
212            except IndexError:      # one of the 'all' chosen - supercedes any individual selection
213                varbs = [FrstVarb,]
214                Atypes = []
215                for x in sel:
216                    item = atchoice[x]
217                    if 'all' in item:
218                        Atypes.append(item.split('all')[1].strip())
219                if '' in Atypes:
220                    varbs += varList
221                else:
222                    for item in varList:
223                        if phaseAtTypes[item] in Atypes:
224                            varbs.append(item) 
225        dlg.Destroy()
226        if len(varbs) > 1:
227            if 'equivalence' in constType:
228                constr = [[1.0,FrstVarb]]
229                for item in varbs[1:]:
230                    constr += [[1.0,item]]
231                return [constr+[None,None,'e']]      # list of equivalent variables & mults
232            elif 'function' in constType:
233                constr = map(list,zip([1.0 for i in range(len(varbs))],varbs))
234                return [constr+[None,False,'f']]         #just one constraint
235            else:       #'constraint'
236                constr = map(list,zip([1.0 for i in range(len(varbs))],varbs))
237                return [constr+[1.0,None,'c']]          #just one constraint - default sum to one
238        return []
239
240    def CheckAddedConstraint(newcons):
241        '''Check a new constraint that has just been input.
242        If there is an error display a message and give the user a
243        choice to keep or discard the last entry (why keep? -- they
244        may want to delete something else or edit multipliers).
245        Since the varylist is not available, no warning messages
246        should be generated.
247        Returns True if constraint should be added
248        '''
249        allcons = []
250        for key in 'Hist','HAP','Phase':
251            allcons += data[key]
252        allcons += newcons
253        if not len(allcons): return True
254        G2mv.InitVars()   
255        constDictList,fixedList,ignored = G2str.ProcessConstraints(allcons)
256        errmsg, warnmsg = G2mv.CheckConstraints('',constDictList,fixedList)
257        if errmsg:
258            res = G2frame.ErrorDialog('Constraint Error',
259                'Error with newly added constraint:\n'+errmsg+
260                '\n\nDiscard newly added constraint?',parent=G2frame.dataFrame,
261                wtype=wx.YES_NO)
262            return res != wx.ID_YES
263        elif warnmsg:
264            print 'Unexpected contraint warning:\n',warnmsg
265        return True
266
267    def CheckChangedConstraint():
268        '''Check all constraints after an edit has been made.
269        If there is an error display a message and give the user a
270        choice to keep or discard the last edit.
271        Since the varylist is not available, no warning messages
272        should be generated.
273        Returns True if the edit should be retained
274        '''
275        allcons = []
276        for key in 'Hist','HAP','Phase':
277            allcons += data[key]
278        if not len(allcons): return True
279        G2mv.InitVars()   
280        constDictList,fixedList,ignored = G2str.ProcessConstraints(allcons)
281        errmsg, warnmsg = G2mv.CheckConstraints('',constDictList,fixedList)
282        if errmsg:
283            res = G2frame.ErrorDialog('Constraint Error',
284                'Error after editing constraint:\n'+errmsg+
285                '\n\nDiscard last constraint edit?',parent=G2frame.dataFrame,
286                wtype=wx.YES_NO)
287            return res != wx.ID_YES
288        elif warnmsg:
289            print 'Unexpected contraint warning:\n',warnmsg
290        return True
291             
292    def OnAddHold(event):
293        '''add a Hold constraint'''
294        for phase in Phases:
295            Phase = Phases[phase]
296            Atoms = Phase['Atoms']
297        constr = []
298        page = G2frame.Page
299        choice = scope[page[1]]
300        if page[1] == 'phs':
301            atchoice = [item+' for '+phaseAtNames[item] for item in choice[2]]
302            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],atchoice)
303        else:   
304            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],choice[2])
305        if dlg.ShowModal() == wx.ID_OK:
306            sel = dlg.GetSelection()
307            FrstVarb = choice[2][sel]
308            newcons = [[[0.0,FrstVarb],None,None,'h']]
309            if CheckAddedConstraint(newcons):
310                data[choice[3]] += newcons
311        dlg.Destroy()
312        choice[4]()
313       
314    def OnAddEquivalence(event):
315        '''add an Equivalence constraint'''
316        constr = []
317        page = G2frame.Page
318        choice = scope[page[1]]
319        if page[1] == 'phs':
320            atchoice = [item+' for '+phaseAtNames[item] for item in choice[2]]
321            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],atchoice)
322        else:   
323            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],choice[2])
324        if dlg.ShowModal() == wx.ID_OK:
325            sel = dlg.GetSelection()
326            FrstVarb = choice[2][sel]
327            moreVarb = FindEquivVarb(FrstVarb,choice[2])
328            newcons = SelectVarbs(page,FrstVarb,moreVarb,choice[1],'equivalence')
329            if len(newcons) > 0:
330                if CheckAddedConstraint(newcons):
331                    data[choice[3]] += newcons
332        dlg.Destroy()
333        choice[4]()
334   
335    def OnAddFunction(event):
336        '''add a Function (new variable) constraint'''
337        constr = []
338        page = G2frame.Page
339        choice = scope[page[1]]
340        if page[1] == 'phs':
341            atchoice = [item+' for '+phaseAtNames[item] for item in choice[2]]
342            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],atchoice)
343        else:   
344            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],choice[2])
345        if dlg.ShowModal() == wx.ID_OK:
346            sel = dlg.GetSelection()
347            FrstVarb = choice[2][sel]
348            moreVarb = FindEquivVarb(FrstVarb,choice[2])
349            newcons = SelectVarbs(page,FrstVarb,moreVarb,choice[1],'function')
350            if len(newcons) > 0:
351                if CheckAddedConstraint(newcons):
352                    data[choice[3]] += newcons
353        dlg.Destroy()
354        choice[4]()
355                       
356    def OnAddConstraint(event):
357        '''add a constraint equation to the constraints list'''
358        constr = []
359        page = G2frame.Page
360        choice = scope[page[1]]
361        if page[1] == 'phs':
362            atchoice = [item+' for '+phaseAtNames[item] for item in choice[2]]
363            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],atchoice)
364        else:   
365            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],choice[2])
366        if dlg.ShowModal() == wx.ID_OK:
367            sel = dlg.GetSelection()
368            FrstVarb = choice[2][sel]
369            moreVarb = FindEquivVarb(FrstVarb,choice[2])
370            newcons = SelectVarbs(page,FrstVarb,moreVarb,choice[1],'constraint')
371            if len(newcons) > 0:
372                if CheckAddedConstraint(newcons):
373                    data[choice[3]] += newcons
374        dlg.Destroy()
375        choice[4]()
376                       
377    def ConstSizer(name,pageDisplay):
378        '''This creates a sizer displaying all of the constraints entered
379        '''
380        constSizer = wx.FlexGridSizer(1,4,0,0)
381        maxlen = 70 # characters before wrapping a constraint
382        for Id,item in enumerate(data[name]):
383            eqString = ['',]
384            if item[-1] == 'h':
385                constSizer.Add((5,5),0)              # blank space for edit button
386                typeString = ' FIXED   '
387                eqString[-1] = item[0][1]+'   '
388            elif isinstance(item[-1],str):
389                constEdit = wx.Button(pageDisplay,-1,'Edit',style=wx.BU_EXACTFIT)
390                constEdit.Bind(wx.EVT_BUTTON,OnConstEdit)
391                constSizer.Add(constEdit)            # edit button
392                Indx[constEdit.GetId()] = [Id,name]
393                if item[-1] == 'f':
394                    for term in item[:-3]:
395                        if len(eqString[-1]) > maxlen:
396                            eqString.append(' ')
397                        m = term[0]
398                        if eqString[-1] != '':
399                            if m >= 0:
400                                eqString[-1] += ' + '
401                            else:
402                                eqString[-1] += ' - '
403                                m = abs(m)
404                        eqString[-1] += '%.3f*%s '%(m,term[1])
405                    typeString = ' NEWVAR  '
406                    eqString[-1] += ' = New Variable   '
407                elif item[-1] == 'c':
408                    for term in item[:-3]:
409                        if len(eqString[-1]) > maxlen:
410                            eqString.append(' ')
411                        if eqString[-1] != '':
412                            if term[0] > 0:
413                                eqString[-1] += ' + '
414                            else:
415                                eqString[-1] += ' - '
416                        eqString[-1] += '%.3f*%s '%(abs(term[0]),term[1])
417                    typeString = ' CONSTR  '
418                    eqString[-1] += ' = %.3f'%(item[-3])+'  '
419                elif item[-1] == 'e':
420                    for term in item[:-3]:
421                        if term[0] == 0: term[0] = 1.0
422                        if len(eqString[-1]) > maxlen:
423                            eqString.append(' ')
424                        if eqString[-1] == '':
425                            eqString[-1] += '%s '%(term[1])
426                            first = term[0]
427                        else:
428                            eqString[-1] += ' = %.3f*%s '%(first/term[0],term[1])
429                    typeString = ' EQUIV   '
430                else:
431                    print 'Unexpected constraint',item
432            else:
433                print 'Removing old-style constraints'
434                data[name] = []
435                return constSizer
436            constDel = wx.Button(pageDisplay,-1,'Delete',style=wx.BU_EXACTFIT)
437            constDel.Bind(wx.EVT_BUTTON,OnConstDel)
438            Indx[constDel.GetId()] = [Id,name]
439            constSizer.Add(constDel)             # delete button
440            constSizer.Add(wx.StaticText(pageDisplay,-1,typeString),0,wx.ALIGN_CENTER_VERTICAL)
441            EqSizer = wx.BoxSizer(wx.VERTICAL)
442            for s in eqString:
443                EqSizer.Add(wx.StaticText(pageDisplay,-1,s),0,wx.ALIGN_CENTER_VERTICAL)
444            constSizer.Add(EqSizer,0,wx.ALIGN_CENTER_VERTICAL)
445            # if item[-1] == 'f':
446            #     constRef = wx.CheckBox(pageDisplay,-1,label=' Refine?')
447            #     constRef.SetValue(item[-2])
448            #     constRef.Bind(wx.EVT_CHECKBOX,OnConstRef)
449            #     Indx[constRef.GetId()] = item
450            #     constSizer.Add(constRef)
451            # else:
452            #     constSizer.Add((5,5),0)
453        return constSizer
454               
455    # def OnConstRef(event):
456    #     Obj = event.GetEventObject()
457    #     Indx[Obj.GetId()][-2] = Obj.GetValue()
458       
459    def OnConstDel(event):
460        Obj = event.GetEventObject()
461        Id,name = Indx[Obj.GetId()]
462        del(data[name][Id])
463        OnPageChanged(None)       
464       
465    def OnConstEdit(event):
466        '''Called to edit an individual contraint by the Edit button'''
467        Obj = event.GetEventObject()
468        Id,name = Indx[Obj.GetId()]
469        sep = '*'
470        if data[name][Id][-1] == 'f':
471            items = data[name][Id][:-3]+[[],]
472            constType = 'New Variable'
473            lbl = 'Enter value for each term in constraint; sum = new variable'
474        elif data[name][Id][-1] == 'c':
475            items = data[name][Id][:-3]+[
476                [data[name][Id][-3],'fixed value ='],[]]
477            constType = 'Constraint'
478            lbl = 'Edit value for each term in constant constraint sum'
479        elif data[name][Id][-1] == 'e':
480            items = data[name][Id][:-3]+[[],]
481            constType = 'Equivalence'
482            lbl = 'The following terms are set to be equal:'
483            sep = '/'
484        else:
485            return
486        dlg = G2frame.ConstraintDialog(G2frame.dataFrame,constType,lbl,items,sep)
487        try:
488            if dlg.ShowModal() == wx.ID_OK:
489                prev = data[name][Id]
490                result = dlg.GetData()
491                if data[name][Id][-1] == 'c':
492                    data[name][Id][:-3] = result[:-2]
493                    data[name][Id][-3] = result[-2][0]
494                else:
495                    data[name][Id][:-3] = result[:-1]
496                if not CheckChangedConstraint():
497                    data[name][Id] = prev
498        except:
499            import traceback
500            print traceback.format_exc()
501        finally:
502            dlg.Destroy()           
503        OnPageChanged(None)                     
504   
505    def UpdateHAPConstr():
506        '''Responds to press on Histogram/Phase Constraints tab,
507        shows constraints in data window'''
508        HAPConstr.DestroyChildren()
509        HAPDisplay = wx.Panel(HAPConstr)
510        HAPSizer = wx.BoxSizer(wx.VERTICAL)
511        HAPSizer.Add((5,5),0)
512        HAPSizer.Add(ConstSizer('HAP',HAPDisplay))
513        HAPDisplay.SetSizer(HAPSizer,True)
514        Size = HAPSizer.GetMinSize()
515        Size[0] += 40
516        Size[1] = max(Size[1],250) + 20
517        HAPDisplay.SetSize(Size)
518        # scroll bar not working, at least not on Mac
519        HAPConstr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
520        Size[1] = min(Size[1],250)
521        G2frame.dataFrame.setSizePosLeft(Size)
522       
523    def UpdateHistConstr():
524        '''Responds to press on Histogram Constraints tab,
525        shows constraints in data window'''
526        HistConstr.DestroyChildren()
527        HistDisplay = wx.Panel(HistConstr)
528        HistSizer = wx.BoxSizer(wx.VERTICAL)
529        HistSizer.Add((5,5),0)       
530        HistSizer.Add(ConstSizer('Hist',HistDisplay))
531        HistDisplay.SetSizer(HistSizer,True)
532        Size = HistSizer.GetMinSize()
533        Size[0] += 40
534        Size[1] = max(Size[1],250) + 20
535        HistDisplay.SetSize(Size)
536        HistConstr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
537        Size[1] = min(Size[1],250)
538        G2frame.dataFrame.setSizePosLeft(Size)
539       
540    def UpdatePhaseConstr():
541        '''Responds to press on Phase Constraint tab,
542        shows constraints in data window'''
543        PhaseConstr.DestroyChildren()
544        PhaseDisplay = wx.Panel(PhaseConstr)
545        PhaseSizer = wx.BoxSizer(wx.VERTICAL)
546        PhaseSizer.Add((5,5),0)       
547        PhaseSizer.Add(ConstSizer('Phase',PhaseDisplay))
548        PhaseDisplay.SetSizer(PhaseSizer,True)
549        Size = PhaseSizer.GetMinSize()
550        Size[0] += 40
551        Size[1] = max(Size[1],250) + 20
552        PhaseDisplay.SetSize(Size)
553        PhaseConstr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
554        Size[1] = min(Size[1],250)
555        G2frame.dataFrame.setSizePosLeft(Size)
556   
557    def OnPageChanged(event):
558        if event:       #page change event!
559            page = event.GetSelection()
560        else:
561            page = G2frame.dataDisplay.GetSelection()
562        oldPage = G2frame.dataDisplay.ChangeSelection(page)
563        text = G2frame.dataDisplay.GetPageText(page)
564        if text == 'Histogram/Phase constraints':
565            G2frame.Page = [page,'hap']
566            UpdateHAPConstr()
567        elif text == 'Histogram constraints':
568            G2frame.Page = [page,'hst']
569            UpdateHistConstr()
570        elif text == 'Phase constraints':
571            G2frame.Page = [page,'phs']
572            UpdatePhaseConstr()
573
574    def SetStatusLine(text):
575        Status.SetStatusText(text)                                     
576       
577    plegend,hlegend,phlegend = GetPHlegends(Phases,Histograms)
578    scope = {'hst':['Histogram contraints:',hlegend,histList,'Hist',UpdateHistConstr],
579        'hap':['Histogram * Phase contraints:',phlegend,hapList,'HAP',UpdateHAPConstr],
580        'phs':['Phase contraints:',plegend,phaseList,'Phase',UpdatePhaseConstr]}
581    if G2frame.dataDisplay:
582        G2frame.dataDisplay.Destroy()
583    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ConstraintMenu)
584    G2frame.dataFrame.SetLabel('Constraints')
585    if not G2frame.dataFrame.GetStatusBar():
586        Status = G2frame.dataFrame.CreateStatusBar()
587    SetStatusLine('')
588   
589    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ConstraintMenu)
590    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddConstraint, id=G2gd.wxID_CONSTRAINTADD)
591    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddFunction, id=G2gd.wxID_FUNCTADD)
592    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddEquivalence, id=G2gd.wxID_EQUIVADD)
593    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddHold, id=G2gd.wxID_HOLDADD)
594    G2frame.dataDisplay = G2gd.GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
595   
596    PhaseConstr = wx.ScrolledWindow(G2frame.dataDisplay)
597    G2frame.dataDisplay.AddPage(PhaseConstr,'Phase constraints')
598    HAPConstr = wx.ScrolledWindow(G2frame.dataDisplay)
599    G2frame.dataDisplay.AddPage(HAPConstr,'Histogram/Phase constraints')
600    HistConstr = wx.ScrolledWindow(G2frame.dataDisplay)
601    G2frame.dataDisplay.AddPage(HistConstr,'Histogram constraints')
602    UpdatePhaseConstr()
603
604    G2frame.dataDisplay.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, OnPageChanged)
605    # validate all the constrants -- should not see any errors here normally
606    allcons = []
607    for key in 'Hist','HAP','Phase':
608        allcons += data[key]
609    if not len(allcons): return
610    G2mv.InitVars()   
611    constDictList,fixedList,ignored = G2str.ProcessConstraints(allcons)
612    errmsg, warnmsg = G2mv.CheckConstraints('',constDictList,fixedList)
613    if errmsg:
614        G2frame.ErrorDialog('Constraint Error','Error in constraints:\n'+errmsg,
615            parent=G2frame.dataFrame)
616    elif warnmsg:
617        print 'Unexpected contraint warning:\n',warnmsg
618       
619################################################################################
620#### Rigid bodies
621################################################################################
622
623def UpdateRigidBodies(G2frame,data):
624    '''Called when Rigid bodies tree item is selected.
625    Displays the rigid bodies in the data window
626    '''
627    if not data:
628        data.update({'Vector':{'AtInfo':{}},'Residue':{'AtInfo':{}},'Z-matrix':{'AtInfo':{}}})       #empty dict - fill it
629           
630    Indx = {}
631    plotDefaults = {'oldxy':[0.,0.],'Quaternion':[1.,0.,0.,0.],'cameraPos':20.,'viewDir':[0,0,1],}
632
633    def OnPageChanged(event):
634        if event:       #page change event!
635            page = event.GetSelection()
636        else:
637            page = G2frame.dataDisplay.GetSelection()
638        oldPage = G2frame.dataDisplay.ChangeSelection(page)
639        text = G2frame.dataDisplay.GetPageText(page)
640        if text == 'Vector rigid bodies':
641            G2frame.Page = [page,'vrb']
642            UpdateVectorRB()
643        elif text == 'Residue rigid bodies':
644            G2frame.Page = [page,'rrb']
645            UpdateResidueRB()
646        elif text == 'Z-matrix rigid bodies':
647            G2frame.Page = [page,'zrb']
648            UpdateZMatrixRB()
649           
650    def getMacroFile(macName):
651        defDir = os.path.join(os.path.split(__file__)[0],'GSASIImacros')
652        dlg = wx.FileDialog(G2frame,message='Choose '+macName+' rigid body macro file',
653            defaultDir=defDir,defaultFile="",wildcard="GSAS-II macro file (*.mac)|*.mac",
654            style=wx.OPEN | wx.CHANGE_DIR)
655        try:
656            if dlg.ShowModal() == wx.ID_OK:
657                macfile = dlg.GetPath()
658                macro = open(macfile,'Ur')
659                head = macro.readline()
660                if macName not in head:
661                    print head
662                    print '**** ERROR - wrong restraint macro file selected, try again ****'
663                    macro = []
664            else: # cancel was pressed
665                macxro = []
666        finally:
667            dlg.Destroy()
668        return macro        #advanced past 1st line
669       
670    def OnAddRigidBody(event):
671        page = G2frame.dataDisplay.GetSelection()
672        if 'Vector' in G2frame.dataDisplay.GetPageText(page):
673            AddVectorRB()
674        elif 'Residue' in G2frame.dataDisplay.GetPageText(page):
675            AddResidueRB()
676        elif 'Z-matrix' in G2frame.dataDisplay.GetPageText(page):
677            AddZMatrixRB()
678           
679    def AddVectorRB():
680        AtInfo = data['Vector']['AtInfo']
681        dlg = MultiIntegerDialog(G2frame.dataDisplay,'New Rigid Body',['No. atoms','No. translations'],[1,1])
682        if dlg.ShowModal() == wx.ID_OK:
683            nAtoms,nTrans = dlg.GetValues()
684            vectorRB = data['Vector']
685            rbId = ran.randint(0,sys.maxint)
686            vecMag = [1.0 for i in range(nTrans)]
687            vecRef = [False for i in range(nTrans)]
688            vecVal = [np.zeros((nAtoms,3)) for j in range(nTrans)]
689            rbTypes = ['C' for i in range(nAtoms)]
690            Info = G2elem.GetAtomInfo('C')
691            AtInfo['C'] = [Info['Drad'],Info['Color']]
692            data['Vector'][rbId] = {'RBname':'UNKRB','VectMag':vecMag,
693                'VectRef':vecRef,'rbTypes':rbTypes,'rbVect':vecVal}
694        dlg.Destroy()
695        UpdateVectorRB()
696       
697    def AddResidueRB():
698        AtInfo = data['Residue']['AtInfo']
699        macro = getMacroFile('rigid body')
700        if not macro:
701            return
702        macStr = macro.readline()
703        while macStr:
704            items = macStr.split()
705            print items
706            if 'I' == items[0]:
707                rbId = ran.randint(0,sys.maxint)
708                rbName = items[1]
709                rbTypes = []
710                rbXYZ = []
711                rbSeq = []
712                atNames = []
713                nAtms,nSeq,nOrig,mRef,nRef = [int(items[i]) for i in [2,3,4,5,6]]
714                for iAtm in range(nAtms):
715                    macStr = macro.readline().split()
716                    atName = macStr[0]
717                    atNames.append(atName)
718                    rbXYZ.append([float(macStr[i]) for i in [1,2,3]])
719                    atNames.append(atName[0])          #might not always work
720                    if atName[0] not in AtInfo:
721                        Info = G2elem.GetAtomInfo(atName[0])
722                        AtInfo[atName[0]] = [Info['Drad'],Info['Color']]
723                rbXYZ = np.array(rbXYZ)-np.array(rbXYZ[nOrig-1])
724                for iSeq in range(nSeq):
725                    macStr = macro.readline().split()
726                    mSeq = int(macStr[0])
727                    rbseq = []
728                    for jSeq in range(mSeq):
729                        macStr = macro.readline().split()
730                        iBeg = int(macStr[0])-1
731                        iFin = int(macStr[1])-1
732                        nMove = int(macStr[2])
733                        iMove = [int(macStr[i]) for i in range(3,nMove+3)]
734                        rbseq.append([iBeg,iFin,iMove])
735                    rbSeq.append(rbseq)
736                data['Residue'][rbId] = {'RBname':rbName,'rbXYZ':rbXYZ,'rbTypes':rbTypes,
737                    'atNames':atNames,'rbRef':[nOrig-1,mRef-1,nRef-1],'rbSeq':rbSeq}
738            macStr = macro.readline()
739        macro.close()
740       
741    def AddZMatrixRB():
742        pass
743
744    def UpdateVectorRB():
745        AtInfo = data['Vector']['AtInfo']
746        SetStatusLine(' You may use e.g. "sind(60)", "cos(60)", "c60" or "s60" for a vector entry')
747        def rbNameSizer(rbId,rbData):
748
749            def OnRBName(event):
750                Obj = event.GetEventObject()
751                rbId = Indx[Obj.GetId()]
752                rbData['RBname'] = Obj.GetValue()
753               
754            def OnDelRB(event):
755                Obj = event.GetEventObject()
756                rbId = Indx[Obj.GetId()]
757                del data['Vector'][rbId]
758                wx.CallAfter(UpdateVectorRB)
759               
760            def OnPlotRB(event):
761                Obj = event.GetEventObject()
762                rbId = Indx[Obj.GetId()]
763                Obj.SetValue(False)
764                G2plt.PlotRigidBody(G2frame,'Vector',AtInfo,rbData,plotDefaults)
765           
766            nameSizer = wx.BoxSizer(wx.HORIZONTAL)
767            nameSizer.Add(wx.StaticText(VectorRBDisplay,-1,'Rigid body name: '),
768                0,wx.ALIGN_CENTER_VERTICAL)
769            RBname = wx.TextCtrl(VectorRBDisplay,-1,rbData['RBname'])
770            Indx[RBname.GetId()] = rbId
771            RBname.Bind(wx.EVT_TEXT_ENTER,OnRBName)
772            RBname.Bind(wx.EVT_KILL_FOCUS,OnRBName)
773            nameSizer.Add(RBname,0,wx.ALIGN_CENTER_VERTICAL)
774            nameSizer.Add((5,0),)
775            plotRB = wx.CheckBox(VectorRBDisplay,-1,'Plot?')
776            Indx[plotRB.GetId()] = rbId
777            plotRB.Bind(wx.EVT_CHECKBOX,OnPlotRB)
778            nameSizer.Add(plotRB,0,wx.ALIGN_CENTER_VERTICAL)
779            nameSizer.Add((5,0),)
780            delRB = wx.CheckBox(VectorRBDisplay,-1,'Delete?')
781            Indx[delRB.GetId()] = rbId
782            delRB.Bind(wx.EVT_CHECKBOX,OnDelRB)
783            nameSizer.Add(delRB,0,wx.ALIGN_CENTER_VERTICAL)
784            return nameSizer
785           
786        def rbVectMag(rbId,imag,rbData):
787           
788            def OnRBVectorMag(event):
789                Obj = event.GetEventObject()
790                rbId,imag = Indx[Obj.GetId()]
791                try:
792                    val = float(Obj.GetValue())
793                    if val <= 0.:
794                        raise ValueError
795                    rbData['VectMag'][imag] = val
796                except ValueError:
797                    pass
798                Obj.SetValue('%8.3f'%(val))
799                UpdateVectorRB()
800                G2plt.PlotRigidBody(G2frame,'Vector',AtInfo,data['Vector'][rbId],plotDefaults)
801               
802            def OnRBVectorRef(event):
803                Obj = event.GetEventObject()
804                rbId,imag = Indx[Obj.GetId()]
805                rbData['VectRef'][imag] = Obj.GetValue()
806                       
807            magSizer = wx.wx.BoxSizer(wx.HORIZONTAL)
808            magSizer.Add(wx.StaticText(VectorRBDisplay,-1,'Translation magnitude: '),
809                0,wx.ALIGN_CENTER_VERTICAL)
810            magValue = wx.TextCtrl(VectorRBDisplay,-1,'%8.3f'%(rbData['VectMag'][imag]))
811            Indx[magValue.GetId()] = [rbId,imag]
812            magValue.Bind(wx.EVT_TEXT_ENTER,OnRBVectorMag)
813            magValue.Bind(wx.EVT_KILL_FOCUS,OnRBVectorMag)
814            magSizer.Add(magValue,0,wx.ALIGN_CENTER_VERTICAL)
815            magSizer.Add((5,0),)
816            magref = wx.CheckBox(VectorRBDisplay,-1,label=' Refine?') 
817            magref.SetValue(rbData['VectRef'][imag])
818            magref.Bind(wx.EVT_CHECKBOX,OnRBVectorRef)
819            Indx[magref.GetId()] = [rbId,imag]
820            magSizer.Add(magref,0,wx.ALIGN_CENTER_VERTICAL)
821            return magSizer
822           
823        def rbVectors(rbId,imag,mag,XYZ,rbData):
824
825            def TypeSelect(event):
826                AtInfo = data['Vector']['AtInfo']
827                r,c = event.GetRow(),event.GetCol()
828                if vecGrid.GetColLabelValue(c) == 'Type':
829                    PE = G2elemGUI.PickElement(G2frame,oneOnly=True)
830                    if PE.ShowModal() == wx.ID_OK:
831                        if PE.Elem != 'None':
832                            El = PE.Elem.strip().lower().capitalize()
833                            if El not in AtInfo:
834                                Info = G2elem.GetAtomInfo(El)
835                                AtInfo[El] = [Info['Drad']['Color']]
836                            rbData['rbTypes'][r] = El
837                            vecGrid.SetCellValue(r,c,El)
838                    PE.Destroy()
839
840            def ChangeCell(event):
841                r,c =  event.GetRow(),event.GetCol()
842                if r >= 0 and (0 <= c < 3):
843                    try:
844                        val = float(vecGrid.GetCellValue(r,c))
845                        rbData['rbVect'][imag][r][c] = val
846                    except ValueError:
847                        pass
848                wx.CallAfter(UpdateVectorRB)
849
850            vecSizer = wx.BoxSizer()
851            Types = 3*[wg.GRID_VALUE_FLOAT+':10,5',]+[wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,5',]
852            colLabels = ['Vector x','Vector y','Vector z','Type','Cart x','Cart y','Cart z']
853            table = []
854            rowLabels = []
855            for ivec,xyz in enumerate(rbData['rbVect'][imag]):
856                table.append(list(xyz)+[rbData['rbTypes'][ivec],]+list(XYZ[ivec]))
857                rowLabels.append(str(ivec))
858            vecTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
859            vecGrid = G2gd.GSGrid(VectorRBDisplay)
860            vecGrid.SetTable(vecTable, True)
861            vecGrid.Bind(wg.EVT_GRID_CELL_CHANGE, ChangeCell)
862            vecGrid.Bind(wg.EVT_GRID_CELL_LEFT_DCLICK, TypeSelect)
863            attr = wx.grid.GridCellAttr()
864            attr.SetEditor(G2phG.GridFractionEditor(vecGrid))
865            for c in range(3):
866                vecGrid.SetColAttr(c, attr)
867            for row in range(vecTable.GetNumberRows()):
868                for col in [4,5,6]:
869                    vecGrid.SetCellStyle(row,col,VERY_LIGHT_GREY,True)
870            vecSizer.Add(vecGrid)
871            return vecSizer
872       
873        VectorRB.DestroyChildren()
874        VectorRBDisplay = wx.Panel(VectorRB)
875        VectorRBSizer = wx.BoxSizer(wx.VERTICAL)
876        for rbId in data['Vector']:
877            if rbId != 'AtInfo':
878                rbData = data['Vector'][rbId]
879                VectorRBSizer.Add(rbNameSizer(rbId,rbData),0)
880                XYZ = np.array([[0.,0.,0.] for Ty in rbData['rbTypes']])
881                for imag,mag in enumerate(rbData['VectMag']):
882                    XYZ += mag*rbData['rbVect'][imag]
883                    VectorRBSizer.Add(rbVectMag(rbId,imag,rbData),0)
884                    VectorRBSizer.Add(rbVectors(rbId,imag,mag,XYZ,rbData),0)
885                VectorRBSizer.Add((5,5),0)       
886        VectorRBSizer.Layout()   
887        VectorRBDisplay.SetSizer(VectorRBSizer,True)
888        Size = VectorRBSizer.GetMinSize()
889        Size[0] += 40
890        Size[1] = max(Size[1],250) + 20
891        VectorRBDisplay.SetSize(Size)
892        VectorRB.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
893#        Size[1] = min(Size[1],450)
894        G2frame.dataFrame.setSizePosLeft(Size)
895       
896    def UpdateResidueRB():
897        ResidueRB.DestroyChildren()
898        ResidueRBDisplay = wx.Panel(ResidueRB)
899        ResidueRBSizer = wx.BoxSizer(wx.VERTICAL)
900        ResidueRBSizer.Add((5,5),0)       
901#        VectorRBSizer.Add(ConstSizer('Phase',PhaseDisplay))
902        ResidueRBSizer.Layout()   
903        ResidueRBDisplay.SetSizer(ResidueRBSizer,True)
904        Size = ResidueRBSizer.GetMinSize()
905        Size[0] += 40
906        Size[1] = max(Size[1],250) + 20
907        ResidueRBDisplay.SetSize(Size)
908        ResidueRB.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
909#        Size[1] = min(Size[1],250)
910        G2frame.dataFrame.setSizePosLeft(Size)
911       
912    def UpdateZMatrixRB():
913        ZMatrixRB.DestroyChildren()
914        ZMatrixRBDisplay = wx.Panel(ZMatrixRB)
915        ZMatrixRBSizer = wx.BoxSizer(wx.VERTICAL)
916        ZMatrixRBSizer.Add((5,5),0)       
917#        ZMatrixRBSizer.Add(ConstSizer('Phase',PhaseDisplay))
918        ZMatrixRBSizer.Layout()   
919        ZMatrixRBDisplay.SetSizer(ZMatrixRBSizer,True)
920        Size = ZMatrixRBSizer.GetMinSize()
921        Size[0] += 40
922        Size[1] = max(Size[1],250) + 20
923        ZMatrixRBDisplay.SetSize(Size)
924        ZMatrixRB.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
925#        Size[1] = min(Size[1],250)
926        G2frame.dataFrame.setSizePosLeft(Size)
927
928    def SetStatusLine(text):
929        Status.SetStatusText(text)                                     
930
931    if G2frame.dataDisplay:
932        G2frame.dataDisplay.Destroy()
933    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RigidBodyMenu)
934    G2frame.dataFrame.SetLabel('Rigid bodies')
935    if not G2frame.dataFrame.GetStatusBar():
936        Status = G2frame.dataFrame.CreateStatusBar()
937    SetStatusLine('')
938
939    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RigidBodyMenu)
940    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddRigidBody, id=G2gd.wxID_RIGIDBODYADD)   
941    G2frame.dataDisplay = G2gd.GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
942
943    VectorRB = wx.ScrolledWindow(G2frame.dataDisplay)
944    G2frame.dataDisplay.AddPage(VectorRB,'Vector rigid bodies')
945    ResidueRB = wx.ScrolledWindow(G2frame.dataDisplay)
946    G2frame.dataDisplay.AddPage(ResidueRB,'Residue rigid bodies')
947    ZMatrix = wx.ScrolledWindow(G2frame.dataDisplay)
948    G2frame.dataDisplay.AddPage(ZMatrix,'Z-matrix rigid bodies')
949    UpdateVectorRB()
950   
Note: See TracBrowser for help on using the repository browser.