source: trunk/GSASIIrestrGUI.py @ 812

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

add restraint macro files
fix a triclinic error in genHlaue
continue development of restraints

File size: 45.3 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIrestr - restraint 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/GSASIIrestrGUI.py $
8# $Id: GSASIIrestrGUI.py 810 2012-12-05 21:38:26Z vondreele $
9########### SVN repository information ###################
10import wx
11import wx.grid as wg
12import time
13import numpy as np
14import numpy.ma as ma
15import os.path
16import GSASIIpath
17GSASIIpath.SetVersionNumber("$Revision: 810 $")
18import GSASIImath as G2mth
19import GSASIIlattice as G2lat
20import GSASIIphsGUI as G2phG
21import GSASIIspc as G2spc
22import GSASIIgrid as G2gd
23
24VERY_LIGHT_GREY = wx.Colour(235,235,235)
25
26################################################################################
27#####  Restraints
28################################################################################           
29       
30def UpdateRestraints(G2frame,data,Phases,phaseName):
31    if not len(Phases):
32        print 'There are no phases to form restraints'
33        return
34    phasedata = Phases[phaseName]
35    if phaseName not in data:
36        data[phaseName] = {}
37    restrData = data[phaseName]
38    if 'Bond' not in restrData:
39        restrData['Bond'] = {'wtFactor':1.0,'Bonds':[],'Use':True}
40    if 'Angle' not in restrData:
41        restrData['Angle'] = {'wtFactor':1.0,'Angles':[],'Use':True}
42    if 'Plane' not in restrData:
43        restrData['Plane'] = {'wtFactor':1.0,'Planes':[],'Use':True}
44    if 'Chiral' not in restrData:
45        restrData['Chiral'] = {'wtFactor':1.0,'Volumes':[],'Use':True}
46    if 'Torsion' not in restrData:
47        restrData['Torsion'] = {'wtFactor':1.0,'Coeff':{},'Torsions':[],'Use':True}
48    if 'Rama' not in restrData:
49        restrData['Rama'] = {'wtFactor':1.0,'Coeff':{},'Ramas':[],'Use':True}
50    General = phasedata['General']
51    Cell = General['Cell'][1:7]          #skip flag & volume   
52    Amat,Bmat = G2lat.cell2AB(Cell)
53    SGData = General['SGData']
54    cx,ct = General['AtomPtrs'][:2]
55    Atoms = phasedata['Atoms']
56    AtLookUp = G2mth.FillAtomLookUp(Atoms)
57    if 'macro' in General['Type']:
58        Names = [atom[0]+atom[1]+atom[2]+' '+atom[3] for atom in Atoms]
59        Ids = []
60        Coords = []
61        Types = []
62    else:   
63        Names = ['all '+ name for name in General['AtomTypes']]
64        iBeg = len(Names)
65        Types = [name for name in General['AtomTypes']]
66        Coords = [ [] for type in Types]
67        Ids = [ 0 for type in Types]
68        Names += [atom[ct-1] for atom in Atoms]
69    Types += [atom[ct] for atom in Atoms]
70    Coords += [atom[cx:cx+3] for atom in Atoms]
71    Ids += [atom[-1] for atom in Atoms]
72   
73    def OnSelectPhase(event):
74        dlg = wx.SingleChoiceDialog(G2frame,'Select','Phase',Phases.keys())
75        try:
76            if dlg.ShowModal() == wx.ID_OK:
77                phaseName = Phases.keys()[dlg.GetSelection()]
78                UpdateRestraints(G2frame,data,Phases,phaseName)
79        finally:
80            dlg.Destroy()
81   
82    def getMacroFile(macName):
83        defDir = os.path.join(os.path.split(__file__)[0],'GSASIImacros')
84        dlg = wx.FileDialog(G2frame,message='Choose '+macName+' restraint macro file',
85            defaultDir=defDir,defaultFile="",wildcard="GSAS-II macro file (*.mac)|*.mac",
86            style=wx.OPEN | wx.CHANGE_DIR)
87        try:
88            if dlg.ShowModal() == wx.ID_OK:
89                macfile = dlg.GetPath()
90                macro = open(macfile,'Ur')
91                head = macro.readline()
92                if macName not in head:
93                    print head
94                    print '**** ERROR - wrong restraint macro file selected, try again ****'
95                    macro = []
96            else: # cancel was pressed
97                macxro = []
98        finally:
99            dlg.Destroy()
100        return macro        #advanced past 1st line
101       
102    def OnAddRestraint(event):
103        page = G2frame.dataDisplay.GetSelection()
104        if 'Bond' in G2frame.dataDisplay.GetPageText(page):
105            bondRestData = restrData['Bond']
106            AddBondRestraint(bondRestData)
107        elif 'Angle' in G2frame.dataDisplay.GetPageText(page):
108            angleRestData = restrData['Angle']
109            AddAngleRestraint(angleRestData)
110        elif 'Plane' in G2frame.dataDisplay.GetPageText(page):
111            AddPlaneRestraint()
112        elif 'Chiral' in G2frame.dataDisplay.GetPageText(page):
113            AddChiralRestraint()
114        elif 'Torsion' in G2frame.dataDisplay.GetPageText(page):
115            AddTorsionRestraint()
116        elif 'Rama' in G2frame.dataDisplay.GetPageText(page):
117            AddRamaRestraint()
118           
119    def OnAddAARestraint(event):
120        page = G2frame.dataDisplay.GetSelection()
121        if 'Bond' in G2frame.dataDisplay.GetPageText(page):
122            bondRestData = restrData['Bond']
123            AddAABondRestraint(bondRestData)
124        elif 'Angle' in G2frame.dataDisplay.GetPageText(page):
125            angleRestData = restrData['Angle']
126            AddAAAngleRestraint(angleRestData)
127        elif 'Plane' in G2frame.dataDisplay.GetPageText(page):
128            AddAAPlaneRestraint()
129        elif 'Chiral' in G2frame.dataDisplay.GetPageText(page):
130            AddAAChiralRestraint()
131        elif 'Torsion' in G2frame.dataDisplay.GetPageText(page):
132            AddAATorsionRestraint()
133        elif 'Rama' in G2frame.dataDisplay.GetPageText(page):
134            AddAARamaRestraint()
135           
136    def AddBondRestraint(bondRestData):
137        Radii = dict(zip(General['AtomTypes'],General['BondRadii']))
138        Lists = {'origin':[],'target':[]}
139        for listName in ['origin','target']:
140            dlg = wx.MultiChoiceDialog(G2frame,'Bond restraint '+listName+' for '+General['Name'],
141                    'Select bond restraint '+listName+' atoms',Names)
142            if dlg.ShowModal() == wx.ID_OK:
143                sel = dlg.GetSelections()
144                for x in sel:
145                    if 'all' in Names[x]:
146                        allType = Types[x]
147                        for name,Type,coords,id in zip(Names,Types,Coords,Ids):
148                            if Type == allType and 'all' not in name:
149                                Lists[listName].append([id,Type,coords])
150                    else:
151                        Lists[listName].append([Ids[x],Types[x],Coords[x],])
152        Factor = .85
153        indices = (-1,0,1)
154        Units = np.array([[h,k,l] for h in indices for k in indices for l in indices])
155        origAtoms = Lists['origin']
156        targAtoms = Lists['target']
157        dlg = wx.ProgressDialog("Generating bond restraints","Processed origin atoms",len(origAtoms), 
158            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME)
159        try:
160            Norig = 0
161            for Oid,Otype,Ocoord in origAtoms:
162                Norig += 1
163                dlg.Update(Norig)
164                for Tid,Ttype,Tcoord in targAtoms:
165                    if 'macro' in General['Type']:
166                        result = [[Tcoord,1,[0,0,0]],]
167                    else:
168                        result = G2spc.GenAtom(Tcoord,SGData,False,Move=False)
169                    BsumR = (Radii[Otype]+Radii[Ttype])*Factor
170                    for Txyz,Top,Tunit in result:
171                        Dx = (Txyz-np.array(Ocoord))+Units
172                        dx = np.inner(Amat,Dx)
173                        dist = ma.masked_less(np.sqrt(np.sum(dx**2,axis=0)),0.5)
174                        IndB = ma.nonzero(ma.masked_greater(dist-BsumR,0.))
175                        if np.any(IndB):
176                            for indb in IndB:
177                                for i in range(len(indb)):
178                                    unit = Units[indb][i]+Tunit
179                                    if np.any(unit):
180                                        Topstr = '%d+%d,%d,%d'%(Top,unit[0],unit[1],unit[2])
181                                    else:
182                                        Topstr = str(Top)
183                                    bondRestData['Bonds'].append([[Oid,Tid],['1',Topstr], \
184                                        ma.getdata(dist[indb])[i],1.54,0.01])
185        finally:
186            dlg.Destroy()
187        UpdateBondRestr(bondRestData)               
188
189    def AddAABondRestraint(bondRestData):
190        Radii = dict(zip(General['AtomTypes'],General['BondRadii']))
191        macro = getMacroFile('bond')
192        if not macro:
193            return
194        macStr = macro.readline()
195        atoms = zip(Names,Types,Coords,Ids)
196       
197        Factor = .85
198        while macStr:
199            items = macStr.split()
200            if 'F' in items[0]:
201                restrData['Bond']['wtFactor'] = float(items[1])
202            elif 'S' in items[0]:
203                oIds = []
204                oTypes = []
205                oCoords = []
206                tIds = []
207                tTypes = []
208                tCoords = []
209                res = items[1]
210                dist = float(items[2])
211                esd = float(items[3])
212                oAtm,tAtm = items[4:6]
213                for Name,Type,coords,Id in atoms:
214                    names = Name.split()
215                    if res == '*' or res in names[0]:
216                        if oAtm == names[2]:
217                            oIds.append(Id)
218                            oTypes.append(Type)
219                            oCoords.append(np.array(coords))
220                        if tAtm == names[2]:
221                            tIds.append(Id)
222                            tTypes.append(Type)
223                            tCoords.append(np.array(coords))
224                for oId,oType,oCoord in zip(oIds,oTypes,oCoords):
225                    for tId,tType,tCoord in zip(tIds,tTypes,tCoords):
226                        BsumR = (Radii[oType]+Radii[tType])*Factor
227                        obsd = np.sqrt(np.sum(np.inner(Amat,tCoord-oCoord)**2))
228                        if 0.2 < obsd <= BsumR:
229                            bondRestData['Bonds'].append([[oId,tId],['1','1'],obsd,dist,esd])                         
230            macStr = macro.readline()
231        macro.close()
232        UpdateBondRestr(bondRestData)               
233           
234    def AddAngleRestraint(angleRestData):
235        Radii = dict(zip(General['AtomTypes'],zip(General['BondRadii'],General['AngleRadii'])))
236        origAtoms = []
237        dlg = wx.MultiChoiceDialog(G2frame,'Select atom B for angle A-B-C for '+General['Name'],
238                'Select angle restraint origin atoms',Names)
239        if dlg.ShowModal() == wx.ID_OK:
240            sel = dlg.GetSelections()
241            for x in sel:
242                if 'all' in Names[x]:
243                    allType = Types[x]
244                    for name,Type,coords,id in zip(Names,Types,Coords,Ids):
245                        if Type == allType and 'all' not in name:
246                            origAtoms.append([id,Type,coords])
247                else:
248                    origAtoms.append([Ids[x],Types[x],Coords[x]])
249        targAtoms = [[Ids[x+iBeg],Types[x+iBeg],Coords[x+iBeg]] for x in range(len(Names[iBeg:]))]
250
251        Factor = 1.0
252        indices = (-1,0,1)
253        Units = np.array([[h,k,l] for h in indices for k in indices for l in indices])
254        VectA = []
255        for Oid,Otype,Ocoord in origAtoms:
256            IndBlist = []
257            angles = []
258            VectB = []
259            for Tid,Ttype,Tcoord in targAtoms:
260                result = G2spc.GenAtom(Tcoord,SGData,False,Move=False)
261                BsumR = (Radii[Otype][0]+Radii[Ttype][0])*Factor
262                AsumR = (Radii[Otype][1]+Radii[Ttype][1])*Factor
263                for Txyz,Top,Tunit in result:
264                    Dx = (Txyz-Ocoord)+Units
265                    dx = np.inner(Amat,Dx)
266                    dist = ma.masked_less(np.sqrt(np.sum(dx**2,axis=0)),0.5)
267                    IndB = ma.nonzero(ma.masked_greater(dist-BsumR,0.))
268                    if np.any(IndB):
269                        for indb in IndB:
270                            for i in range(len(indb)):
271                                if str(dx.T[indb][i]) not in IndBlist:
272                                    IndBlist.append(str(dx.T[indb][i]))
273                                    unit = Units[indb][i]+Tunit
274                                if np.any(unit):
275                                    Topstr = '%d+%d,%d,%d'%(Top,unit[0],unit[1],unit[2])
276                                else:
277                                    Topstr = str(Top)
278                                    tunit = '[%2d%2d%2d]'%(unit[0]+Tunit[0],unit[1]+Tunit[1],unit[2]+Tunit[2])
279                                    Dist = ma.getdata(dist[indb])[i]
280                                    if (Dist-AsumR) <= 0.:
281                                        VectB.append([Oid,'1',Ocoord,Tid,Topstr,Tcoord,Dist])
282            VectA.append(VectB)
283            for Vects in VectA:
284                for i,vecta in enumerate(Vects):                   
285                    for vectb in Vects[:i]:
286                        ids = [vecta[3],vecta[0],vectb[3]]
287                        ops = [vecta[4],vecta[1],vectb[4]]
288                        XYZ = np.array([vecta[5],vecta[2],vectb[5]])
289                        angle = G2mth.getRestAngle(XYZ,Amat)
290                        angles.append([ids,ops,angle,109.5,1.0])
291            angleRestData['Angles'] += angles
292        UpdateAngleRestr(angleRestData)               
293
294    def AddAAAngleRestraint(angleRestData):
295        macro = getMacroFile('angle')
296        if not macro:
297            return
298        macStr = macro.readline()
299        while macStr:
300            items = macStr.split()
301            print items
302            if 'F' in items[0]:
303                restrData['Angle']['wtFactor'] = float(items[1])
304            elif 'S' in items[0]:
305                List = []
306                res = items[1]
307                dist = items[2]
308                esd = items[3]
309                oAtm = items[4]
310                tAtm = items[5]
311                for name,Type,coords,id in zip(Names,Types,Coords,Ids):
312                    if res == '*' or res in name:
313                        if oAtm in name:
314                            oCoord = coords
315                            oId = id
316                            oName = name
317                        elif tAtm in name:
318                            tCoord = coords
319                            tId = id
320                            tName = name
321               
322            macStr = macro.readline()
323        macro.close()
324        UpdateAngleRestr(angleRestData)               
325       
326    def AddPlaneRestraint():
327        origAtoms = []
328        dlg = wx.MultiChoiceDialog(G2frame,'Select atom B for angle A-B-C for '+General['Name'],
329                'Select angle restraint origin atoms',Names)
330        if dlg.ShowModal() == wx.ID_OK:
331            sel = dlg.GetSelections()
332            for x in sel:
333                if 'all' in Names[x]:
334                    allType = Types[x]
335                    for name,Type,coords,id in zip(Names,Types,Coords,Ids):
336                        if Type == allType and 'all' not in name:
337                            origAtoms.append([id,Type,coords])
338                else:
339                    origAtoms.append([Ids[x],Types[x],Coords[x]])
340
341    def AddAAPlaneRestraint():
342        macro = getMacroFile('plane')
343        if not macro:
344            return
345        macStr = macro.readline()
346        while macStr:
347            items = macStr.split()
348            print items
349            if 'F' in items[0]:
350                restrData['Plane']['wtFactor'] = float(items[1])
351            elif 'S' in items[0]:
352                List = []
353                res = items[1]
354                dist = items[2]
355                esd = items[3]
356                oAtm = items[4]
357                tAtm = items[5]
358                for name,Type,coords,id in zip(Names,Types,Coords,Ids):
359                    if res == '*' or res in name:
360                        if oAtm in name:
361                            oCoord = coords
362                            oId = id
363                            oName = name
364                        elif tAtm in name:
365                            tCoord = coords
366                            tId = id
367                            tName = name
368               
369            macStr = macro.readline()
370        macro.close()
371
372    def AddChiralRestraint():
373        print 'Chiral restraint'
374       
375    def AddAAChiralRestraint():
376        macro = getMacroFile('chiral')
377        if not macro:
378            return
379        macStr = macro.readline()
380        while macStr:
381            items = macStr.split()
382            print items
383            if 'F' in items[0]:
384                restrData['Chiral']['wtFactor'] = float(items[1])
385            elif 'S' in items[0]:
386                List = []
387                res = items[1]
388                dist = items[2]
389                esd = items[3]
390                oAtm = items[4]
391                tAtm = items[5]
392                for name,Type,coords,id in zip(Names,Types,Coords,Ids):
393                    if res == '*' or res in name:
394                        if oAtm in name:
395                            oCoord = coords
396                            oId = id
397                            oName = name
398                        elif tAtm in name:
399                            tCoord = coords
400                            tId = id
401                            tName = name
402               
403            macStr = macro.readline()
404        macro.close()
405       
406    def AddTorsionRestraint():
407        print 'Torsion restraint'
408       
409    def AddAATorsionRestraint():
410        print 'Add AA Torsion'
411       
412    def AddRamaRestraint():
413        print 'Ramachandran restraint'
414               
415    def AddAARamaRestraint():
416        print 'Add AA Ramachandran'
417       
418    def WtBox(wind,restData):
419       
420        def OnWtFactor(event):
421            try:
422                value = float(wtfactor.GetValue())
423            except ValueError:
424                value = 1.0
425            restData['wtFactor'] = value
426            wtfactor.SetValue('%.2f'%(value))
427           
428        def OnUseData(event):
429            restData['Use'] = Obj.GetValue()
430
431        wtBox = wx.BoxSizer(wx.HORIZONTAL)
432        wtBox.Add(wx.StaticText(wind,-1,'Restraint weight factor:'),0,wx.ALIGN_CENTER_VERTICAL)
433        wtfactor = wx.TextCtrl(wind,-1,value='%.2f'%(restData['wtFactor']),style=wx.TE_PROCESS_ENTER)
434        wtfactor.Bind(wx.EVT_TEXT_ENTER,OnWtFactor)
435        wtfactor.Bind(wx.EVT_KILL_FOCUS,OnWtFactor)
436        wtBox.Add(wtfactor,0,wx.ALIGN_CENTER_VERTICAL)
437        useData = wx.CheckBox(wind,-1,label=' Use?')
438        useData.Bind(wx.EVT_CHECKBOX, OnUseData)
439        useData.SetValue(restData['Use'])       
440        wtBox.Add(useData,0,wx.ALIGN_CENTER_VERTICAL)
441        return wtBox
442       
443    def UpdateBondRestr(bondRestData):
444       
445        def OnColSort(event):
446            r,c = event.GetRow(),event.GetCol()
447            if r < 0 and c == 0:
448                names = G2mth.sortArray(table,0)
449                bonds = []
450                for name in names:
451                    idx = table.index(name)
452                    bonds.append(bondList[idx])
453                bondRestData['Bonds'] = bonds
454                UpdateBondRestr(bondRestData)               
455       
456        def OnChangeValue(event):
457            rows = Bonds.GetSelectedRows()
458            if not rows:
459                return
460            Bonds.ClearSelection()
461            val = bondList[rows[0]][3]
462            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new value for bond',val,[0.,5.],'%.4f')
463            if dlg.ShowModal() == wx.ID_OK:
464                parm = dlg.GetValue()
465                for r in rows:
466                    bondList[r][3] = parm
467            dlg.Destroy()
468            UpdateBondRestr(bondRestData)               
469
470        def OnChangeEsd(event):
471            rows = Bonds.GetSelectedRows()
472            if not rows:
473                return
474            Bonds.ClearSelection()
475            val = bondList[rows[0]][4]
476            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new esd for bond',val,[0.,1.],'%.4f')
477            if dlg.ShowModal() == wx.ID_OK:
478                parm = dlg.GetValue()
479                for r in rows:
480                    bondList[r][4] = parm
481            dlg.Destroy()
482            UpdateBondRestr(bondRestData)               
483                               
484        def OnDeleteRestraint(event):
485            rows = Bonds.GetSelectedRows()
486            if not rows:
487                return
488            Bonds.ClearSelection()
489            rows.sort()
490            rows.reverse()
491            for row in rows:
492                bondList.remove(bondList[row])
493            UpdateBondRestr(bondRestData)               
494           
495        BondRestr.DestroyChildren()
496        dataDisplay = wx.Panel(BondRestr)
497        mainSizer = wx.BoxSizer(wx.VERTICAL)
498        mainSizer.Add((5,5),0)
499        mainSizer.Add(WtBox(BondRestr,bondRestData),0,wx.ALIGN_CENTER_VERTICAL)
500
501        bondList = bondRestData['Bonds']
502        if len(bondList) and len(bondList[0]) == 6:   #patch
503            bondList = bondRestData['Bonds'] = []
504        if len(bondList):
505            table = []
506            rowLabels = []
507            Types = [wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,3',]
508            if 'macro' in General['Type']:
509                colLabels = ['(res) A - (res) B','calc','obs','esd']
510                for i,[indx,ops,dcalc,dobs,esd] in enumerate(bondList):
511                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4)
512                    name = ''
513                    for atom in atoms:
514                        name += '('+atom[1]+atom[0].strip()+atom[2]+') '+atom[3]+' - '
515                    table.append([name[:-3],dcalc,dobs,esd])
516                    rowLabels.append(str(i))               
517            else:
518                colLabels = ['A+SymOp - B+SymOp','calc','obs','esd']
519                for i,[indx,ops,dcalc,dobs,esd] in enumerate(bondList):
520                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,ct-1)
521                    table.append([atoms[0]+'+('+ops[0]+') - '+atoms[1]+'+('+ops[1]+')',dcalc,dobs,esd])
522                    rowLabels.append(str(i))
523            bondTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
524            Bonds = G2gd.GSGrid(BondRestr)
525            Bonds.SetTable(bondTable, True)
526            Bonds.AutoSizeColumns(False)
527            for r in range(len(bondList)):
528                for c in range(2):
529                    Bonds.SetReadOnly(r,c,True)
530                    Bonds.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
531            Bonds.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK,OnColSort)
532            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2gd.wxID_RESTDELETE)
533            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeValue, id=G2gd.wxID_RESRCHANGEVAL)
534            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeEsd, id=G2gd.wxID_RESTCHANGEESD)
535            mainSizer.Add(Bonds,0,)
536        else:
537            mainSizer.Add(wx.StaticText(BondRestr,-1,'No bond distance restraints for this phase'),0,)
538
539        BondRestr.SetSizer(mainSizer)
540        Size = mainSizer.Fit(G2frame.dataFrame)
541        Size[0] += 5
542        Size[1] += 50       #make room for tab
543        BondRestr.SetSize(Size)
544        BondRestr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
545        G2frame.dataFrame.setSizePosLeft(Size)
546       
547    def UpdateAngleRestr(angleRestData):
548       
549        def OnColSort(event):
550            r,c = event.GetRow(),event.GetCol()
551            if r < 0 and c == 0:
552                names = G2mth.sortArray(table,0)
553                angles = []
554                for name in names:
555                    idx = table.index(name)
556                    angles.append(angleList[idx])
557                angleRestData['Angles'] = angles
558                UpdateAngleRestr(angleRestData)               
559       
560        def OnChangeValue(event):
561            rows = Angles.GetSelectedRows()
562            if not rows:
563                return
564            Angles.ClearSelection()
565            val = angleList[rows[0]][3]
566            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new value for angle',val,[0.,360.],'%.2f')
567            if dlg.ShowModal() == wx.ID_OK:
568                parm = dlg.GetValue()
569                for r in rows:
570                    angleList[r][3] = parm
571            dlg.Destroy()
572            UpdateAngleRestr(angleRestData)               
573
574        def OnChangeEsd(event):
575            rows = Angles.GetSelectedRows()
576            if not rows:
577                return
578            Angles.ClearSelection()
579            val = angleList[rows[0]][4]
580            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new esd for angle',val,[0.,5.],'%.2f')
581            if dlg.ShowModal() == wx.ID_OK:
582                parm = dlg.GetValue()
583                for r in rows:
584                    angleList[r][4] = parm
585            dlg.Destroy()
586            UpdateAngleRestr(angleRestData)               
587                                           
588        def OnDeleteRestraint(event):
589            rows = Angles.GetSelectedRows()
590            if not rows:
591                return
592            rows.sort()
593            rows.reverse()
594            for row in rows:
595                angleList.remove(angleList[row])
596            UpdateAngleRestr(angleRestData)               
597           
598        AngleRestr.DestroyChildren()
599        dataDisplay = wx.Panel(AngleRestr)
600        mainSizer = wx.BoxSizer(wx.VERTICAL)
601        mainSizer.Add((5,5),0)
602        mainSizer.Add(WtBox(AngleRestr,angleRestData),0,wx.ALIGN_CENTER_VERTICAL)
603
604        angleList = angleRestData['Angles']
605        if len(angleList):
606            table = []
607            rowLabels = []
608            Types = [wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,2',]
609            if 'macro' in General['Type']:
610                colLabels = ['(res) A - (res) B - (res) C','calc','obs','esd']
611                for i,[indx,ops,dcalc,dobs,esd] in enumerate(angleList):
612                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4)
613                    name = ''
614                    for atom in atoms:
615                        name += '('+atom[1]+atom[0].strip()+atom[2]+') '+atom[3]+' - '
616                    table.append([name[:-3],dcalc,dobs,esd])
617                    rowLabels.append(str(i))                               
618            else:
619                colLabels = ['A+SymOp - B+SymOp - C+SymOp','calc','obs','esd']
620                for i,[indx,ops,dcalc,dobs,esd] in enumerate(angleList):
621                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,ct-1)
622                    table.append([atoms[0]+'+('+ops[0]+') - '+atoms[1]+'+('+ops[1]+') - '+atoms[2]+ \
623                    '+('+ops[2]+')',dcalc,dobs,esd])
624                    rowLabels.append(str(i))
625            angleTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
626            Angles = G2gd.GSGrid(AngleRestr)
627            Angles.SetTable(angleTable, True)
628            Angles.AutoSizeColumns(False)
629            for r in range(len(angleList)):
630                for c in range(2):
631                    Angles.SetReadOnly(r,c,True)
632                    Angles.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
633            Angles.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK,OnColSort)
634            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2gd.wxID_RESTDELETE)
635            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeValue, id=G2gd.wxID_RESRCHANGEVAL)
636            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeEsd, id=G2gd.wxID_RESTCHANGEESD)
637            mainSizer.Add(Angles,0,)
638        else:
639            mainSizer.Add(wx.StaticText(AngleRestr,-1,'No bond angle restraints for this phase'),0,)
640
641        AngleRestr.SetSizer(mainSizer)
642        Size = mainSizer.Fit(G2frame.dataFrame)
643        Size[0] += 5
644        Size[1] += 50      #make room for tab
645        AngleRestr.SetSize(Size)
646        AngleRestr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
647        G2frame.dataFrame.setSizePosLeft(Size)
648   
649    def UpdatePlaneRestr(planeRestData):
650       
651        items = G2frame.dataFrame.RestraintEdit.GetMenuItems()
652        for item in items:
653            if item.GetLabel() in ['Change value']:
654                item.Enable(False)
655
656        def OnChangeEsd(event):
657            rows = Planes.GetSelectedRows()
658            if not rows:
659                return
660            Planes.ClearSelection()
661            val = planeList[rows[0]][4]
662            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new esd for plane',val,[0.,5.],'%.2f')
663            if dlg.ShowModal() == wx.ID_OK:
664                parm = dlg.GetValue()
665                for r in rows:
666                    planeList[r][4] = parm
667            dlg.Destroy()
668            UpdatePlaneRestr(planeRestData)               
669                                           
670        def OnDeleteRestraint(event):
671            rows = Planes.GetSelectedRows()
672            if not rows:
673                return
674            rows.sort()
675            rows.reverse()
676            for row in rows:
677                planeList.remove(planeList[row])
678            UpdatePlaneRestr(planeRestData)               
679           
680        PlaneRestr.DestroyChildren()
681        dataDisplay = wx.Panel(PlaneRestr)
682        mainSizer = wx.BoxSizer(wx.VERTICAL)
683        mainSizer.Add((5,5),0)
684        mainSizer.Add(WtBox(PlaneRestr,planeRestData),0,wx.ALIGN_CENTER_VERTICAL)
685
686        planeList = planeRestData['Planes']
687        if len(planeList):
688            table = []
689            rowLabels = []
690            Types = [wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,2',]
691            if 'macro' in General['Type']:
692                colLabels = ['(res) atom','calc','obs','esd']
693                for i,[indx,ops,dcalc,dobs,esd] in enumerate(planeList):
694                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4)
695                    name = ''
696                    for a,atom in enumerate(atoms):
697                        name += '('+atom[1]+atom[0].strip()+atom[2]+') '+atom[3]+' - '
698                        if (a+1)%3 == 0:
699                            name += '\n'
700                    table.append([name[:-3],dcalc,dobs,esd])
701                    rowLabels.append(str(i))
702            else:                               
703                colLabels = ['atom+SymOp','calc','obs','esd']
704                for i,[indx,ops,dcalc,dobs,esd] in enumerate(planeList):
705                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,ct-1)
706                    atString = ''
707                    for a,atom in enumerate(atoms):
708                        atString += atom+'+ ('+ops[a]+'),'
709                        if (a+1)%3 == 0:
710                            atString += '\n'
711                    table.append([atString[:-1],dcalc,dobs,esd])
712                    rowLabels.append(str(i))
713            planeTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
714            Planes = G2gd.GSGrid(PlaneRestr)
715            Planes.SetTable(planeTable, True)
716            Planes.AutoSizeColumns(False)
717            Planes.AutoSizeRows(False)
718            for r in range(len(planeList)):
719                for c in range(3):
720                    Planes.SetReadOnly(r,c,True)
721                    Planes.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
722            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2gd.wxID_RESTDELETE)
723            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeEsd, id=G2gd.wxID_RESTCHANGEESD)
724            mainSizer.Add(Planes,0,)
725        else:
726            mainSizer.Add(wx.StaticText(PlaneRestr,-1,'No plane restraints for this phase'),0,)
727
728        PlaneRestr.SetSizer(mainSizer)
729        Size = mainSizer.Fit(G2frame.dataFrame)
730        Size[0] += 5
731        Size[1] += 50       #make room for tab
732        PlaneRestr.SetSize(Size)
733        PlaneRestr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
734        G2frame.dataFrame.setSizePosLeft(Size)
735   
736    def UpdateChiralRestr(chiralRestData):
737
738        def OnDeleteRestraint(event):
739            rows = Volumes.GetSelectedRows()
740            if not rows:
741                return
742            rows.sort()
743            rows.reverse()
744            for row in rows:
745                volumeList.remove(volumeList[row])
746            UpdateChiralRestr(chiralRestData)               
747           
748        def OnChangeValue(event):
749            rows = Volumes.GetSelectedRows()
750            if not rows:
751                return
752            Volumes.ClearSelection()
753            val = volumeList[rows[0]][3]
754            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new value for chiral volume',val,[0.,360.],'%.2f')
755            if dlg.ShowModal() == wx.ID_OK:
756                parm = dlg.GetValue()
757                for r in rows:
758                    volumeList[r][3] = parm
759            dlg.Destroy()
760            UpdateChiralRestr(chiralRestData)               
761
762        def OnChangeEsd(event):
763            rows = Volumes.GetSelectedRows()
764            if not rows:
765                return
766            Volumes.ClearSelection()
767            val = volumeList[rows[0]][4]
768            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new esd for chiral volume',val,[0.,5.],'%.2f')
769            if dlg.ShowModal() == wx.ID_OK:
770                parm = dlg.GetValue()
771                for r in rows:
772                    volumeList[r][4] = parm
773            dlg.Destroy()
774            UpdateChiralRestr(chiralRestData)               
775                                           
776        ChiralRestr.DestroyChildren()
777        dataDisplay = wx.Panel(ChiralRestr)
778        mainSizer = wx.BoxSizer(wx.VERTICAL)
779        mainSizer.Add((5,5),0)
780        mainSizer.Add(WtBox(ChiralRestr,chiralRestData),0,wx.ALIGN_CENTER_VERTICAL)
781
782        volumeList = chiralRestData['Volumes']
783        if len(volumeList):
784            table = []
785            rowLabels = []
786            Types = [wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,2',]
787            if 'macro' in General['Type']:
788                colLabels = ['(res) O (res) A (res) B (res) C','calc','obs','esd']
789                for i,[indx,ops,dcalc,dobs,esd] in enumerate(volumeList):
790                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4)
791                    name = ''
792                    for atom in atoms:
793                        name += '('+atom[1]+atom[0].strip()+atom[2]+') '+atom[3]+' '
794                    table.append([name,dcalc,dobs,esd])
795                    rowLabels.append(str(i))
796            else:
797                colLabels = ['O+SymOp  A+SymOp  B+SymOp  C+SymOp)','calc','obs','esd']
798                for i,[indx,ops,dcalc,dobs,esd] in enumerate(volumeList):
799                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,ct-1)
800                    table.append([atoms[0]+'+('+ops[0]+') '+atoms[1]+'+('+ops[1]+') '+atoms[2]+ \
801                    '+('+ops[2]+') '+atoms[3]+'+('+ops[3]+')',dcalc,dobs,esd])
802                    rowLabels.append(str(i))
803            volumeTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
804            Volumes = G2gd.GSGrid(ChiralRestr)
805            Volumes.SetTable(volumeTable, True)
806            Volumes.AutoSizeColumns(False)
807            for r in range(len(volumeList)):
808                for c in range(2):
809                    Volumes.SetReadOnly(r,c,True)
810                    Volumes.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
811            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2gd.wxID_RESTDELETE)
812            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeValue, id=G2gd.wxID_RESRCHANGEVAL)
813            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeEsd, id=G2gd.wxID_RESTCHANGEESD)
814            mainSizer.Add(Volumes,0,)
815        else:
816            mainSizer.Add(wx.StaticText(ChiralRestr,-1,'No chiral volume restraints for this phase'),0,)
817
818        ChiralRestr.SetSizer(mainSizer)
819        Size = mainSizer.Fit(G2frame.dataFrame)
820        Size[0] += 5
821        Size[1] += 50       #make room for tab
822        ChiralRestr.SetSize(Size)
823        ChiralRestr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
824        G2frame.dataFrame.setSizePosLeft(Size)
825   
826    def UpdateTorsionRestr(torsionRestData):
827
828        def OnDeleteRestraint(event):
829            rows = Torsions.GetSelectedRows()
830            if not rows:
831                return
832            rows.sort()
833            rows.reverse()
834            for row in rows:
835                torsionList.remove(torsionList[row])
836            UpdateTorsionRestr(torsionRestData)               
837           
838        TorsionRestr.DestroyChildren()
839        dataDisplay = wx.Panel(TorsionRestr)
840        mainSizer = wx.BoxSizer(wx.VERTICAL)
841        mainSizer.Add((5,5),0)
842        mainSizer.Add(WtBox(TorsionRestr,torsionRestData),0,wx.ALIGN_CENTER_VERTICAL)
843
844        torsionList = torsionRestData['Torsions']
845        if len(torsionList):
846            table = []
847            rowLabels = []
848            Types = 2*[wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,2',]
849            if 'macro' in General['Type']:
850                colLabels = ['(res) A (res) B (res) C (res) D','coef name','calc','obs','esd']
851                for i,[indx,ops,cofName,dcalc,dobs,esd] in enumerate(torsionList):
852                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4)
853                    name = ''
854                    for atom in atoms:
855                        name += '('+atom[1]+atom[0].strip()+atom[2]+') '+atom[3]+' '
856                    table.append([name,cofName,dcalc,dobs,esd])
857                    rowLabels.append(str(i))
858            else:
859                colLabels = ['A+SymOp  B+SymOp  C+SymOp  D+SymOp)','coef name','calc','obs','esd']
860                for i,[indx,ops,cofName,dcalc,dobs,esd] in enumerate(torsionList):
861                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,ct-1)
862                    table.append([atoms[0]+'+('+ops[0]+') '+atoms[1]+'+('+ops[1]+') '+atoms[2]+ \
863                    '+('+ops[2]+') '+atoms[3]+'+('+ops[3]+')',cofName,dcalc,dobs,esd])
864                    rowLabels.append(str(i))
865            torsionTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
866            Torsions = G2gd.GSGrid(TorsionRestr)
867            Torsions.SetTable(torsionTable, True)
868            Torsions.AutoSizeColumns(False)
869            for r in range(len(torsionList)):
870                for c in range(2):
871                    Torsions.SetReadOnly(r,c,True)
872                    Torsions.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
873            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2gd.wxID_RESTDELETE)
874            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeEsd, id=G2gd.wxID_RESTCHANGEESD)
875            mainSizer.Add(Torsions,0,)
876        else:
877            mainSizer.Add(wx.StaticText(TorsionRestr,-1,'No torsion restraints for this phase'),0,)
878
879        TorsionRestr.SetSizer(mainSizer)
880        Size = mainSizer.Fit(G2frame.dataFrame)
881        Size[0] += 5
882        Size[1] += 50       #make room for tab
883        TorsionRestr.SetSize(Size)
884        TorsionRestr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
885        G2frame.dataFrame.setSizePosLeft(Size)
886
887    def UpdateRamaRestr(ramaRestData):
888
889        def OnDeleteRestraint(event):
890            rows = Volumes.GetSelectedRows()
891            if not rows:
892                return
893            rows.sort()
894            rows.reverse()
895            for row in rows:
896                ramaList.remove(ramaList[row])
897            UpdateRamaRestr(ramaRestData)               
898           
899        RamaRestr.DestroyChildren()
900        dataDisplay = wx.Panel(RamaRestr)
901        mainSizer = wx.BoxSizer(wx.VERTICAL)
902        mainSizer.Add((5,5),0)
903        mainSizer.Add(WtBox(RamaRestr,ramaRestData),0,wx.ALIGN_CENTER_VERTICAL)
904
905        ramaList = ramaRestData['Ramas']
906        if len(ramaList):
907            table = []
908            rowLabels = []
909            Types = 2*[wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,2',]
910            if 'macro' in General['Type']:
911                colLabels = ['(res) A (res) B (res) C (res) D (res) E','coef name','calc','obs','esd']
912                for i,[indx,ops,cofName,dcalc,dobs,esd] in enumerate(ramaList):
913                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4)
914                    name = ''
915                    for atom in atoms:
916                        name += '('+atom[1]+atom[0].strip()+atom[2]+') '+atom[3]+' '
917                    table.append([name,cofName,dcalc,dobs,esd])
918                    rowLabels.append(str(i))
919            else:
920                colLabels = ['A+SymOp  B+SymOp  C+SymOp  D+SymOp  E+SymOp)','coef name','calc','obs','esd']
921                for i,[indx,ops,cofName,dcalc,dobs,esd] in enumerate(ramaList):
922                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,ct-1)
923                    table.append([atoms[0]+'+('+ops[0]+') '+atoms[1]+'+('+ops[1]+') '+atoms[2]+ \
924                    '+('+ops[2]+') '+atoms[3]+'+('+ops[3]+')',cofName,dcalc,dobs,esd])
925                    rowLabels.append(str(i))
926            ramaTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
927            Ramas = G2gd.GSGrid(RamaRestr)
928            Ramas.SetTable(ramaTable, True)
929            Ramas.AutoSizeColumns(False)
930            for r in range(len(ramaList)):
931                for c in range(2):
932                    Ramas.SetReadOnly(r,c,True)
933                    Ramas.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
934            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2gd.wxID_RESTDELETE)
935            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeEsd, id=G2gd.wxID_RESTCHANGEESD)
936            mainSizer.Add(Ramas,0,)
937        else:
938            mainSizer.Add(wx.StaticText(RamaRestr,-1,'No Ramachandran restraints for this phase'),0,)
939
940        RamaRestr.SetSizer(mainSizer)
941        Size = mainSizer.Fit(G2frame.dataFrame)
942        Size[0] += 5
943        Size[1] += 50       #make room for tab
944        RamaRestr.SetSize(Size)
945        RamaRestr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
946        G2frame.dataFrame.setSizePosLeft(Size)
947
948    def OnPageChanged(event):
949        page = event.GetSelection()
950        text = G2frame.dataDisplay.GetPageText(page)
951        if text == 'Bond restraints':
952            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RestraintMenu)
953            bondRestData = restrData['Bond']
954            UpdateBondRestr(bondRestData)
955        elif text == 'Angle restraints':
956            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RestraintMenu)
957            angleRestData = restrData['Angle']
958            UpdateAngleRestr(angleRestData)
959        elif text == 'Plane restraints':
960            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RestraintMenu)
961            planeRestData = restrData['Plane']
962            UpdatePlaneRestr(planeRestData)
963        elif text == 'Chiral restraints':
964            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RestraintMenu)
965            chiralRestData = restrData['Chiral']
966            UpdateChiralRestr(chiralRestData)
967        elif text == 'Torsion restraints':
968            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RestraintMenu)
969            torsionRestData = restrData['Torsion']
970            UpdateTorsionRestr(torsionRestData)
971        elif text == 'Ramachandran restraints':
972            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RestraintMenu)
973            ramaRestData = restrData['Rama']
974            UpdateRamaRestr(ramaRestData)
975        event.Skip()
976
977    def SetStatusLine(text):
978        Status.SetStatusText(text)                                     
979       
980    if G2frame.dataDisplay:
981        G2frame.dataDisplay.Destroy()
982       
983    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RestraintMenu)
984    G2frame.dataFrame.SetLabel('restraints for '+phaseName)
985    if not G2frame.dataFrame.GetStatusBar():
986        Status = G2frame.dataFrame.CreateStatusBar()
987    SetStatusLine('')
988   
989    G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_RESTSELPHASE,False)
990    if len(Phases) > 1:
991        G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_RESTSELPHASE,True)
992        G2frame.dataFrame.Bind(wx.EVT_MENU, OnSelectPhase, id=G2gd.wxID_RESTSELPHASE)
993    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddRestraint, id=G2gd.wxID_RESTRAINTADD)
994    if 'macro' in phasedata['General']['Type']:
995        G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_AARESTRAINTADD,True)
996        G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddAARestraint, id=G2gd.wxID_AARESTRAINTADD)
997    G2frame.dataDisplay = G2gd.GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
998   
999    BondRestr = wx.ScrolledWindow(G2frame.dataDisplay)
1000    G2frame.dataDisplay.AddPage(BondRestr,'Bond restraints')
1001    AngleRestr = wx.ScrolledWindow(G2frame.dataDisplay)
1002    G2frame.dataDisplay.AddPage(AngleRestr,'Angle restraints')
1003    PlaneRestr = wx.ScrolledWindow(G2frame.dataDisplay)
1004    G2frame.dataDisplay.AddPage(PlaneRestr,'Plane restraints')
1005    ChiralRestr = wx.ScrolledWindow(G2frame.dataDisplay)
1006    G2frame.dataDisplay.AddPage(ChiralRestr,'Chiral restraints')
1007    TorsionRestr = wx.ScrolledWindow(G2frame.dataDisplay)
1008    G2frame.dataDisplay.AddPage(TorsionRestr,'Torsion restraints')
1009    RamaRestr = wx.ScrolledWindow(G2frame.dataDisplay)
1010    G2frame.dataDisplay.AddPage(RamaRestr,'Ramachandran restraints')
1011   
1012    UpdateBondRestr(restrData['Bond'])
1013
1014    G2frame.dataDisplay.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, OnPageChanged)
Note: See TracBrowser for help on using the repository browser.