source: trunk/GSASIIrestrGUI.py @ 819

Last change on this file since 819 was 819, checked in by vondreele, 10 years ago

restraint fixes

File size: 64.8 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
23import GSASIIplot as G2plt
24import GSASIIdata as G2data
25
26VERY_LIGHT_GREY = wx.Colour(235,235,235)
27
28################################################################################
29#####  Restraints
30################################################################################           
31       
32def UpdateRestraints(G2frame,data,Phases,phaseName):
33    if not len(Phases):
34        print 'There are no phases to form restraints'
35        return
36    phasedata = Phases[phaseName]
37    if phaseName not in data:
38        data[phaseName] = {}
39    restrData = data[phaseName]
40    if 'Bond' not in restrData:
41        restrData['Bond'] = {'wtFactor':1.0,'Range':1.1,'Bonds':[],'Use':True}
42    if 'Angle' not in restrData:
43        restrData['Angle'] = {'wtFactor':1.0,'Range':0.85,'Angles':[],'Use':True}
44    if 'Plane' not in restrData:
45        restrData['Plane'] = {'wtFactor':1.0,'Planes':[],'Use':True}
46    if 'Chiral' not in restrData:
47        restrData['Chiral'] = {'wtFactor':1.0,'Volumes':[],'Use':True}
48    if 'Torsion' not in restrData:
49        restrData['Torsion'] = {'wtFactor':1.0,'Coeff':{},'Torsions':[],'Use':True}
50    if 'Rama' not in restrData:
51        restrData['Rama'] = {'wtFactor':1.0,'Coeff':{},'Ramas':[],'Use':True}
52    General = phasedata['General']
53    Cell = General['Cell'][1:7]          #skip flag & volume   
54    Amat,Bmat = G2lat.cell2AB(Cell)
55    SGData = General['SGData']
56    cx,ct = General['AtomPtrs'][:2]
57    Atoms = phasedata['Atoms']
58    AtLookUp = G2mth.FillAtomLookUp(Atoms)
59    if 'macro' in General['Type']:
60        Names = [atom[0]+':'+atom[1]+atom[2]+' '+atom[3] for atom in Atoms]
61        Ids = []
62        Coords = []
63        Types = []
64    else:   
65        Names = ['all '+ name for name in General['AtomTypes']]
66        iBeg = len(Names)
67        Types = [name for name in General['AtomTypes']]
68        Coords = [ [] for type in Types]
69        Ids = [ 0 for type in Types]
70        Names += [atom[ct-1] for atom in Atoms]
71    Types += [atom[ct] for atom in Atoms]
72    Coords += [atom[cx:cx+3] for atom in Atoms]
73    Ids += [atom[-1] for atom in Atoms]
74    rama = G2data.ramachandranDist['All']
75    ramaName = 'All'
76   
77    def OnSelectPhase(event):
78        dlg = wx.SingleChoiceDialog(G2frame,'Select','Phase',Phases.keys())
79        try:
80            if dlg.ShowModal() == wx.ID_OK:
81                phaseName = Phases.keys()[dlg.GetSelection()]
82                UpdateRestraints(G2frame,data,Phases,phaseName)
83        finally:
84            dlg.Destroy()
85   
86    def getMacroFile(macName):
87        defDir = os.path.join(os.path.split(__file__)[0],'GSASIImacros')
88        dlg = wx.FileDialog(G2frame,message='Choose '+macName+' restraint macro file',
89            defaultDir=defDir,defaultFile="",wildcard="GSAS-II macro file (*.mac)|*.mac",
90            style=wx.OPEN | wx.CHANGE_DIR)
91        try:
92            if dlg.ShowModal() == wx.ID_OK:
93                macfile = dlg.GetPath()
94                macro = open(macfile,'Ur')
95                head = macro.readline()
96                if macName not in head:
97                    print head
98                    print '**** ERROR - wrong restraint macro file selected, try again ****'
99                    macro = []
100            else: # cancel was pressed
101                macxro = []
102        finally:
103            dlg.Destroy()
104        return macro        #advanced past 1st line
105       
106    def OnPlotAARestraint(event):
107        page = G2frame.dataDisplay.GetSelection()
108        if 'Torsion' in G2frame.dataDisplay.GetPageText(page):
109            torNames = []
110            torNames += restrData['Torsion']['Coeff'].keys()
111            dlg = wx.SingleChoiceDialog(G2frame,'Select','Torsion data',torNames)
112            try:
113                if dlg.ShowModal() == wx.ID_OK:
114                    torName = torNames[dlg.GetSelection()]
115                    torsion = G2data.torsionDist[torName]
116                    torCoeff = restrData['Torsion']['Coeff'][torName]
117                    torList = restrData['Torsion']['Torsions']
118                    Names = []
119                    Angles = []
120                    for i,[indx,ops,cofName,esd] in enumerate(torList):
121                        if cofName == torName:
122                            atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4)
123                            name = '('+atoms[2][1]+atoms[2][0].strip()+atoms[2][2]+')'
124                            for atom in atoms:
125                                name += '  '+atom[3]
126                            XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3))
127                            angle = G2mth.getRestTorsion(XYZ,Amat)
128                            Angles.append(angle)
129                            Names.append(name) 
130                    G2plt.PlotTorsion(G2frame,phaseName,torsion,torName,Names,np.array(Angles),torCoeff)
131            finally:
132                dlg.Destroy()
133           
134        elif 'Rama' in G2frame.dataDisplay.GetPageText(page):
135            ramaNames = ['All',]
136            ramaNames += restrData['Rama']['Coeff'].keys()
137            dlg = wx.SingleChoiceDialog(G2frame,'Select','Ramachandran data',ramaNames)
138            try:
139                if dlg.ShowModal() == wx.ID_OK:
140                    ramaName = ramaNames[dlg.GetSelection()]
141                    rama = G2data.ramachandranDist[ramaName]
142                    ramaCoeff = []
143                    if ramaName != 'All':
144                        ramaCoeff = restrData['Rama']['Coeff'][ramaName]
145                    ramaList = restrData['Rama']['Ramas']
146                    Names = []
147                    PhiPsi = []
148                    for i,[indx,ops,cofName,esd] in enumerate(ramaList):
149                        if cofName == ramaName or (ramaName == 'All' and '-1' in cofName):
150                            atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4)
151                            name = '('+atoms[3][1]+atoms[3][0].strip()+atoms[3][2]+')'
152                            for atom in atoms:
153                                name += '  '+atom[3]
154                            XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3))
155                            phi,psi = G2mth.getRestRama(XYZ,Amat)
156                            PhiPsi.append([phi,psi])
157                            Names.append(name) 
158                    G2plt.PlotRama(G2frame,phaseName,rama,ramaName,Names,np.array(PhiPsi),ramaCoeff)
159            finally:
160                dlg.Destroy()
161           
162    def OnAddRestraint(event):
163        page = G2frame.dataDisplay.GetSelection()
164        if 'Bond' in G2frame.dataDisplay.GetPageText(page):
165            AddBondRestraint(restrData['Bond'])
166        elif 'Angle' in G2frame.dataDisplay.GetPageText(page):
167            AddAngleRestraint(restrData['Angle'])
168        elif 'Plane' in G2frame.dataDisplay.GetPageText(page):
169            AddPlaneRestraint(restrData['Plane'])
170           
171    def OnAddAARestraint(event):
172        page = G2frame.dataDisplay.GetSelection()
173        if 'Bond' in G2frame.dataDisplay.GetPageText(page):
174            AddAABondRestraint(restrData['Bond'])
175        elif 'Angle' in G2frame.dataDisplay.GetPageText(page):
176            AddAAAngleRestraint(restrData['Angle'])
177        elif 'Plane' in G2frame.dataDisplay.GetPageText(page):
178            AddAAPlaneRestraint(restrData['Plane'])
179        elif 'Chiral' in G2frame.dataDisplay.GetPageText(page):
180            AddAAChiralRestraint(restrData['Chiral'])
181        elif 'Torsion' in G2frame.dataDisplay.GetPageText(page):
182            AddAATorsionRestraint(restrData['Torsion'])
183        elif 'Rama' in G2frame.dataDisplay.GetPageText(page):
184            AddAARamaRestraint(restrData['Rama'])
185           
186    def AddBondRestraint(bondRestData):
187        Lists = {'origin':[],'target':[]}
188        for listName in ['origin','target']:
189            dlg = wx.MultiChoiceDialog(G2frame,'Bond restraint '+listName+' for '+General['Name'],
190                    'Select bond restraint '+listName+' atoms',Names)
191            if dlg.ShowModal() == wx.ID_OK:
192                sel = dlg.GetSelections()
193                for x in sel:
194                    if 'all' in Names[x]:
195                        allType = Types[x]
196                        for name,Type,coords,id in zip(Names,Types,Coords,Ids):
197                            if Type == allType and 'all' not in name:
198                                Lists[listName].append([id,Type,coords])
199                    else:
200                        Lists[listName].append([Ids[x],Types[x],Coords[x],])
201        bond = 1.54
202        dlg = G2phG.SingleFloatDialog(G2frame,'Distance','Enter restraint distance for bond',bond,[1.,4.],'%.4f')
203        if dlg.ShowModal() == wx.ID_OK:
204            bond = dlg.GetValue()
205        dlg.Destroy()
206        Factor = bondRestData['Range']
207        indices = (-1,0,1)
208        Units = np.array([[h,k,l] for h in indices for k in indices for l in indices])
209        origAtoms = Lists['origin']
210        targAtoms = Lists['target']
211        dlg = wx.ProgressDialog("Generating bond restraints","Processed origin atoms",len(origAtoms), 
212            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME)
213        try:
214            Norig = 0
215            for Oid,Otype,Ocoord in origAtoms:
216                Norig += 1
217                dlg.Update(Norig)
218                for Tid,Ttype,Tcoord in targAtoms:
219                    if 'macro' in General['Type']:
220                        result = [[Tcoord,1,[0,0,0]],]
221                    else:
222                        result = G2spc.GenAtom(Tcoord,SGData,False,Move=False)
223                    for Txyz,Top,Tunit in result:
224                        Dx = (Txyz-np.array(Ocoord))+Units
225                        dx = np.inner(Amat,Dx)
226                        dist = ma.masked_less(np.sqrt(np.sum(dx**2,axis=0)),bond/Factor)
227                        IndB = ma.nonzero(ma.masked_greater(dist,bond*Factor))
228                        if np.any(IndB):
229                            for indb in IndB:
230                                for i in range(len(indb)):
231                                    unit = Units[indb][i]+Tunit
232                                    if np.any(unit):
233                                        Topstr = '%d+%d,%d,%d'%(Top,unit[0],unit[1],unit[2])
234                                    else:
235                                        Topstr = str(Top)
236                                    newBond = [[Oid,Tid],['1',Topstr],bond,0.01]
237                                    if newBond not in bondRestData['Bonds']:
238                                        bondRestData['Bonds'].append(newBond)
239        finally:
240            dlg.Destroy()
241        UpdateBondRestr(bondRestData)               
242
243    def AddAABondRestraint(bondRestData):
244        Radii = dict(zip(General['AtomTypes'],General['BondRadii']))
245        macro = getMacroFile('bond')
246        if not macro:
247            return
248        macStr = macro.readline()
249        atoms = zip(Names,Coords,Ids)
250       
251        Factor = bondRestData['Range']
252        while macStr:
253            items = macStr.split()
254            if 'F' in items[0]:
255                restrData['Bond']['wtFactor'] = float(items[1])
256            elif 'S' in items[0]:
257                oIds = []
258                oCoords = []
259                tIds = []
260                tCoords = []
261                res = items[1]
262                dist = float(items[2])
263                esd = float(items[3])
264                oAtm,tAtm = items[4:6]
265                for Name,coords,Id in atoms:
266                    names = Name.split()
267                    if res == '*' or res in names[0]:
268                        if oAtm == names[2]:
269                            oIds.append(Id)
270                            oCoords.append(np.array(coords))
271                        if tAtm == names[2]:
272                            tIds.append(Id)
273                            tCoords.append(np.array(coords))
274                for i,[oId,oCoord] in enumerate(zip(oIds,oCoords)):
275                    for tId,tCoord in zip(tIds,tCoords)[i:]:
276                        obsd = np.sqrt(np.sum(np.inner(Amat,tCoord-oCoord)**2))
277                        if dist/Factor < obsd < dist*Factor:
278                            newBond = [[oId,tId],['1','1'],dist,esd]
279                            if newBond not in bondRestData['Bonds']:
280                                bondRestData['Bonds'].append(newBond)                         
281            macStr = macro.readline()
282        macro.close()
283        UpdateBondRestr(bondRestData)               
284           
285    def AddAngleRestraint(angleRestData):
286        Radii = dict(zip(General['AtomTypes'],zip(General['BondRadii'],General['AngleRadii'])))
287        origAtoms = []
288        dlg = wx.MultiChoiceDialog(G2frame,'Select atom B for angle A-B-C for '+General['Name'],
289                'Select angle restraint origin atoms',Names)
290        if dlg.ShowModal() == wx.ID_OK:
291            sel = dlg.GetSelections()
292            for x in sel:
293                if 'all' in Names[x]:
294                    allType = Types[x]
295                    for name,Type,coords,id in zip(Names,Types,Coords,Ids):
296                        if Type == allType and 'all' not in name:
297                            origAtoms.append([id,Type,coords])
298                else:
299                    origAtoms.append([Ids[x],Types[x],Coords[x]])
300        targAtoms = [[Ids[x+iBeg],Types[x+iBeg],Coords[x+iBeg]] for x in range(len(Names[iBeg:]))]
301        value = 109.54
302        dlg = G2phG.SingleFloatDialog(G2frame,'Angle','Enter restraint angle ',value,[30.,180.],'%.2f')
303        if dlg.ShowModal() == wx.ID_OK:
304            value = dlg.GetValue()
305        dlg.Destroy()
306
307        Factor = angleRestData['Range']
308        indices = (-1,0,1)
309        Units = np.array([[h,k,l] for h in indices for k in indices for l in indices])
310        VectA = []
311        for Oid,Otype,Ocoord in origAtoms:
312            IndBlist = []
313            VectB = []
314            for Tid,Ttype,Tcoord in targAtoms:
315                result = G2spc.GenAtom(Tcoord,SGData,False,Move=False)
316                BsumR = (Radii[Otype][0]+Radii[Ttype][0])*Factor
317                AsumR = (Radii[Otype][1]+Radii[Ttype][1])*Factor
318                for Txyz,Top,Tunit in result:
319                    Dx = (Txyz-Ocoord)+Units
320                    dx = np.inner(Amat,Dx)
321                    dist = ma.masked_less(np.sqrt(np.sum(dx**2,axis=0)),0.5)
322                    IndB = ma.nonzero(ma.masked_greater(dist-BsumR,0.))
323                    if np.any(IndB):
324                        for indb in IndB:
325                            for i in range(len(indb)):
326                                if str(dx.T[indb][i]) not in IndBlist:
327                                    IndBlist.append(str(dx.T[indb][i]))
328                                    unit = Units[indb][i]+Tunit
329                                if np.any(unit):
330                                    Topstr = '%d+%d,%d,%d'%(Top,unit[0],unit[1],unit[2])
331                                else:
332                                    Topstr = str(Top)
333                                    tunit = '[%2d%2d%2d]'%(unit[0]+Tunit[0],unit[1]+Tunit[1],unit[2]+Tunit[2])
334                                    Dist = ma.getdata(dist[indb])[i]
335                                    if (Dist-AsumR) <= 0.:
336                                        VectB.append([Oid,'1',Ocoord,Tid,Topstr,Tcoord,Dist])
337            VectA.append(VectB)
338            for Vects in VectA:
339                for i,vecta in enumerate(Vects):                   
340                    for vectb in Vects[:i]:
341                        ids = [vecta[3],vecta[0],vectb[3]]
342                        ops = [vecta[4],vecta[1],vectb[4]]
343                        XYZ = np.array([vecta[5],vecta[2],vectb[5]])
344                        angle = [ids,ops,value,1.0]
345                        if angle not in angleRestData['Angles']:
346                            angleRestData['Angles'].append(angle)
347        UpdateAngleRestr(angleRestData)               
348
349    def AddAAAngleRestraint(angleRestData):
350        macro = getMacroFile('angle')
351        if not macro:
352            return
353        atoms = zip(Names,Ids)
354        macStr = macro.readline()
355        while macStr:
356            items = macStr.split()
357            if 'F' in items[0]:
358                restrData['Angle']['wtFactor'] = float(items[1])
359            elif 'S' in items[0]:
360                res = items[1]
361                value = float(items[2])
362                esd = float(items[3])
363                Atms = items[4:7]
364                pAtms = ['','','']
365                for i,atm in enumerate(Atms):
366                    if '+' in atm:
367                        pAtms[i] = atm.strip('+')
368                ids = np.array([0,0,0])
369                rNum = -1
370                for name,id in atoms:
371                    names = name.split()
372                    tNum = int(names[0].split(':')[0])
373                    if res in names[0]:
374                        try:
375                            ipos = Atms.index(names[2])
376                            ids[ipos] = id
377                        except ValueError:
378                            continue
379                    elif res == '*':
380                        try:
381                            ipos = Atms.index(names[2])
382                            if not np.all(ids):
383                                rNum = int(names[0].split(':')[0])
384                            ids[ipos] = id
385                        except ValueError:
386                            try:
387                                if tNum == rNum+1:
388                                    ipos = pAtms.index(names[2])
389                                    ids[ipos] = id
390                            except ValueError:
391                                continue
392                    if np.all(ids):
393                        angle = [list(ids),['1','1','1'],value,esd]
394                        if angle not in angleRestData['Angles']:
395                            angleRestData['Angles'].append(angle)
396                        ids = np.array([0,0,0])
397            macStr = macro.readline()
398        macro.close()
399        UpdateAngleRestr(angleRestData)               
400       
401    def AddPlaneRestraint(restrData):
402        ids = []
403        dlg = wx.MultiChoiceDialog(G2frame,'Select 4 or more atoms for plane in '+General['Name'],
404                'Select 4+ atoms',Names[iBeg:])
405        if dlg.ShowModal() == wx.ID_OK:
406            sel = dlg.GetSelections()
407            if len(sel) > 3:
408                for x in sel:
409                    ids.append(Ids[x+iBeg])
410                ops = ['1' for i in range(len(sel))]
411                plane = [ids,ops,0.0,0.01]
412                if plane not in restrData['Planes']:
413                    restrData['Planes'].append(plane)
414            else:
415                print '**** ERROR - not enough atoms for a plane restraint - try again ****'
416        UpdatePlaneRestr(restrData)               
417
418    def AddAAPlaneRestraint(planeRestData):
419        macro = getMacroFile('plane')
420        if not macro:
421            return
422        atoms = zip(Names,Ids)
423        macStr = macro.readline()
424        while macStr:
425            items = macStr.split()
426            if 'F' in items[0]:
427                restrData['Plane']['wtFactor'] = float(items[1])
428            elif 'S' in items[0]:
429                res = items[1]
430                esd = float(items[2])
431                Atms = items[3:]
432                pAtms = ['' for i in Atms]
433                for i,atm in enumerate(Atms):
434                    if '+' in atm:
435                        pAtms[i] = atm.strip('+')
436                rNum = -1
437                ids = np.zeros(len(Atms))
438                ops = ['1' for i in range(len(Atms))]
439                for name,id in atoms:
440                    names = name.split()
441                    tNum = int(names[0].split(':')[0])
442                    if res in names[0]:
443                        try:
444                            ipos = Atms.index(names[2])
445                            ids[ipos] = id
446                        except ValueError:
447                            continue
448                    elif res == '*':
449                        try:
450                            ipos = Atms.index(names[2])
451                            if not np.all(ids):
452                                rNum = int(names[0].split(':')[0])
453                            ids[ipos] = id
454                        except ValueError:
455                            try:
456                                if tNum == rNum+1:
457                                    ipos = pAtms.index(names[2])
458                                    ids[ipos] = id
459                            except ValueError:
460                                continue
461                    if np.all(ids):
462                        plane = [list(ids),ops,0.0,esd]
463                        if plane not in planeRestData['Planes']:
464                            planeRestData['Planes'].append(plane)
465                        ids = np.zeros(len(Atms))
466            macStr = macro.readline()
467        macro.close()
468        UpdatePlaneRestr(planeRestData)               
469
470    def AddAAChiralRestraint(chiralRestData):
471        macro = getMacroFile('chiral')
472        if not macro:
473            return
474        atoms = zip(Names,Ids)
475        macStr = macro.readline()
476        while macStr:
477            items = macStr.split()
478            if 'F' in items[0]:
479                restrData['Chiral']['wtFactor'] = float(items[1])
480            elif 'S' in items[0]:
481                res = items[1]
482                value = float(items[2])
483                esd = float(items[3])
484                Atms = items[4:8]
485                ids = np.array([0,0,0,0])
486                for name,id in atoms:
487                    names = name.split()
488                    if res in names[0]:
489                        try:
490                            ipos = Atms.index(names[2])
491                            ids[ipos] = id
492                        except ValueError:
493                            pass
494                        if np.all(ids):
495                            chiral = [list(ids),['1','1','1','1'],value,esd]
496                            if chiral not in chiralRestData['Volumes']:
497                                chiralRestData['Volumes'].append(chiral)
498                            ids = np.array([0,0,0,0])
499            macStr = macro.readline()
500        macro.close()
501        UpdateChiralRestr(chiralRestData)               
502       
503    def makeChains(Names,Ids):
504        Chains = {}
505        chain = ''
506        atoms = zip(Names,Ids)
507        for name,id in atoms:
508            items = name.split()
509            rnum,res = items[0].split(':')
510            if items[1] not in Chains:
511                Residues = {}
512                Chains[items[1]] = Residues
513            if int(rnum) not in Residues:
514                Residues[int(rnum)] = []
515            Residues[int(rnum)].append([res,items[2],id])
516        return Chains
517       
518    def AddAATorsionRestraint(torsionRestData):
519        macro = getMacroFile('torsion')
520        if not macro:
521            return
522        Chains = makeChains(Names,Ids)           
523        macStr = macro.readline()[:-1]
524        while macStr:
525            items = macStr.split()
526            if 'F' in items[0]:
527                restrData['Torsion']['wtFactor'] = float(items[1])
528            elif 'A' in items[0]:
529                name = items[10]
530                coeff = np.zeros(9)
531                for i,item in enumerate(items[1:10]):
532                    coeff[i] = float(item)
533                torsionRestData['Coeff'][name] = coeff
534            elif 'S' in items[0]:
535                Name = items[1]
536                Res = items[2]
537                Esd = float(items[3])
538                Atms = items[4:8]
539                pAtms = ['','','','']
540                for i,atm in enumerate(Atms):
541                    if '+' in atm:
542                        pAtms[i] = atm.strip('+')
543                ids = np.array([0,0,0,0])
544                chains = Chains.keys()
545                chains.sort()
546                for chain in chains:
547                    residues = Chains[chain].keys()
548                    residues.sort()
549                    for residue in residues:
550                        if residue == residues[-1] and Res == '*':
551                            continue
552                        if Res != '*':
553                            for res,name,id in Chains[chain][residue]:
554                                if Res == res:
555                                    try:
556                                        ipos = Atms.index(name)
557                                        ids[ipos] = id
558                                    except ValueError:
559                                        continue
560                        else:
561                            for res,name,id in Chains[chain][residue]:
562                                try:
563                                    ipos = Atms.index(name)
564                                    ids[ipos] = id
565                                except ValueError:
566                                    continue
567                            for res,name,id in Chains[chain][residue+1]:
568                                try:
569                                    ipos = pAtms.index(name)
570                                    ids[ipos] = id
571                                except ValueError:
572                                    continue
573                        if np.all(ids):
574                            torsion = [list(ids),['1','1','1','1'],Name,Esd]
575                            if torsion not in torsionRestData['Torsions']:
576                                torsionRestData['Torsions'].append(torsion)
577                            ids = np.array([0,0,0,0])                           
578            macStr = macro.readline()
579        macro.close()
580        UpdateTorsionRestr(torsionRestData)                       
581       
582    def AddAARamaRestraint(ramaRestData):
583        macro = getMacroFile('Ramachandran')
584        if not macro:
585            return
586        Chains = makeChains(Names,Ids)           
587        macStr = macro.readline()
588        while macStr:
589            items = macStr.split()
590            if 'F' in items[0]:
591                restrData['Rama']['wtFactor'] = float(items[1])
592            elif 'A' in items[0]:
593                nTerms = int(items[1])
594                name = items[2]
595                coeff = np.zeros((nTerms,6))
596                for i in range(nTerms):
597                    macStr = macro.readline()
598                    items = macStr.split()
599                    for j,val in enumerate(items):
600                        coeff[i][j] = float(val)
601                ramaRestData['Coeff'][name] = coeff
602            elif 'S' in items[0]:
603                Name = items[1]
604                Res = items[2]
605                Esd = float(items[3])
606                Atms = items[4:9]
607                mAtms = ['','','','','']
608                pAtms = ['','','','','']
609                for i,atm in enumerate(Atms):
610                    if '+' in atm:
611                        pAtms[i] = atm.strip('+')
612                    elif '-' in atm:
613                        mAtms[i] = atm.strip('-')
614                ids = np.array([0,0,0,0,0])
615                chains = Chains.keys()
616                chains.sort()
617                for chain in chains:
618                    residues = Chains[chain].keys()
619                    residues.sort()
620                    if not (any(mAtms) or any(pAtms)):
621                        for residue in residues:
622                            for res,name,id in Chains[chain][residue]:
623                                if Res == res:
624                                    try:
625                                        ipos = Atms.index(name)
626                                        ids[ipos] = id
627                                    except ValueError:
628                                        continue
629                            if np.all(ids):
630                                rama = [list(ids),['1','1','1','1','1'],Name,Esd]
631                                if rama not in ramaRestData['Ramas']:
632                                    ramaRestData['Ramas'].append(rama)
633                                ids = np.array([0,0,0,0,0])
634                    else:
635                        for residue in residues[1:-1]:
636                            for res,name,id in Chains[chain][residue-1]:
637                                try:
638                                    ipos = mAtms.index(name)
639                                    ids[ipos] = id
640                                except ValueError:
641                                    continue
642                            for res,name,id in Chains[chain][residue+1]:
643                                try:
644                                    ipos = pAtms.index(name)
645                                    ids[ipos] = id
646                                except ValueError:
647                                    continue
648                            for res,name,id in Chains[chain][residue]:
649                                if Res == res:
650                                    try:
651                                        ipos = Atms.index(name)
652                                        ids[ipos] = id
653                                    except ValueError:
654                                        continue
655                            if np.all(ids):
656                                rama = [list(ids),['1','1','1','1','1'],Name,Esd]
657                                if rama not in ramaRestData['Ramas']:
658                                    ramaRestData['Ramas'].append(rama)
659                                ids = np.array([0,0,0,0,0])
660            macStr = macro.readline()
661        macro.close()
662        UpdateRamaRestr(ramaRestData)               
663               
664    def WtBox(wind,restData):
665        if 'Range' not in restData: restData['Range'] = 1.1     #patch
666       
667        def OnWtFactor(event):
668            try:
669                value = float(wtfactor.GetValue())
670            except ValueError:
671                value = 1.0
672            restData['wtFactor'] = value
673            wtfactor.SetValue('%.2f'%(value))
674           
675        def OnRange(event):
676            try:
677                value = float(sRange.GetValue())
678            except ValueError:
679                value = 1.0
680            restData['Range'] = value
681            sRange.SetValue('%.2f'%(value))
682           
683        def OnUseData(event):
684            restData['Use'] = Obj.GetValue()
685
686        wtBox = wx.BoxSizer(wx.HORIZONTAL)
687        wtBox.Add(wx.StaticText(wind,-1,'Restraint weight factor:'),0,wx.ALIGN_CENTER_VERTICAL)
688        wtfactor = wx.TextCtrl(wind,-1,value='%.2f'%(restData['wtFactor']),style=wx.TE_PROCESS_ENTER)
689        wtfactor.Bind(wx.EVT_TEXT_ENTER,OnWtFactor)
690        wtfactor.Bind(wx.EVT_KILL_FOCUS,OnWtFactor)
691        wtBox.Add(wtfactor,0,wx.ALIGN_CENTER_VERTICAL)
692        useData = wx.CheckBox(wind,-1,label=' Use?')
693        useData.Bind(wx.EVT_CHECKBOX, OnUseData)
694        useData.SetValue(restData['Use'])       
695        wtBox.Add(useData,0,wx.ALIGN_CENTER_VERTICAL)
696        if 'Bonds' in restData or 'Angles' in restData:
697            wtBox.Add(wx.StaticText(wind,-1,'Search range:'),0,wx.ALIGN_CENTER_VERTICAL)
698            sRange = wx.TextCtrl(wind,-1,value='%.2f'%(restData['Range']),style=wx.TE_PROCESS_ENTER)
699            sRange.Bind(wx.EVT_TEXT_ENTER,OnRange)
700            sRange.Bind(wx.EVT_KILL_FOCUS,OnRange)
701            wtBox.Add(sRange,0,wx.ALIGN_CENTER_VERTICAL)
702        return wtBox
703       
704    def OnRowSelect(event):
705        r,c =  event.GetRow(),event.GetCol()
706        Obj = event.GetEventObject()
707        if r < 0 and c < 0:
708            if Obj.IsSelection():
709                Obj.ClearSelection()
710            else:
711                for row in range(Obj.GetNumberRows()):
712                    Obj.SelectRow(row,True)
713        elif c < 0:                   #only row clicks
714            if event.ControlDown():                   
715                if r in Obj.GetSelectedRows():
716                    Obj.DeselectRow(r)
717                else:
718                    Obj.SelectRow(r,True)
719            elif event.ShiftDown():
720                indxs = Obj.GetSelectedRows()
721                Obj.ClearSelection()
722                ibeg = 0
723                if indxs:
724                    ibeg = indxs[-1]
725                for row in range(ibeg,r+1):
726                    Obj.SelectRow(row,True)
727            else:
728                Obj.ClearSelection()
729                Obj.SelectRow(r,True)
730                   
731    def UpdateBondRestr(bondRestData):
732       
733        def OnChangeValue(event):
734            rows = Bonds.GetSelectedRows()
735            if not rows:
736                return
737            Bonds.ClearSelection()
738            val = bondList[rows[0]][2]
739            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new value for bond',val,[0.,5.],'%.4f')
740            if dlg.ShowModal() == wx.ID_OK:
741                parm = dlg.GetValue()
742                for r in rows:
743                    bondRestData['Bonds'][r][2] = parm
744            dlg.Destroy()
745            UpdateBondRestr(bondRestData)               
746
747        def OnChangeEsd(event):
748            rows = Bonds.GetSelectedRows()
749            if not rows:
750                return
751            Bonds.ClearSelection()
752            val = bondList[rows[0]][3]
753            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new esd for bond',val,[0.,1.],'%.4f')
754            if dlg.ShowModal() == wx.ID_OK:
755                parm = dlg.GetValue()
756                for r in rows:
757                    bondRestData['Bonds'][r][3] = parm
758            dlg.Destroy()
759            UpdateBondRestr(bondRestData)               
760                               
761        def OnDeleteRestraint(event):
762            rows = Bonds.GetSelectedRows()
763            if not rows:
764                return
765            Bonds.ClearSelection()
766            rows.sort()
767            rows.reverse()
768            for row in rows:
769                bondList.remove(bondList[row])
770            UpdateBondRestr(bondRestData)               
771           
772        BondRestr.DestroyChildren()
773        dataDisplay = wx.Panel(BondRestr)
774        mainSizer = wx.BoxSizer(wx.VERTICAL)
775        mainSizer.Add((5,5),0)
776        mainSizer.Add(WtBox(BondRestr,bondRestData),0,wx.ALIGN_CENTER_VERTICAL)
777
778        bondList = bondRestData['Bonds']
779        if len(bondList) and len(bondList[0]) == 6:   #patch
780            bondList = bondRestData['Bonds'] = []
781        if len(bondList):
782            table = []
783            rowLabels = []
784            Types = [wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,3',]
785            if 'macro' in General['Type']:
786                colLabels = ['(res) A - (res) B','calc','obs','esd']
787                for i,[indx,ops,obs,esd] in enumerate(bondList):
788                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4)
789                    name = ''
790                    for atom in atoms:
791                        name += '('+atom[1]+atom[0].strip()+atom[2]+') '+atom[3]+' - '
792                    XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3))
793                    calc = G2mth.getRestDist(XYZ,Amat)
794                    table.append([name[:-3],calc,obs,esd])
795                    rowLabels.append(str(i))               
796            else:
797                colLabels = ['A+SymOp - B+SymOp','calc','obs','esd']
798                try:
799                    for i,[indx,ops,obs,esd] in enumerate(bondList):
800                        names = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,ct-1)
801                        XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3))
802                        XYZ = G2mth.getSyXYZ(XYZ,ops,SGData)
803                        calc = G2mth.getRestDist(XYZ,Amat)
804                        table.append([names[0]+'+('+ops[0]+') - '+names[1]+'+('+ops[1]+')',calc,obs,esd])
805                        rowLabels.append(str(i))
806                except ValueError:              #patch - old restraints!
807                    bondList = []
808            bondTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
809            Bonds = G2gd.GSGrid(BondRestr)
810            Bonds.SetTable(bondTable, True)
811            Bonds.AutoSizeColumns(False)
812            for r in range(len(bondList)):
813                for c in range(2):
814                    Bonds.SetReadOnly(r,c,True)
815                    Bonds.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
816            Bonds.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK,OnRowSelect)
817            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2gd.wxID_RESTDELETE)
818            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeValue, id=G2gd.wxID_RESRCHANGEVAL)
819            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeEsd, id=G2gd.wxID_RESTCHANGEESD)
820            mainSizer.Add(Bonds,0,)
821        else:
822            mainSizer.Add(wx.StaticText(BondRestr,-1,'No bond distance restraints for this phase'),0,)
823
824        BondRestr.SetSizer(mainSizer)
825        Size = mainSizer.Fit(G2frame.dataFrame)
826        Size[0] = 600
827        Size[1] += 50       #make room for tab
828        BondRestr.SetSize(Size)
829        BondRestr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
830        G2frame.dataFrame.SetSize(Size)
831       
832    def UpdateAngleRestr(angleRestData):
833       
834        def OnChangeValue(event):
835            rows = Angles.GetSelectedRows()
836            if not rows:
837                return
838            Angles.ClearSelection()
839            val = angleList[rows[0]][2]
840            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new value for angle',val,[0.,360.],'%.2f')
841            if dlg.ShowModal() == wx.ID_OK:
842                parm = dlg.GetValue()
843                for r in rows:
844                    angleRestData['Angles'][r][2] = parm
845            dlg.Destroy()
846            UpdateAngleRestr(angleRestData)               
847
848        def OnChangeEsd(event):
849            rows = Angles.GetSelectedRows()
850            if not rows:
851                return
852            Angles.ClearSelection()
853            val = angleList[rows[0]][3]
854            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new esd for angle',val,[0.,5.],'%.2f')
855            if dlg.ShowModal() == wx.ID_OK:
856                parm = dlg.GetValue()
857                for r in rows:
858                    angleRestData['Angles'][r][3] = parm
859            dlg.Destroy()
860            UpdateAngleRestr(angleRestData)               
861                                           
862        def OnDeleteRestraint(event):
863            rows = Angles.GetSelectedRows()
864            if not rows:
865                return
866            rows.sort()
867            rows.reverse()
868            for row in rows:
869                angleList.remove(angleList[row])
870            UpdateAngleRestr(angleRestData)               
871           
872        AngleRestr.DestroyChildren()
873        dataDisplay = wx.Panel(AngleRestr)
874        mainSizer = wx.BoxSizer(wx.VERTICAL)
875        mainSizer.Add((5,5),0)
876        mainSizer.Add(WtBox(AngleRestr,angleRestData),0,wx.ALIGN_CENTER_VERTICAL)
877
878        angleList = angleRestData['Angles']
879        if len(angleList):
880            table = []
881            rowLabels = []
882            Types = [wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,2',]
883            if 'macro' in General['Type']:
884                colLabels = ['(res) A - (res) B - (res) C','calc','obs','esd']
885                for i,[indx,ops,obs,esd] in enumerate(angleList):
886                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4)
887                    name = ''
888                    for atom in atoms:
889                        name += '('+atom[1]+atom[0].strip()+atom[2]+') '+atom[3]+' - '
890                    XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3))
891                    calc = G2mth.getRestAngle(XYZ,Amat)
892                    table.append([name[:-3],calc,obs,esd])
893                    rowLabels.append(str(i))                               
894            else:
895                colLabels = ['A+SymOp - B+SymOp - C+SymOp','calc','obs','esd']
896                for i,[indx,ops,obs,esd] in enumerate(angleList):
897                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,ct-1)
898                    name = atoms[0]+'+('+ops[0]+') - '+atoms[1]+'+('+ops[1]+') - '+atoms[2]+ \
899                    '+('+ops[2]+')'
900                    XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3))
901                    XYZ = G2mth.getSyXYZ(XYZ,ops,SGData)
902                    calc = G2mth.getRestAngle(XYZ,Amat)
903                    table.append([name,calc,obs,esd])
904                    rowLabels.append(str(i))
905            angleTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
906            Angles = G2gd.GSGrid(AngleRestr)
907            Angles.SetTable(angleTable, True)
908            Angles.AutoSizeColumns(False)
909            for r in range(len(angleList)):
910                for c in range(2):
911                    Angles.SetReadOnly(r,c,True)
912                    Angles.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
913            Angles.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK,OnRowSelect)
914            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2gd.wxID_RESTDELETE)
915            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeValue, id=G2gd.wxID_RESRCHANGEVAL)
916            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeEsd, id=G2gd.wxID_RESTCHANGEESD)
917            mainSizer.Add(Angles,0,)
918        else:
919            mainSizer.Add(wx.StaticText(AngleRestr,-1,'No bond angle restraints for this phase'),0,)
920
921        AngleRestr.SetSizer(mainSizer)
922        Size = mainSizer.Fit(G2frame.dataFrame)
923        Size[0] = 600
924        Size[1] += 50      #make room for tab
925        AngleRestr.SetSize(Size)
926        AngleRestr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
927        G2frame.dataFrame.SetSize(Size)
928   
929    def UpdatePlaneRestr(planeRestData):
930       
931        items = G2frame.dataFrame.RestraintEdit.GetMenuItems()
932        for item in items:
933            if item.GetLabel() in ['Change value']:
934                item.Enable(False)
935
936        def OnChangeEsd(event):
937            rows = Planes.GetSelectedRows()
938            if not rows:
939                return
940            Planes.ClearSelection()
941            val = planeList[rows[0]][3]
942            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new esd for plane',val,[0.,5.],'%.2f')
943            if dlg.ShowModal() == wx.ID_OK:
944                parm = dlg.GetValue()
945                for r in rows:
946                    planeRestData['Planes'][r][3] = parm
947            dlg.Destroy()
948            UpdatePlaneRestr(planeRestData)               
949                                           
950        def OnDeleteRestraint(event):
951            rows = Planes.GetSelectedRows()
952            if not rows:
953                return
954            rows.sort()
955            rows.reverse()
956            for row in rows:
957                planeList.remove(planeList[row])
958            UpdatePlaneRestr(planeRestData)               
959           
960        PlaneRestr.DestroyChildren()
961        dataDisplay = wx.Panel(PlaneRestr)
962        mainSizer = wx.BoxSizer(wx.VERTICAL)
963        mainSizer.Add((5,5),0)
964        mainSizer.Add(WtBox(PlaneRestr,planeRestData),0,wx.ALIGN_CENTER_VERTICAL)
965
966        planeList = planeRestData['Planes']
967        if len(planeList):
968            table = []
969            rowLabels = []
970            Types = [wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,2',]
971            if 'macro' in General['Type']:
972                colLabels = ['(res) atom','calc','obs','esd']
973                for i,[indx,ops,obs,esd] in enumerate(planeList):
974                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4)
975                    name = ''
976                    for a,atom in enumerate(atoms):
977                        name += '('+atom[1]+atom[0].strip()+atom[2]+') '+atom[3]+' - '
978                        if (a+1)%3 == 0:
979                            name += '\n'
980                    XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3))
981                    calc = G2mth.getRestPlane(XYZ,Amat)
982                    table.append([name[:-3],calc,obs,esd])
983                    rowLabels.append(str(i))
984            else:                               
985                colLabels = ['atom+SymOp','calc','obs','esd']
986                for i,[indx,ops,obs,esd] in enumerate(planeList):
987                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,ct-1)
988                    XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3))
989                    XYZ = G2mth.getSyXYZ(XYZ,ops,SGData)
990                    calc = G2mth.getRestPlane(XYZ,Amat)
991                    name = ''
992                    for a,atom in enumerate(atoms):
993                        name += atom+'+ ('+ops[a]+'),'
994                        if (a+1)%3 == 0:
995                            name += '\n'
996                    table.append([name[:-1],calc,obs,esd])
997                    rowLabels.append(str(i))
998            planeTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
999            Planes = G2gd.GSGrid(PlaneRestr)
1000            Planes.SetTable(planeTable, True)
1001            Planes.AutoSizeColumns(False)
1002            Planes.AutoSizeRows(False)
1003            for r in range(len(planeList)):
1004                for c in range(3):
1005                    Planes.SetReadOnly(r,c,True)
1006                    Planes.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
1007            Planes.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK,OnRowSelect)
1008            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2gd.wxID_RESTDELETE)
1009            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeEsd, id=G2gd.wxID_RESTCHANGEESD)
1010            mainSizer.Add(Planes,0,)
1011        else:
1012            mainSizer.Add(wx.StaticText(PlaneRestr,-1,'No plane restraints for this phase'),0,)
1013
1014        PlaneRestr.SetSizer(mainSizer)
1015        Size = mainSizer.Fit(G2frame.dataFrame)
1016        Size[0] = 600
1017        Size[1] += 50       #make room for tab
1018        PlaneRestr.SetSize(Size)
1019        PlaneRestr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
1020        G2frame.dataFrame.SetSize(Size)
1021#        G2frame.dataFrame.setSizePosLeft(Size)
1022   
1023    def UpdateChiralRestr(chiralRestData):
1024
1025        def OnDeleteRestraint(event):
1026            rows = Volumes.GetSelectedRows()
1027            if not rows:
1028                return
1029            rows.sort()
1030            rows.reverse()
1031            for row in rows:
1032                volumeList.remove(volumeList[row])
1033            UpdateChiralRestr(chiralRestData)               
1034           
1035        def OnChangeValue(event):
1036            rows = Volumes.GetSelectedRows()
1037            if not rows:
1038                return
1039            Volumes.ClearSelection()
1040            val = volumeList[rows[0]][2]
1041            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new value for chiral volume',val,[0.,360.],'%.2f')
1042            if dlg.ShowModal() == wx.ID_OK:
1043                parm = dlg.GetValue()
1044                for r in rows:
1045                    chiralRestData['Volumes'][r][2] = parm
1046            dlg.Destroy()
1047            UpdateChiralRestr(chiralRestData)               
1048
1049        def OnChangeEsd(event):
1050            rows = Volumes.GetSelectedRows()
1051            if not rows:
1052                return
1053            Volumes.ClearSelection()
1054            val = volumeList[rows[0]][3]
1055            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new esd for chiral volume',val,[0.,5.],'%.2f')
1056            if dlg.ShowModal() == wx.ID_OK:
1057                parm = dlg.GetValue()
1058                for r in rows:
1059                    chiralRestData['Volumes'][r][3] = parm
1060            dlg.Destroy()
1061            UpdateChiralRestr(chiralRestData)               
1062                                           
1063        ChiralRestr.DestroyChildren()
1064        dataDisplay = wx.Panel(ChiralRestr)
1065        mainSizer = wx.BoxSizer(wx.VERTICAL)
1066        mainSizer.Add((5,5),0)
1067        mainSizer.Add(WtBox(ChiralRestr,chiralRestData),0,wx.ALIGN_CENTER_VERTICAL)
1068
1069        volumeList = chiralRestData['Volumes']
1070        if len(volumeList):
1071            table = []
1072            rowLabels = []
1073            Types = [wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,2',]
1074            if 'macro' in General['Type']:
1075                colLabels = ['(res) O (res) A (res) B (res) C','calc','obs','esd']
1076                for i,[indx,ops,obs,esd] in enumerate(volumeList):
1077                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4)
1078                    name = ''
1079                    for atom in atoms:
1080                        name += '('+atom[1]+atom[0].strip()+atom[2]+') '+atom[3]+' '
1081                    XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3))
1082                    calc = G2mth.getRestChiral(XYZ,Amat)
1083                    table.append([name,calc,obs,esd])
1084                    rowLabels.append(str(i))
1085            else:
1086                colLabels = ['O+SymOp  A+SymOp  B+SymOp  C+SymOp)','calc','obs','esd']
1087                for i,[indx,ops,obs,esd] in enumerate(volumeList):
1088                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,ct-1)
1089                    name = atoms[0]+'+('+ops[0]+') '+atoms[1]+'+('+ops[1]+') '+atoms[2]+ \
1090                        '+('+ops[2]+') '+atoms[3]+'+('+ops[3]+')'
1091                    XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3))
1092                    XYZ = G2mth.getSyXYZ(XYZ,ops,SGData)
1093                    calc = G2mth.getRestChiral(XYZ,Amat)
1094                    table.append([name,calc,obs,esd])
1095                    rowLabels.append(str(i))
1096            volumeTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
1097            Volumes = G2gd.GSGrid(ChiralRestr)
1098            Volumes.SetTable(volumeTable, True)
1099            Volumes.AutoSizeColumns(False)
1100            for r in range(len(volumeList)):
1101                for c in range(2):
1102                    Volumes.SetReadOnly(r,c,True)
1103                    Volumes.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
1104            Volumes.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK,OnRowSelect)
1105            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2gd.wxID_RESTDELETE)
1106            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeValue, id=G2gd.wxID_RESRCHANGEVAL)
1107            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeEsd, id=G2gd.wxID_RESTCHANGEESD)
1108            mainSizer.Add(Volumes,0,)
1109        else:
1110            mainSizer.Add(wx.StaticText(ChiralRestr,-1,'No chiral volume restraints for this phase'),0,)
1111
1112        ChiralRestr.SetSizer(mainSizer)
1113        Size = mainSizer.Fit(G2frame.dataFrame)
1114        Size[0] = 600
1115        Size[1] += 50       #make room for tab
1116        ChiralRestr.SetSize(Size)
1117        ChiralRestr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
1118        G2frame.dataFrame.SetSize(Size)
1119   
1120    def UpdateTorsionRestr(torsionRestData):
1121
1122        def OnDeleteRestraint(event):
1123            rows = Torsions.GetSelectedRows()
1124            if not rows:
1125                return
1126            rows.sort()
1127            rows.reverse()
1128            for row in rows:
1129                torsionList.remove(torsionList[row])
1130            UpdateTorsionRestr(torsionRestData)               
1131           
1132        def OnChangeEsd(event):
1133            rows = Torsions.GetSelectedRows()
1134            if not rows:
1135                return
1136            Torsions.ClearSelection()
1137            val = torsionList[rows[0]][4]
1138            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new esd for torsion restraints',val,[0.,5.],'%.2f')
1139            if dlg.ShowModal() == wx.ID_OK:
1140                parm = dlg.GetValue()
1141                for r in rows:
1142                    torsionRestData['Torsions'][r][4] = parm
1143            dlg.Destroy()
1144            UpdateTorsionRestr(torsionRestData)               
1145                                           
1146        TorsionRestr.DestroyChildren()
1147        dataDisplay = wx.Panel(TorsionRestr)
1148        mainSizer = wx.BoxSizer(wx.VERTICAL)
1149        mainSizer.Add((5,5),0)
1150        mainSizer.Add(WtBox(TorsionRestr,torsionRestData),0,wx.ALIGN_CENTER_VERTICAL)
1151       
1152        coeffDict = torsionRestData['Coeff']
1153        torsionList = torsionRestData['Torsions']
1154        mainSizer.Add(wx.StaticText(TorsionRestr,-1,'Torsion restraints:'),0,wx.ALIGN_CENTER_VERTICAL)
1155        if len(torsionList):
1156            table = []
1157            rowLabels = []
1158            Types = 2*[wg.GRID_VALUE_STRING,]+4*[wg.GRID_VALUE_FLOAT+':10,2',]
1159            if 'macro' in General['Type']:
1160                colLabels = ['(res) A  B  C  D','coef name','torsion','obs E','restr','esd']
1161                for i,[indx,ops,cofName,esd] in enumerate(torsionList):
1162                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4)
1163                    name = '('+atoms[2][1]+atoms[2][0].strip()+atoms[2][2]+')'
1164                    for atom in atoms:
1165                        name += '  '+atom[3]
1166                    XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3))
1167                    tor = G2mth.getRestTorsion(XYZ,Amat)
1168                    restr,calc = G2mth.calcTorsionEnergy(tor,coeffDict[cofName])
1169                    table.append([name,cofName,tor,calc,restr,esd])
1170                    rowLabels.append(str(i))
1171            torsionTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
1172            Torsions = G2gd.GSGrid(TorsionRestr)
1173            Torsions.SetTable(torsionTable, True)
1174            Torsions.AutoSizeColumns(False)
1175            for r in range(len(torsionList)):
1176                for c in range(2):
1177                    Torsions.SetReadOnly(r,c,True)
1178                    Torsions.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
1179            Torsions.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK,OnRowSelect)
1180            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2gd.wxID_RESTDELETE)
1181            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeEsd, id=G2gd.wxID_RESTCHANGEESD)
1182            mainSizer.Add(Torsions,0,)
1183           
1184            mainSizer.Add((5,5))
1185            mainSizer.Add(wx.StaticText(TorsionRestr,-1,'Torsion function coefficients:'),0,wx.ALIGN_CENTER_VERTICAL)
1186            table = []
1187            rowLabels = []
1188            Types = 9*[wg.GRID_VALUE_FLOAT+':10,4',]
1189            colLabels = ['Mag A','Pos A','Width A','Mag B','Pos B','Width B','Mag C','Pos C','Width C']
1190            for item in coeffDict:
1191                rowLabels.append(item)
1192                table.append(coeffDict[item])
1193            coeffTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
1194            Coeff = G2gd.GSGrid(TorsionRestr)
1195            Coeff.SetTable(coeffTable, True)
1196            Coeff.AutoSizeColumns(False)
1197            for r in range(len(coeffDict)):
1198                for c in range(9):
1199                    Coeff.SetReadOnly(r,c,True)
1200                    Coeff.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
1201            mainSizer.Add(Coeff,0,)
1202        else:
1203            mainSizer.Add(wx.StaticText(TorsionRestr,-1,'No torsion restraints for this phase'),0,)
1204
1205        TorsionRestr.SetSizer(mainSizer)
1206        Size = mainSizer.Fit(G2frame.dataFrame)
1207        Size[0] = 600
1208        Size[1] += 50       #make room for tab
1209        TorsionRestr.SetSize(Size)
1210        TorsionRestr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
1211        G2frame.dataFrame.SetSize(Size)
1212
1213    def UpdateRamaRestr(ramaRestData):
1214
1215        def OnDeleteRestraint(event):
1216            rows = Ramas.GetSelectedRows()
1217            if not rows:
1218                return
1219            rows.sort()
1220            rows.reverse()
1221            for row in rows:
1222                ramaList.remove(ramaList[row])
1223            UpdateRamaRestr(ramaRestData)               
1224           
1225        def OnChangeEsd(event):
1226            rows = Ramas.GetSelectedRows()
1227            if not rows:
1228                return
1229            Ramas.ClearSelection()
1230            val = ramaList[rows[0]][4]
1231            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new esd for energy',val,[0.,5.],'%.2f')
1232            if dlg.ShowModal() == wx.ID_OK:
1233                parm = dlg.GetValue()
1234                for r in rows:
1235                    ramaRestData['Ramas'][r][4] = parm
1236            dlg.Destroy()
1237            UpdateRamaRestr(ramaRestData)               
1238                                           
1239        RamaRestr.DestroyChildren()
1240        dataDisplay = wx.Panel(RamaRestr)
1241        mainSizer = wx.BoxSizer(wx.VERTICAL)
1242        mainSizer.Add((5,5),0)
1243        mainSizer.Add(WtBox(RamaRestr,ramaRestData),0,wx.ALIGN_CENTER_VERTICAL)
1244
1245        ramaList = ramaRestData['Ramas']
1246        coeffDict = ramaRestData['Coeff']
1247        if len(ramaList):
1248            mainSizer.Add(wx.StaticText(RamaRestr,-1,'Ramachandran restraints:'),0,wx.ALIGN_CENTER_VERTICAL)
1249            table = []
1250            rowLabels = []
1251            Types = 2*[wg.GRID_VALUE_STRING,]+5*[wg.GRID_VALUE_FLOAT+':10,2',]
1252            if 'macro' in General['Type']:
1253                colLabels = ['(res) A  B  C  D  E','coef name','phi','psi','obs E','restr','esd']
1254                for i,[indx,ops,cofName,esd] in enumerate(ramaList):
1255                    atoms = G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,0,4)
1256                    name = '('+atoms[3][1]+atoms[3][0].strip()+atoms[3][2]+')'
1257                    for atom in atoms:
1258                        name += '  '+atom[3]
1259                    XYZ = np.array(G2mth.GetAtomItemsById(Atoms,AtLookUp,indx,cx,3))
1260                    phi,psi = G2mth.getRestRama(XYZ,Amat)
1261                    restr,calc = G2mth.calcRamaEnergy(phi,psi,coeffDict[cofName])
1262                    table.append([name,cofName,phi,psi,calc,restr,esd])
1263                    rowLabels.append(str(i))
1264            ramaTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
1265            Ramas = G2gd.GSGrid(RamaRestr)
1266            Ramas.SetTable(ramaTable, True)
1267            Ramas.AutoSizeColumns(False)
1268            for r in range(len(ramaList)):
1269                for c in range(2):
1270                    Ramas.SetReadOnly(r,c,True)
1271                    Ramas.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
1272            Ramas.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK,OnRowSelect)
1273            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=G2gd.wxID_RESTDELETE)
1274            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeEsd, id=G2gd.wxID_RESTCHANGEESD)
1275            mainSizer.Add(Ramas,0,)
1276        else:
1277            mainSizer.Add(wx.StaticText(RamaRestr,-1,'No Ramachandran restraints for this phase'),0,)
1278        mainSizer.Add((5,5))
1279        mainSizer.Add(wx.StaticText(RamaRestr,-1,'Ramachandran function coefficients:'),0,wx.ALIGN_CENTER_VERTICAL)
1280        if len(coeffDict):
1281            table = []
1282            rowLabels = []
1283            Types = 6*[wg.GRID_VALUE_FLOAT+':10,4',]
1284            colLabels = ['Mag','Pos phi','Pos psi','sig(phi)','sig(psi)','sig(cov)']
1285            for item in coeffDict:
1286                for i,term in enumerate(coeffDict[item]):
1287                    rowLabels.append(item+' term:'+str(i))
1288                    table.append(term)
1289            coeffTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
1290            Coeff = G2gd.GSGrid(RamaRestr)
1291            Coeff.SetTable(coeffTable, True)
1292            Coeff.AutoSizeColumns(False)
1293            for r in range(Coeff.GetNumberRows()):
1294                for c in range(6):
1295                    Coeff.SetReadOnly(r,c,True)
1296                    Coeff.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
1297            mainSizer.Add(Coeff,0,)
1298
1299        RamaRestr.SetSizer(mainSizer)
1300        Size = mainSizer.Fit(G2frame.dataFrame)
1301        Size[0] = 600
1302        Size[1] += 50       #make room for tab
1303        RamaRestr.SetSize(Size)
1304        RamaRestr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
1305        G2frame.dataFrame.SetSize(Size)
1306#        G2frame.dataFrame.setSizePosLeft(Size)
1307
1308    def OnPageChanged(event):
1309        page = event.GetSelection()
1310        text = G2frame.dataDisplay.GetPageText(page)
1311        if text == 'Bond restraints':
1312            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RestraintMenu)
1313            G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_RESTRAINTADD,True)
1314            G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_RESRCHANGEVAL,True)
1315            bondRestData = restrData['Bond']
1316            UpdateBondRestr(bondRestData)
1317        elif text == 'Angle restraints':
1318            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RestraintMenu)
1319            G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_RESTRAINTADD,True)
1320            G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_RESRCHANGEVAL,True)
1321            angleRestData = restrData['Angle']
1322            UpdateAngleRestr(angleRestData)
1323        elif text == 'Plane restraints':
1324            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RestraintMenu)
1325            G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_RESTRAINTADD,True)
1326            G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_RESRCHANGEVAL,False)
1327            planeRestData = restrData['Plane']
1328            UpdatePlaneRestr(planeRestData)
1329        elif text == 'Chiral restraints':
1330            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RestraintMenu)
1331            G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_RESTRAINTADD,False)
1332            G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_RESRCHANGEVAL,True)
1333            chiralRestData = restrData['Chiral']
1334            UpdateChiralRestr(chiralRestData)
1335        elif text == 'Torsion restraints':
1336            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RestraintMenu)
1337            G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_RESTRAINTADD,False)
1338            G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_RESRCHANGEVAL,False)
1339            G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_AARESTRAINTPLOT,True)
1340            torsionRestData = restrData['Torsion']
1341            UpdateTorsionRestr(torsionRestData)
1342        elif text == 'Ramachandran restraints':
1343            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RestraintMenu)
1344            G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_RESTRAINTADD,False)
1345            G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_RESRCHANGEVAL,False)
1346            G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_AARESTRAINTPLOT,True)
1347            ramaRestData = restrData['Rama']
1348            UpdateRamaRestr(ramaRestData)
1349            G2plt.PlotRama(G2frame,phaseName,rama,ramaName)
1350        event.Skip()
1351
1352    def SetStatusLine(text):
1353        Status.SetStatusText(text)                                     
1354       
1355    if G2frame.dataDisplay:
1356        G2frame.dataDisplay.Destroy()
1357       
1358    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RestraintMenu)
1359    G2frame.dataFrame.SetLabel('restraints for '+phaseName)
1360    if not G2frame.dataFrame.GetStatusBar():
1361        Status = G2frame.dataFrame.CreateStatusBar()
1362    SetStatusLine('')
1363   
1364    G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_RESTSELPHASE,False)
1365    if len(Phases) > 1:
1366        G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_RESTSELPHASE,True)
1367        G2frame.dataFrame.Bind(wx.EVT_MENU, OnSelectPhase, id=G2gd.wxID_RESTSELPHASE)
1368    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddRestraint, id=G2gd.wxID_RESTRAINTADD)
1369    if 'macro' in phasedata['General']['Type']:
1370        G2frame.dataFrame.RestraintEdit.Enable(G2gd.wxID_AARESTRAINTADD,True)
1371        G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddAARestraint, id=G2gd.wxID_AARESTRAINTADD)
1372        G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlotAARestraint, id=G2gd.wxID_AARESTRAINTPLOT)
1373    G2frame.dataDisplay = G2gd.GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
1374   
1375    BondRestr = wx.ScrolledWindow(G2frame.dataDisplay)
1376    G2frame.dataDisplay.AddPage(BondRestr,'Bond restraints')
1377    AngleRestr = wx.ScrolledWindow(G2frame.dataDisplay)
1378    G2frame.dataDisplay.AddPage(AngleRestr,'Angle restraints')
1379    PlaneRestr = wx.ScrolledWindow(G2frame.dataDisplay)
1380    G2frame.dataDisplay.AddPage(PlaneRestr,'Plane restraints')
1381    ChiralRestr = wx.ScrolledWindow(G2frame.dataDisplay)
1382    G2frame.dataDisplay.AddPage(ChiralRestr,'Chiral restraints')
1383    if 'macro' in General['Type']:
1384        TorsionRestr = wx.ScrolledWindow(G2frame.dataDisplay)
1385        G2frame.dataDisplay.AddPage(TorsionRestr,'Torsion restraints')
1386        RamaRestr = wx.ScrolledWindow(G2frame.dataDisplay)
1387        G2frame.dataDisplay.AddPage(RamaRestr,'Ramachandran restraints')
1388   
1389    UpdateBondRestr(restrData['Bond'])
1390
1391    G2frame.dataDisplay.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, OnPageChanged)
Note: See TracBrowser for help on using the repository browser.