Changeset 4421


Ignore:
Timestamp:
May 16, 2020 8:55:12 AM (19 months ago)
Author:
toby
Message:

add R.B. extractor; misc doc updates; plt bug after strip Hs; grid bug: uncompleted edits; mac horz. line fix

Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/GSASIIconstrGUI.py

    r4400 r4421  
    2222import wx.grid as wg
    2323import wx.lib.scrolledpanel as wxscroll
     24import wx.lib.gridmovers as gridmovers
    2425import random as ran
    2526import numpy as np
     
    4041import GSASIIspc as G2spc
    4142import GSASIIpy3 as G2py3
     43import GSASIIphsGUI as G2phG
     44import GSASIIscriptable as G2sc
    4245VERY_LIGHT_GREY = wx.Colour(235,235,235)
    4346WACV = wx.ALIGN_CENTER_VERTICAL
     47
     48class DragableRBGrid(wg.Grid):
     49    '''Simple grid implentation for display of rigid body positions.
     50
     51    :param parent: frame or panel where grid will be placed
     52    :param dict rb: dict with atom labels, types and positions
     53    :param function onChange: a callback used every time a value in
     54      rb is changed.
     55    '''
     56    def __init__(self, parent, rb, onChange=None):
     57        #wg.Grid.__init__(self, parent, wx.ID_ANY,size=(-1,200))
     58        wg.Grid.__init__(self, parent, wx.ID_ANY)
     59        self.SetTable(RBDataTable(rb,onChange), True)
     60        # Enable Row moving
     61        gridmovers.GridRowMover(self)
     62        self.Bind(gridmovers.EVT_GRID_ROW_MOVE, self.OnRowMove, self)
     63        self.SetColSize(0, 60)
     64        self.SetColSize(1, 35)
     65        self.SetColSize(5, 40)
     66        for r in range(len(rb['RBlbls'])):
     67            self.SetReadOnly(r,0,isReadOnly=True)
     68            self.SetCellEditor(r,2, wg.GridCellFloatEditor())
     69            self.SetCellEditor(r,3, wg.GridCellFloatEditor())
     70            self.SetCellEditor(r,4, wg.GridCellFloatEditor())
     71
     72    def OnRowMove(self,evt):
     73        'called when a row move needs to take place'
     74        frm = evt.GetMoveRow()          # Row being moved
     75        to = evt.GetBeforeRow()         # Before which row to insert
     76        self.GetTable().MoveRow(frm,to)
     77       
     78    def completeEdits(self):
     79        'complete any outstanding edits'
     80        if self.IsCellEditControlEnabled(): # complete any grid edits in progress
     81            #if GSASIIpath.GetConfigValue('debug'): print ('Completing grid edit')
     82            self.SaveEditControlValue()
     83            self.HideCellEditControl()
     84            self.DisableCellEditControl()
     85           
     86class RBDataTable(wg.GridTableBase):
     87    '''A Table to support :class:`DragableRBGrid`
     88    '''
     89    def __init__(self,rb,onChange):
     90        wg.GridTableBase.__init__(self)
     91        self.colLabels = ['Label','Type','x','y','z','Select']
     92        self.coords = rb['RBcoords']
     93        self.labels = rb['RBlbls']
     94        self.types = rb['RBtypes']
     95        self.index = rb['RBindex']
     96        self.select = rb['RBselection']
     97        self.onChange = onChange
     98
     99    # required methods
     100    def GetNumberRows(self):
     101        return len(self.labels)
     102    def GetNumberCols(self):
     103        return len(self.colLabels)
     104    def IsEmptyCell(self, row, col):
     105        return False
     106    def GetValue(self, row, col):
     107        row = self.index[row]
     108        if col == 0:
     109            return self.labels[row]
     110        elif col == 1:
     111            return self.types[row]
     112        elif col < 5:
     113            return '{:.5f}'.format(self.coords[row][col-2])
     114        elif col == 5:
     115            return self.select[row]
     116    def SetValue(self, row, col, value):
     117        row = self.index[row]
     118        if col == 0:
     119            self.labels[row] = value
     120        elif col == 1:
     121            self.types[row] = value
     122        elif col < 5:
     123            self.coords[row][col-2] = float(value)
     124        elif col == 5:
     125            self.select[row] = value
     126        if self.onChange:
     127            self.onChange()
     128    # implement boolean for selection
     129    def GetTypeName(self, row, col):
     130        if col==5:
     131            return wg.GRID_VALUE_BOOL
     132        else:
     133            return wg.GRID_VALUE_STRING
     134    def CanGetValueAs(self, row, col, typeName):
     135        if col==5 and typeName != wg.GRID_VALUE_BOOL:
     136            return False
     137        return True
     138
     139    # Display column & row labels
     140    def GetColLabelValue(self, col):
     141        return self.colLabels[col]
     142    def GetRowLabelValue(self,row):
     143        return str(row+1)
     144
     145    # Implement "row movement" by updating the pointer array
     146    def MoveRow(self,frm,to):
     147        grid = self.GetView()
     148        if grid:
     149            move = self.index[frm]
     150            del self.index[frm]
     151            if frm > to:
     152                self.index.insert(to,move)
     153            else:
     154                self.index.insert(to-1,move)
     155           
     156            # Notify the grid
     157            grid.BeginBatch()
     158            msg = wg.GridTableMessage(
     159                    self, wg.GRIDTABLE_NOTIFY_ROWS_DELETED, frm, 1
     160                    )
     161            grid.ProcessTableMessage(msg)
     162            msg = wg.GridTableMessage(
     163                    self, wg.GRIDTABLE_NOTIFY_ROWS_INSERTED, to, 1
     164                    )
     165            grid.ProcessTableMessage(msg)
     166            grid.EndBatch()
     167        if self.onChange:
     168            self.onChange()
     169
     170def MakeDrawAtom(data,atom):
     171    'Convert atom to format needed to draw it'
     172    generalData = data['General']
     173    if generalData['Type'] in ['nuclear','faulted',]:
     174        atomInfo = [atom[:2]+atom[3:6]+['1',]+['vdW balls',]+
     175                    ['',]+[[255,255,255],]+atom[9:]+[[],[]]][0]
     176    ct,cs = [1,8]         #type & color
     177    atNum = generalData['AtomTypes'].index(atom[ct])
     178    atomInfo[cs] = list(generalData['Color'][atNum])
     179    return atomInfo
    44180
    45181class ConstraintDialog(wx.Dialog):
     
    15271663#### Rigid bodies
    15281664################################################################################
    1529 
     1665resRBsel = None
    15301666def UpdateRigidBodies(G2frame,data):
    15311667    '''Called when Rigid bodies tree item is selected.
     
    15361672            'RBIds':{'Vector':[],'Residue':[]}})       #empty/bad dict - fill it
    15371673           
    1538     global resList,rbId
     1674    global resList,resRBsel
    15391675    Indx = {}
    15401676    resList = []
     
    15621698            G2gd.SetDataMenuBar(G2frame,G2frame.dataWindow.VectorBodyMenu)
    15631699            G2frame.Bind(wx.EVT_MENU, AddVectorRB, id=G2G.wxID_VECTORBODYADD)
     1700            G2frame.Bind(wx.EVT_MENU, ExtractPhaseRB, id=G2G.wxID_VECTORBODYIMP)
     1701            G2frame.Bind(wx.EVT_MENU, AddVectTrans, id=G2G.wxID_VECTORBODYEXTD)
     1702            G2frame.Bind(wx.EVT_MENU, SaveVectorRB, id=G2G.wxID_VECTORBODYSAV)
     1703            G2frame.Bind(wx.EVT_MENU, ReadVectorRB, id=G2G.wxID_VECTORBODYRD)
    15641704            G2frame.Page = [page,'vrb']
    15651705            UpdateVectorRB()
     
    15671707            G2gd.SetDataMenuBar(G2frame,G2frame.dataWindow.RigidBodyMenu)
    15681708            G2frame.Bind(wx.EVT_MENU, AddResidueRB, id=G2G.wxID_RIGIDBODYADD)
     1709            G2frame.Bind(wx.EVT_MENU, ExtractPhaseRB, id=G2G.wxID_RIGIDBODYIMP)
    15691710            G2frame.Bind(wx.EVT_MENU, OnImportRigidBody, id=G2G.wxID_RIGIDBODYIMPORT)
    15701711            G2frame.Bind(wx.EVT_MENU, OnSaveRigidBody, id=G2G.wxID_RIGIDBODYSAVE)
    15711712            G2frame.Bind(wx.EVT_MENU, OnDefineTorsSeq, id=G2G.wxID_RESIDUETORSSEQ) #enable only if residue RBs exist?
     1713            G2frame.Bind(wx.EVT_MENU, DumpVectorRB, id=G2G.wxID_RESBODYSAV)
     1714            G2frame.Bind(wx.EVT_MENU, LoadVectorRB, id=G2G.wxID_RESBODYRD)
    15721715            G2frame.Page = [page,'rrb']
    15731716            UpdateResidueRB()
     1717        else:
     1718            G2gd.SetDataMenuBar(G2frame)
     1719            #G2frame.Page = [page,'rrb']
    15741720           
    15751721    def getMacroFile(macName):
     
    16261772            SaveResidueRB()
    16271773           
     1774    def DumpVectorRB(event):
     1775        global resRBsel
     1776        if resRBsel not in data['Residue']:
     1777            return
     1778        rbData = data['Residue'][resRBsel]
     1779        pth = G2G.GetExportPath(G2frame)
     1780        dlg = wx.FileDialog(G2frame, 'Choose file to save residue rigid body',
     1781            pth, '', 'RRB files (*.resbody)|*.resbody',
     1782            wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
     1783        try:
     1784            if dlg.ShowModal() == wx.ID_OK:
     1785                filename = dlg.GetPath()
     1786                filename = os.path.splitext(filename)[0]+'.resbody'  # set extension
     1787                fp = open(filename,'w')
     1788                fp.write('Name: '+rbData['RBname']+'\n')
     1789                fp.write('atNames: ')
     1790                for i in rbData['atNames']:
     1791                    fp.write(str(i)+" ")
     1792                fp.write('\n')
     1793                for item in rbData['rbSeq']:
     1794                    fp.write('rbSeq: ')
     1795                    fp.write('{:d} {:d} {:.1f}: '.format(*item[:3]))
     1796                    for num in item[3]:
     1797                        fp.write('{:d} '.format(num))
     1798                    fp.write('\n')
     1799                for i,sym in enumerate(rbData['rbTypes']):
     1800                    fp.write("{:3s}".format(sym))
     1801                    fp.write('{:8.5f}{:9.5f}{:9.5f}   '
     1802                            .format(*rbData['rbXYZ'][i]))
     1803                    fp.write('\n')
     1804                fp.close()
     1805                print ('Vector rigid body saved to: '+filename)
     1806               
     1807        finally:
     1808            dlg.Destroy()
     1809       
     1810    def LoadVectorRB(event):
     1811        AtInfo = data['Residue']['AtInfo']
     1812        pth = G2G.GetExportPath(G2frame)
     1813        dlg = wx.FileDialog(G2frame, 'Choose file to read vector rigid body',
     1814            pth, '', 'RRB files (*.resbody)|*.resbody',
     1815            wx.FD_OPEN)
     1816        try:
     1817            if dlg.ShowModal() == wx.ID_OK:
     1818                filename = dlg.GetPath()
     1819                filename = os.path.splitext(filename)[0]+'.resbody'  # set extension
     1820                fp = open(filename,'r')
     1821                l = fp.readline().strip()
     1822                if 'Name' not in l:
     1823                    fp.close()
     1824                    G2frame.ErrorDialog('Read Error',
     1825                        'File '+filename+' does not start with Name\nFirst line ='
     1826                        +l+'\ninvalid file',parent=G2frame)
     1827                    return
     1828                name = l.split(':')[1].strip()
     1829                line = fp.readline().strip().split(':')[1].split()
     1830                atNames = [i for i in line]
     1831                types = []
     1832                coords = []
     1833                l = fp.readline().strip()
     1834                rbSeq = []
     1835                while 'rbSeq' in l:
     1836                    tag,vals,lst = l.split(':')
     1837                    seq = []
     1838                    for t,v in zip((int,int,float),vals.split()):
     1839                        seq.append(t(v))
     1840                    seq.append([])
     1841                    for num in lst.split():
     1842                        seq[-1].append(int(num))
     1843                    rbSeq.append(seq)
     1844                    l = fp.readline().strip()                   
     1845                while l:
     1846                    nums = l.strip().split()
     1847                    types.append(nums.pop(0))
     1848                    t = types[-1]
     1849                    if t not in AtInfo:
     1850                        Info = G2elem.GetAtomInfo(t)
     1851                        AtInfo[t] = [Info['Drad'],Info['Color']]
     1852                    coords.append([float(nums.pop(0)) for j in range(3)])
     1853                    l = fp.readline().strip()
     1854                fp.close()
     1855            else:
     1856                return       
     1857        finally:
     1858            dlg.Destroy()
     1859        coords = np.array(coords)
     1860        rbid = ran.randint(0,sys.maxsize)
     1861        data['Residue'][rbid] = {'RBname':name,
     1862                'rbXYZ': coords,
     1863                'rbRef':[0,1,2,False],
     1864                'rbTypes':types, 'atNames':atNames,
     1865                'useCount':0,
     1866                'rbSeq':rbSeq, 'SelSeq':[0,0],}
     1867        data['RBIds']['Residue'].append(rbid)
     1868        UpdateResidueRB()
     1869   
    16281870    def AddVectorRB(event):
     1871        'Create a new vector rigid body'
    16291872        AtInfo = data['Vector']['AtInfo']
    16301873        dlg = G2G.MultiIntegerDialog(G2frame,'New Rigid Body',['No. atoms','No. translations'],[1,1])
    16311874        if dlg.ShowModal() == wx.ID_OK:
    16321875            nAtoms,nTrans = dlg.GetValues()
    1633             rbId = ran.randint(0,sys.maxsize)
     1876            rbid = ran.randint(0,sys.maxsize)
    16341877            vecMag = [1.0 for i in range(nTrans)]
    16351878            vecRef = [False for i in range(nTrans)]
     
    16381881            Info = G2elem.GetAtomInfo('C')
    16391882            AtInfo['C'] = [Info['Drad'],Info['Color']]
    1640             data['Vector'][rbId] = {'RBname':'UNKRB','VectMag':vecMag,'rbXYZ':np.zeros((nAtoms,3)),
     1883            data['Vector'][rbid] = {'RBname':'UNKRB','VectMag':vecMag,'rbXYZ':np.zeros((nAtoms,3)),
    16411884                'rbRef':[0,1,2,False],'VectRef':vecRef,'rbTypes':rbTypes,'rbVect':vecVal,'useCount':0}
    1642             data['RBIds']['Vector'].append(rbId)
     1885            data['RBIds']['Vector'].append(rbid)
    16431886        dlg.Destroy()
     1887        UpdateVectorRB()
     1888
     1889    def ExtractPhaseRB(event):
     1890        'Extract a rigid body from a file with a phase'
     1891        def SetupDrawing(atmData):
     1892            '''Add the dicts needed for G2plt.PlotStructure to work to the
     1893            reader .Phase object
     1894            '''
     1895            generalData = atmData['General']
     1896            generalData['BondRadii'] = []
     1897
     1898            G2phG.SetDrawingDefaults(atmData['Drawing'])
     1899            atmData['Drawing'].update(
     1900                {'oldxy':[0.,0.],'Quaternion':[0.,0.,0.,1.],'cameraPos':150.,
     1901                     'viewDir':[0,0,1],'atomPtrs': [2, 1, 6, 17],
     1902                     })
     1903            atmData['Drawing']['showRigidBodies'] = False
     1904            generalData['Map'] = {'MapType':False, 'rho':[]}
     1905            generalData['AtomTypes'] = []
     1906            generalData['BondRadii'] = []
     1907            generalData['AngleRadii'] = []
     1908            generalData['vdWRadii'] = []
     1909            generalData['Color'] = []
     1910            generalData['Isotopes'] = {}
     1911            generalData['Isotope'] = {}
     1912            cx,ct,cs,cia = generalData['AtomPtrs']
     1913            generalData['Mydir'] = G2frame.dirname
     1914            for iat,atom in enumerate(atmData['Atoms']):
     1915                atom[ct] = atom[ct].lower().capitalize()      #force elem symbol to standard form
     1916                if atom[ct] not in generalData['AtomTypes'] and atom[ct] != 'UNK':
     1917                    Info = G2elem.GetAtomInfo(atom[ct])
     1918                    if not Info:
     1919                        atom[ct] = 'UNK'
     1920                        continue
     1921                    atom[ct] = Info['Symbol'] # N.B. symbol might be changed by GetAtomInfo
     1922                    generalData['AtomTypes'].append(atom[ct])
     1923                    generalData['Z'] = Info['Z']
     1924                    generalData['Isotopes'][atom[ct]] = Info['Isotopes']
     1925                    generalData['BondRadii'].append(Info['Drad'])
     1926                    generalData['AngleRadii'].append(Info['Arad'])
     1927                    generalData['vdWRadii'].append(Info['Vdrad'])
     1928                    if atom[ct] in generalData['Isotope']:
     1929                        if generalData['Isotope'][atom[ct]] not in generalData['Isotopes'][atom[ct]]:
     1930                            isotope = list(generalData['Isotopes'][atom[ct]].keys())[-1]
     1931                            generalData['Isotope'][atom[ct]] = isotope
     1932                    else:
     1933                        generalData['Isotope'][atom[ct]] = 'Nat. Abund.'
     1934                        if 'Nat. Abund.' not in generalData['Isotopes'][atom[ct]]:
     1935                            isotope = list(generalData['Isotopes'][atom[ct]].keys())[-1]
     1936                            generalData['Isotope'][atom[ct]] = isotope
     1937                    generalData['Color'].append(Info['Color'])
     1938                    if generalData['Type'] == 'magnetic':
     1939                        if len(landeg) < len(generalData['AtomTypes']):
     1940                            landeg.append(2.0)
     1941            atmData['Drawing']['Atoms'] = []
     1942            for atom in atmData['Atoms']:
     1943                atmData['Drawing']['Atoms'].append(MakeDrawAtom(atmData,atom))
     1944
     1945        def onCancel(event,page=0):
     1946            'complete or bail out from RB define, cleaning up'
     1947            G2frame.rbBook.DeletePage(G2frame.rbBook.FindPage(pagename))
     1948            G2frame.rbBook.SetSelection(page)
     1949
     1950        def Page1():
     1951            '''Show the GUI for first stage of the rigid body with all atoms in
     1952            phase in crystal coordinates. Select the atoms to go onto the
     1953            next stage
     1954            '''
     1955            def ShowSelection(selections):
     1956                'respond to change in atom selections'
     1957                ct,cs = [1,8]
     1958                generalData = rd.Phase['General']
     1959                for i,atom in enumerate(rd.Phase['Drawing']['Atoms']):
     1960                    if i in selections:
     1961                        factor = 1
     1962                    else:
     1963                        factor = 2.5
     1964                    atNum = generalData['AtomTypes'].index(atom[ct])
     1965                    atom[cs] = list(np.array(generalData['Color'][atNum])//factor)
     1966                draw(*drawArgs)
     1967            def onPage1OK(event):
     1968                '1st section has been completed, move onto next'
     1969                G2frame.G2plotNB.Delete(rd.Phase['General']['Name'])
     1970                GetCoords(atmsel)
     1971                Page2()
     1972
     1973            SetupDrawing(rd.Phase) # add information to reader object to allow plotting
     1974            atomlist = [atom[0] for atom in rd.Phase['Atoms']]
     1975            atmsel = list(range(len(rd.Phase['Atoms'])))
     1976            # broken -- # why no bonds?
     1977            #for atm in rd.Phase['Drawing']['Atoms']:
     1978            #    atm[6] = 'balls & sticks'
     1979
     1980            draw,drawArgs = G2plt.PlotStructure(G2frame,rd.Phase,True)
     1981            ShowSelection(atmsel)
     1982
     1983            if G2frame.rbBook.FindPage(pagename) is not None:
     1984                G2frame.rbBook.DeletePage(G2frame.rbBook.FindPage(pagename))
     1985
     1986            RBImp = wx.ScrolledWindow(G2frame.rbBook)
     1987            RBImpPnl = wx.Panel(RBImp)
     1988            G2frame.rbBook.AddPage(RBImp,pagename)
     1989            G2frame.rbBook.SetSelection(G2frame.rbBook.FindPage(pagename))
     1990
     1991            mainSizer = G2G.G2MultiChoiceWindow(RBImpPnl,
     1992                            'Select atoms to import',
     1993                            atomlist,atmsel,OnChange=ShowSelection)
     1994
     1995            # OK/Cancel buttons       
     1996            btnsizer = wx.StdDialogButtonSizer()
     1997            OKbtn = wx.Button(RBImpPnl, wx.ID_OK, 'Continue')
     1998            OKbtn.SetDefault()
     1999            btnsizer.AddButton(OKbtn)
     2000            OKbtn.Bind(wx.EVT_BUTTON,onPage1OK)
     2001            btn = wx.Button(RBImpPnl, wx.ID_CANCEL)
     2002            btn.Bind(wx.EVT_BUTTON,onCancel)
     2003            btnsizer.AddButton(btn)
     2004            btnsizer.Realize()
     2005            mainSizer.Add(btnsizer,0,wx.ALIGN_CENTER,50)
     2006
     2007            RBImpPnl.SetSizer(mainSizer,True)
     2008
     2009            mainSizer.Layout()   
     2010            Size = mainSizer.GetMinSize()
     2011            Size[0] += 40
     2012            Size[1] = max(Size[1],G2frame.GetSize()[1]-200) + 20
     2013            RBImpPnl.SetSize(Size)
     2014            RBImp.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
     2015            RBImp.Scroll(0,0)
     2016
     2017        def Page2():
     2018            '''Show the GUI for the second stage, where selected atoms are
     2019            now in Cartesian space, manipulate the axes and export selected
     2020            atoms to a vector or residue rigid body.
     2021            '''
     2022            def UpdateDraw(event=None):
     2023                'Called when info changes in grid, replots'
     2024                UpdateVectorBody(rbData)
     2025                DrawCallback()
     2026               
     2027            def onSetAll(event):
     2028                'Set all atoms as selected'
     2029                for i in range(len(rd.Phase['RBselection'])):
     2030                    rd.Phase['RBselection'][i] = True
     2031                grid.ForceRefresh()
     2032                UpdateDraw()
     2033               
     2034            def onToggle(event):
     2035                'Toggles selection state for all atoms'
     2036                grid.completeEdits()
     2037                for i in range(len(rd.Phase['RBselection'])):
     2038                    rd.Phase['RBselection'][i] = not rd.Phase['RBselection'][i]
     2039                grid.ForceRefresh()
     2040                UpdateDraw()
     2041               
     2042            def onSetOrigin(event):
     2043                'Resets origin to midpoint between all selected atoms'
     2044                grid.completeEdits()
     2045                center = np.array([0.,0.,0.])
     2046                count = 0
     2047                for i in range(len(rd.Phase['RBselection'])):
     2048                    if rd.Phase['RBselection'][i]:
     2049                        count += 1
     2050                        center += rd.Phase['RBcoords'][i]
     2051                if count:
     2052                    rd.Phase['RBcoords'] -= center/count
     2053                grid.ForceRefresh()
     2054                UpdateDraw()
     2055               
     2056            def onSetX(event):
     2057                grid.completeEdits()
     2058                center = np.array([0.,0.,0.])
     2059                count = 0
     2060                for i in range(len(rd.Phase['RBselection'])):
     2061                    if rd.Phase['RBselection'][i]:
     2062                        count += 1
     2063                        center += rd.Phase['RBcoords'][i]
     2064                if not count:
     2065                    return
     2066                XP = center/count
     2067                if np.sqrt(sum(XP**2)) < 0.1:
     2068                    G2G.G2MessageBox(G2frame,
     2069                            'The selected atom(s) are too close to the origin',
     2070                            'near origin')
     2071                    return
     2072                XP /= np.sqrt(np.sum(XP**2))
     2073                Z = np.array((0,0,1.))
     2074                YP = np.cross(Z,XP)
     2075                ZP = np.cross(XP,YP)
     2076                trans = np.array((XP,YP,ZP))
     2077                # update atoms in place
     2078                rd.Phase['RBcoords'][:] = np.inner(trans,rd.Phase['RBcoords']).T
     2079                grid.ForceRefresh()
     2080                UpdateDraw()
     2081
     2082            def onSetPlane(event):
     2083                '''Compute least-squares plane for selected atoms;
     2084                move atoms so that LS plane aligned with x-y plane,
     2085                with minimum required change to x
     2086                '''
     2087                grid.completeEdits()
     2088                #X,Y,Z = rd.Phase['RBcoords'][rd.Phase['RBselection']].T
     2089                XYZ = rd.Phase['RBcoords'][rd.Phase['RBselection']]
     2090                Z = copy.copy(XYZ[:,2])
     2091                if len(Z) < 3:
     2092                    G2G.G2MessageBox(G2frame,'A plane requires three or more atoms',
     2093                                     'Need more atoms')
     2094                    return
     2095                XY0 = copy.copy(XYZ)
     2096                XY0[:,2] = 1
     2097                # solve for  ax + bx + z + c = 0 or equivalently ax + bx + c = -z
     2098                try:
     2099                    (a,b,c), resd, rank, sing = nl.lstsq(XY0, -Z)
     2100                except:
     2101                    G2G.G2MessageBox(G2frame,
     2102                            'Error computing plane; are atoms in a line?',
     2103                            'Computation error')
     2104                    return
     2105                # new coordinate system is z' (zp, normal to plane = [a,b,1]),
     2106                # y' = z' cross x (YP, = [0,1,-b])
     2107                # x' = (z' cross x) cross z'
     2108                # this puts XP as close as possible to X with XP & YP in plane
     2109                ZP = np.array([a,b,1])
     2110                ZP /= np.sqrt(np.sum(ZP**2))
     2111                YP = np.array([0,1,-b])
     2112                YP /= np.sqrt(np.sum(YP**2))
     2113                XP = np.cross(YP,ZP)
     2114                trans = np.array((XP,YP,ZP))
     2115                # update atoms in place
     2116                rd.Phase['RBcoords'][:] = np.inner(trans,rd.Phase['RBcoords']).T
     2117                grid.ForceRefresh()
     2118                UpdateDraw()
     2119
     2120            def onAddVector(event):
     2121                '''Adds selected atoms as a new vector rigid body.
     2122                Closes out the importer tab when done.
     2123                '''
     2124                grid.completeEdits()
     2125                rb = MakeVectorBody(os.path.split(filename)[1])
     2126                UpdateVectorBody(rb,True)
     2127                if len(rb['rbTypes']) < 3: return # must have at least 3 atoms
     2128                rbid = ran.randint(0,sys.maxsize)
     2129                data['Vector'][rbid] = rb
     2130                data['RBIds']['Vector'].append(rbid)
     2131                AtInfo = data['Vector']['AtInfo']
     2132                for t in rb['rbTypes']:
     2133                    if t in data['Vector']['AtInfo']: continue
     2134                    Info = G2elem.GetAtomInfo(t)
     2135                    data['Vector']['AtInfo'][t] = [Info['Drad'],Info['Color']]
     2136                G2frame.G2plotNB.Delete('Rigid body')
     2137                onCancel(event,0)
     2138               
     2139            def onAddResidue(event):
     2140                '''Adds selected atoms as a new residue rigid body.
     2141                Closes out the importer tab when done.
     2142                '''
     2143                grid.completeEdits()
     2144                name = os.path.split(filename)[1]
     2145                rbXYZ = []
     2146                rbTypes = []
     2147                atNames = []
     2148                for i in rd.Phase['RBindex']:
     2149                    if rd.Phase['RBselection'][i]:
     2150                        rbXYZ.append(rd.Phase['RBcoords'][i])
     2151                        rbTypes.append(rd.Phase['RBtypes'][i])
     2152                        atNames.append(rd.Phase['RBlbls'][i])
     2153                if len(rbTypes) < 3: return # must have at least 3 atoms
     2154                rbXYZ = np.array(rbXYZ)
     2155                rbid = ran.randint(0,sys.maxsize)
     2156                data['Residue'][rbid] = {'RBname':name,'rbXYZ':rbXYZ,
     2157                    'rbTypes':rbTypes,'atNames':atNames,'rbRef':[0,1,2,False],
     2158                    'rbSeq':[],'SelSeq':[0,0],'useCount':0}
     2159                data['RBIds']['Residue'].append(rbid)
     2160                AtInfo = data['Residue']['AtInfo']
     2161                for t in rbTypes:
     2162                    if t in data['Residue']['AtInfo']: continue
     2163                    Info = G2elem.GetAtomInfo(t)
     2164                    data['Residue']['AtInfo'][t] = [Info['Drad'],Info['Color']]
     2165
     2166                print ('Rigid body added')
     2167                G2frame.G2plotNB.Delete('Rigid body')
     2168                onCancel(event,1)
     2169
     2170            if G2frame.rbBook.FindPage(pagename) is not None:
     2171                G2frame.rbBook.DeletePage(G2frame.rbBook.FindPage(pagename))
     2172            RBImp = wx.ScrolledWindow(G2frame.rbBook)
     2173            RBImpPnl = wx.Panel(RBImp)
     2174            G2frame.rbBook.AddPage(RBImp,pagename)
     2175            G2frame.rbBook.SetSelection(G2frame.rbBook.FindPage(pagename))
     2176            generalData = rd.Phase['General']
     2177            AtInfo = {}
     2178            ct = 1
     2179            for t in rd.Phase['RBtypes']:
     2180                if t in AtInfo: continue
     2181                Info = G2elem.GetAtomInfo(t)
     2182                AtInfo[t] = [Info['Drad'],Info['Color']]
     2183            plotDefaults = {'oldxy':[0.,0.],'Quaternion':[0.,0.,0.,1.],'cameraPos':30.,'viewDir':[0,0,1],}
     2184
     2185            rd.Phase['RBindex'] = list(range(len(rd.Phase['RBtypes'])))
     2186            rd.Phase['RBselection'] = len(rd.Phase['RBtypes']) * [True]
     2187            rbData = MakeVectorBody()
     2188            DrawCallback = G2plt.PlotRigidBody(G2frame,'Vector',
     2189                                    AtInfo,rbData,plotDefaults)
     2190
     2191            mainSizer = wx.BoxSizer(wx.HORIZONTAL)
     2192            gridSizer = wx.BoxSizer(wx.VERTICAL)
     2193            grid = DragableRBGrid(RBImpPnl,rd.Phase,UpdateDraw)
     2194            gridSizer.Add(grid)
     2195            gridSizer.Add(
     2196                wx.StaticText(RBImpPnl,wx.ID_ANY,'Reorder atoms by dragging'),
     2197                0,wx.ALL)
     2198            mainSizer.Add(gridSizer)
     2199            mainSizer.Add((5,5))
     2200            btnSizer = wx.BoxSizer(wx.VERTICAL)
     2201            btn = wx.Button(RBImpPnl, wx.ID_OK, 'Set All')
     2202            btn.Bind(wx.EVT_BUTTON,onSetAll)
     2203            btnSizer.Add(btn,0,wx.ALIGN_CENTER)
     2204            btn = wx.Button(RBImpPnl, wx.ID_OK, 'Toggle')
     2205            btn.Bind(wx.EVT_BUTTON,onToggle)
     2206            btnSizer.Add(btn,0,wx.ALIGN_CENTER)
     2207            btnSizer.Add((-1,15))
     2208            btnSizer.Add(
     2209                wx.StaticText(RBImpPnl,wx.ID_ANY,'Reorient using selected\natoms...'),
     2210                0,wx.ALL)
     2211            btnSizer.Add((-1,5))
     2212            btn = wx.Button(RBImpPnl, wx.ID_OK, 'Set origin')
     2213            btn.Bind(wx.EVT_BUTTON,onSetOrigin)
     2214            btnSizer.Add(btn,0,wx.ALIGN_CENTER)
     2215            btn = wx.Button(RBImpPnl, wx.ID_OK, 'Place in xy plane')
     2216            btn.Bind(wx.EVT_BUTTON,onSetPlane)
     2217            btnSizer.Add(btn,0,wx.ALIGN_CENTER)
     2218            btn = wx.Button(RBImpPnl, wx.ID_OK, 'Define selection as X')
     2219            btn.Bind(wx.EVT_BUTTON,onSetX)
     2220            btnSizer.Add(btn,0,wx.ALIGN_CENTER)
     2221            btnSizer.Add((-1,15))
     2222            btnSizer.Add(
     2223                wx.StaticText(RBImpPnl,wx.ID_ANY,'Use selected atoms to\ncreate...'),
     2224                0,wx.ALL)
     2225            btnSizer.Add((-1,5))
     2226            btn = wx.Button(RBImpPnl, wx.ID_OK, 'a Vector Body')
     2227            btn.Bind(wx.EVT_BUTTON,onAddVector)
     2228            btnSizer.Add(btn,0,wx.ALIGN_CENTER)
     2229            btn = wx.Button(RBImpPnl, wx.ID_OK, 'a Residue Body')
     2230            btn.Bind(wx.EVT_BUTTON,onAddResidue)
     2231            btnSizer.Add(btn,0,wx.ALIGN_CENTER)
     2232            btn = wx.Button(RBImpPnl, wx.ID_CANCEL)
     2233            btn.Bind(wx.EVT_BUTTON,onCancel)
     2234            btnSizer.Add((-1,10))
     2235            btnSizer.Add(btn,0,wx.ALIGN_CENTER)
     2236
     2237            mainSizer.Add(btnSizer)
     2238            RBImpPnl.SetSizer(mainSizer,True)
     2239            mainSizer.Layout()   
     2240            Size = mainSizer.GetMinSize()
     2241            Size[0] += 40
     2242            Size[1] = max(Size[1],G2frame.GetSize()[1]-200) + 20
     2243            RBImpPnl.SetSize(Size)
     2244            RBImp.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
     2245            RBImp.Scroll(0,0)
     2246
     2247        def GetCoords(atmsel):
     2248            '''Create orthogonal coordinates for selected atoms.
     2249            Place the origin at the center of the body
     2250            '''
     2251            atms = rd.Phase['Atoms']
     2252            cell = rd.Phase['General']['Cell'][1:7]
     2253            Amat,Bmat = G2lat.cell2AB(cell)
     2254            rd.Phase['RBcoords'] = np.array([np.inner(Amat,atms[i][3:6]) for i in atmsel])
     2255            rd.Phase['RBcoords'] -= rd.Phase['RBcoords'].mean(axis=0)  # origin to middle
     2256            rd.Phase['RBtypes'] = [atms[i][1] for i in atmsel]
     2257            rd.Phase['RBlbls'] = [atms[i][0] for i in atmsel]
     2258
     2259        def UpdateVectorBody(rb,useSelection=False):
     2260            '''Put the atoms in order to pass for plotting or for storage as
     2261            a vector rigid body.
     2262
     2263            :param dict rb: rigid body contents created in :func:`MakeVectorBody`
     2264            :param bool useSelection: True if the rd.Phase['RBselection']
     2265              values will be used to select which atoms are included in the
     2266              rigid body. If False (default) they are included in rb
     2267              and are used for plotting.         
     2268            '''
     2269            coordlist = []
     2270            typeslist = []
     2271            sellist = []
     2272            for i in rd.Phase['RBindex']:
     2273                use = True
     2274                if useSelection and not rd.Phase['RBselection'][i]: use = False
     2275                if use:
     2276                    coordlist.append(rd.Phase['RBcoords'][i])
     2277                    typeslist.append(rd.Phase['RBtypes'][i])
     2278                    sellist.append(rd.Phase['RBselection'][i])
     2279            coordlist = np.array(coordlist)
     2280            rb['rbXYZ'] = coordlist
     2281            rb['rbVect'] = [coordlist]
     2282            rb['rbTypes'] = typeslist
     2283            if not useSelection:
     2284                rb['Selection'] = sellist
     2285            elif 'Selection' in rb:
     2286                del rb['Selection']
     2287
     2288        def MakeVectorBody(name=''):
     2289            '''Make the basic vector rigid body dict (w/o coordinates) used for
     2290            export and for plotting
     2291            '''
     2292            nTrans = 1
     2293            vecMag = [1.0]
     2294            vecRef = [False]
     2295            rb = {'RBname':name,'VectMag':vecMag,
     2296                    'rbRef':[0,1,2,False],'VectRef':vecRef,
     2297                    'useCount':0}
     2298            UpdateVectorBody(rb)
     2299            return rb
     2300
     2301        # get importer type and a phase file of that type
     2302        G2sc.LoadG2fil()
     2303        choices = [rd.formatName for  rd in G2sc.Readers['Phase']]
     2304        dlg = G2G.G2SingleChoiceDialog(G2frame,'Select the format of the file',
     2305                                     'select format',choices)
     2306        try:
     2307            if dlg.ShowModal() == wx.ID_OK:
     2308                col = dlg.GetSelection()
     2309            else:
     2310                col = None
     2311        finally:
     2312            dlg.Destroy()
     2313        reader = G2sc.Readers['Phase'][col]
     2314
     2315        choices = reader.formatName + " file ("
     2316        w = ""
     2317        for extn in reader.extensionlist:
     2318            if w != "": w += ";"
     2319            w += "*" + extn
     2320        choices += w + ")|" + w
     2321        #choices += "|zip archive (.zip)|*.zip"
     2322        if not reader.strictExtension:
     2323            choices += "|any file (*.*)|*.*"
     2324        typ = '( type '+reader.formatName+')'
     2325        filelist = G2G.GetImportFile(G2frame,
     2326                        message="Choose phase input file"+typ,
     2327                        defaultFile="",wildcard=choices,style=wx.FD_OPEN)
     2328        if len(filelist) != 1: return
     2329
     2330        # read in the phase file
     2331        filename = filelist[0]
     2332        rd = reader
     2333        with open(filename, 'Ur') as fp:
     2334            rd.ReInitialize()
     2335            rd.errors = ""
     2336            if not rd.ContentsValidator(filename):   # Report error
     2337                G2fil.G2Print("Warning: File {} has a validation error".format(filename))
     2338                return
     2339            if len(rd.selections) > 1:
     2340                print("File {} has {} phases. This is unexpected."
     2341                                    .format(filename,len(rd.selections)))
     2342                return
     2343
     2344            rd.objname = os.path.basename(filename)
     2345            try:
     2346                flag = rd.Reader(filename)
     2347            except:
     2348                G2fil.G2Print("Warning: read of file {} failed".format(filename))
     2349                return
     2350
     2351        pagename = 'Rigid body importer'
     2352        Page1()
     2353        return
     2354
     2355    def AddVectTrans(event):
     2356        'Add a translation to an existing vector rigid body'
     2357        choices = []
     2358        rbIdlist = []
     2359        for rbid in data['RBIds']['Vector']:
     2360            if rbid != 'AtInfo':
     2361                rbIdlist.append(rbid)
     2362                choices.append(data['Vector'][rbid]['RBname'])
     2363        if len(choices) == 0:
     2364            G2G.G2MessageBox(G2frame,'No Vector Rigid Bodies found',
     2365                                 'No VR Bodies')
     2366            return
     2367        elif len(choices) == 1:
     2368            rbid = rbIdlist[0]
     2369        else:
     2370            dlg = G2G.G2SingleChoiceDialog(G2frame,'Select the rigid body to save',
     2371                                  'select format',choices)
     2372            try:
     2373                if dlg.ShowModal() == wx.ID_OK:
     2374                    rbid = rbIdlist[dlg.GetSelection()]
     2375                else:
     2376                    return
     2377            finally:
     2378                dlg.Destroy()
     2379        data['Vector'][rbid]['VectMag'] += [1.0]
     2380        data['Vector'][rbid]['VectRef'] += [False]
     2381        nAtoms = len(data['Vector'][rbid]['rbXYZ'])
     2382        data['Vector'][rbid]['rbVect'] += [np.zeros((nAtoms,3))]
     2383        UpdateVectorRB()
     2384       
     2385    def SaveVectorRB(event):
     2386        choices = []
     2387        rbIdlist = []
     2388        for rbid in data['RBIds']['Vector']:
     2389            if rbid != 'AtInfo':
     2390                rbIdlist.append(rbid)
     2391                choices.append(data['Vector'][rbid]['RBname'])
     2392        if len(choices) == 0:
     2393            G2G.G2MessageBox(G2frame,'No Vector Rigid Bodies found',
     2394                                 'No VR Bodies')
     2395            return
     2396        elif len(choices) == 1:
     2397            rbid = rbIdlist[0]
     2398        else:
     2399            dlg = G2G.G2SingleChoiceDialog(G2frame,'Select the rigid body to save',
     2400                                  'select format',choices)
     2401            try:
     2402                if dlg.ShowModal() == wx.ID_OK:
     2403                    rbid = rbIdlist[dlg.GetSelection()]
     2404                else:
     2405                    return
     2406            finally:
     2407                dlg.Destroy()
     2408             
     2409        pth = G2G.GetExportPath(G2frame)
     2410        dlg = wx.FileDialog(G2frame, 'Choose file to save vector rigid body',
     2411            pth, '', 'VRB files (*.vecbody)|*.vecbody',
     2412            wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
     2413        try:
     2414            if dlg.ShowModal() == wx.ID_OK:
     2415                filename = dlg.GetPath()
     2416                filename = os.path.splitext(filename)[0]+'.vecbody'  # set extension
     2417                fp = open(filename,'w')
     2418                fp.write('Name: '+data['Vector'][rbid]['RBname']+'\n')
     2419                fp.write('Trans: ')
     2420                for i in data['Vector'][rbid]['VectMag']:
     2421                    fp.write(str(i)+" ")
     2422                fp.write('\n')
     2423                ntrans = len(data['Vector'][rbid]['VectMag'])
     2424                for i,sym in enumerate(data['Vector'][rbid]['rbTypes']):
     2425                    fp.write("{:3s}".format(sym))
     2426                    for j in range(ntrans):
     2427                        fp.write('{:8.5f}{:9.5f}{:9.5f}   '
     2428                            .format(*data['Vector'][rbid]['rbVect'][j][i]))
     2429                    fp.write('\n')
     2430                fp.close()
     2431                print ('Vector rigid body saved to: '+filename)
     2432        finally:
     2433            dlg.Destroy()
     2434           
     2435    def ReadVectorRB(event):
     2436        AtInfo = data['Vector']['AtInfo']
     2437        pth = G2G.GetExportPath(G2frame)
     2438        dlg = wx.FileDialog(G2frame, 'Choose file to read vector rigid body',
     2439            pth, '', 'VRB files (*.vecbody)|*.vecbody',
     2440            wx.FD_OPEN)
     2441        try:
     2442            if dlg.ShowModal() == wx.ID_OK:
     2443                filename = dlg.GetPath()
     2444                filename = os.path.splitext(filename)[0]+'.vecbody'  # set extension
     2445                fp = open(filename,'r')
     2446                l = fp.readline().strip()
     2447                if 'Name' not in l:
     2448                    fp.close()
     2449                    G2frame.ErrorDialog('Read Error',
     2450                        'File '+filename+' does not start with Name\nFirst line ='
     2451                        +l+'\ninvalid file',parent=G2frame)
     2452                    return
     2453                name = l.split(':')[1].strip()
     2454                trans = fp.readline().strip().split(':')[1].split()
     2455                vecMag = [float(i) for i in trans]
     2456                ntrans = len(trans)
     2457                vecs = [[] for i in range(ntrans)]
     2458                types = []
     2459                l = fp.readline().strip()
     2460                while l:
     2461                    nums = l.strip().split()
     2462                    types.append(nums.pop(0))
     2463                    t = types[-1]
     2464                    if t not in AtInfo:
     2465                        Info = G2elem.GetAtomInfo(t)
     2466                        AtInfo[t] = [Info['Drad'],Info['Color']]
     2467                    for i in range(ntrans):
     2468                        vecs[i].append([float(nums.pop(0)) for j in range(3)])
     2469                    l = fp.readline().strip()
     2470                fp.close()
     2471            else:
     2472                return       
     2473        finally:
     2474            dlg.Destroy()
     2475        natoms = len(types)
     2476        vecs = [np.array(vecs[i]) for i in range(ntrans)]
     2477        rbid = ran.randint(0,sys.maxsize)
     2478        data['Vector'][rbid] = {'RBname':name,'VectMag':vecMag,
     2479                'rbXYZ':np.zeros((natoms,3)),
     2480                'rbRef':[0,1,2,False],'VectRef':ntrans*[False],
     2481                'rbTypes':types,
     2482                'rbVect':vecs,'useCount':0}
     2483        data['RBIds']['Vector'].append(rbid)
    16442484        UpdateVectorRB()
    16452485       
    16462486    def AddResidueRB(event):
    1647         global rbId
     2487        global resRBsel
    16482488        AtInfo = data['Residue']['AtInfo']
    16492489        macro = getMacroFile('rigid body')
     
    16542494            items = macStr.split()
    16552495            if 'I' == items[0]:
    1656                 rbId = ran.randint(0,sys.maxsize)
     2496                resRBsel = ran.randint(0,sys.maxsize)
    16572497                rbName = items[1]
    16582498                rbTypes = []
     
    16832523                        iMove = [int(macStr[i])-1 for i in range(3,nMove+3)]
    16842524                        rbSeq.append([iBeg,iFin,angle,iMove])
    1685                 data['Residue'][rbId] = {'RBname':rbName,'rbXYZ':rbXYZ,'rbTypes':rbTypes,
     2525                data['Residue'][resRBsel] = {'RBname':rbName,'rbXYZ':rbXYZ,'rbTypes':rbTypes,
    16862526                    'atNames':atNames,'rbRef':[nOrig-1,mRef-1,nRef-1,True],'rbSeq':rbSeq,
    16872527                    'SelSeq':[0,0],'useCount':0}
    1688                 data['RBIds']['Residue'].append(rbId)
     2528                data['RBIds']['Residue'].append(resRBsel)
    16892529                print ('Rigid body '+rbName+' added')
    16902530            macStr = macro.readline()
     
    16932533       
    16942534    def ImportResidueRB():
    1695         global rbId
     2535        global resRBsel
    16962536        AtInfo = data['Residue']['AtInfo']
    16972537        text,ext = getTextFile()
    16982538        if not text:
    16992539            return
    1700         rbId = ran.randint(0,sys.maxsize)
     2540        resRBsel = ran.randint(0,sys.maxsize)
    17012541        rbTypes = []
    17022542        rbXYZ = []
     
    17582598            Mat = G2mth.getRBTransMat(X,Y)
    17592599            rbXYZ = np.inner(Mat,rbXYZ).T
    1760             data['Residue'][rbId] = {'RBname':'UNKRB','rbXYZ':rbXYZ,'rbTypes':rbTypes,
     2600            data['Residue'][resRBsel] = {'RBname':'UNKRB','rbXYZ':rbXYZ,'rbTypes':rbTypes,
    17612601                'atNames':atNames,'rbRef':[0,1,2,False],'rbSeq':[],'SelSeq':[0,0],'useCount':0}
    1762             data['RBIds']['Residue'].append(rbId)
     2602            data['RBIds']['Residue'].append(resRBsel)
    17632603            print ('Rigid body UNKRB added')
    17642604        text.close()
     
    17662606       
    17672607    def SaveResidueRB():
    1768         global rbId
     2608        global resRBsel
    17692609        pth = G2G.GetExportPath(G2frame)
    17702610        dlg = wx.FileDialog(G2frame, 'Choose PDB file for Atom XYZ', pth, '',
     
    17732613            if dlg.ShowModal() == wx.ID_OK:
    17742614                filename = dlg.GetPath()
    1775                 # make sure extension is .pkslst
    1776                 filename = os.path.splitext(filename)[0]+'.pdb'
     2615                filename = os.path.splitext(filename)[0]+'.pdb'  # make extension .pdb
    17772616                File = open(filename,'w')       
    1778                 rbData =  data['Residue'][rbId]
     2617                rbData =  data['Residue'][resRBsel]
    17792618                for iat,xyz in enumerate(rbData['rbXYZ']):
    17802619                    File.write('ATOM %6d  %-4s%3s     1    %8.3f%8.3f%8.3f  1.00  0.00          %2s\n'%(
     
    18242663                       
    18252664    def OnDefineTorsSeq(event):
    1826         global rbId
    1827         rbData = data['Residue'][rbId]
     2665        global resRBsel
     2666        rbData = data['Residue'][resRBsel]
    18282667        if not len(rbData):
    18292668            return
     
    18602699            return
    18612700        SetStatusLine(' You may use e.g. "c60" or "s60" for a vector entry')
    1862         def rbNameSizer(rbId,rbData):
     2701        def rbNameSizer(rbid,rbData):
    18632702
    18642703            def OnRBName(event):
     
    18692708            def OnDelRB(event):
    18702709                Obj = event.GetEventObject()
    1871                 rbId = Indx[Obj.GetId()]
    1872                 if rbId in data['Vector']:
    1873                     del data['Vector'][rbId]
    1874                     data['RBIds']['Vector'].remove(rbId)
     2710                rbid = Indx[Obj.GetId()]
     2711                if rbid in data['Vector']:
     2712                    del data['Vector'][rbid]
     2713                    data['RBIds']['Vector'].remove(rbid)
    18752714                    rbData['useCount'] -= 1
    18762715                wx.CallAfter(UpdateVectorRB)
    1877                
    18782716            def OnPlotRB(event):
    18792717                Obj = event.GetEventObject()
    1880                 Obj.SetValue(False)
    18812718                G2plt.PlotRigidBody(G2frame,'Vector',AtInfo,rbData,plotDefaults)
    18822719           
     
    18852722                0,wx.ALIGN_CENTER_VERTICAL)
    18862723            RBname = wx.TextCtrl(VectorRBDisplay,-1,rbData['RBname'])
    1887             Indx[RBname.GetId()] = rbId
     2724            Indx[RBname.GetId()] = rbid
    18882725            RBname.Bind(wx.EVT_TEXT_ENTER,OnRBName)
    18892726            RBname.Bind(wx.EVT_KILL_FOCUS,OnRBName)
    18902727            nameSizer.Add(RBname,0,wx.ALIGN_CENTER_VERTICAL)
    18912728            nameSizer.Add((5,0),)
    1892             plotRB = wx.CheckBox(VectorRBDisplay,-1,'Plot?')
    1893             Indx[plotRB.GetId()] = rbId
    1894             plotRB.Bind(wx.EVT_CHECKBOX,OnPlotRB)
     2729            plotRB =  wx.Button(VectorRBDisplay,wx.ID_ANY,'Plot',
     2730                                style=wx.BU_EXACTFIT)
     2731            plotRB.Bind(wx.EVT_BUTTON, OnPlotRB)
     2732            Indx[plotRB.GetId()] = rbid
    18952733            nameSizer.Add(plotRB,0,wx.ALIGN_CENTER_VERTICAL)
    18962734            nameSizer.Add((5,0),)
    18972735            if not rbData['useCount']:
    1898                 delRB = wx.CheckBox(VectorRBDisplay,-1,'Delete?')
    1899                 Indx[delRB.GetId()] = rbId
    1900                 delRB.Bind(wx.EVT_CHECKBOX,OnDelRB)
     2736                delRB = wx.Button(VectorRBDisplay,wx.ID_ANY,"Delete",
     2737                                style=wx.BU_EXACTFIT)
     2738                delRB.Bind(wx.EVT_BUTTON, OnDelRB)
     2739                Indx[delRB.GetId()] = rbid
    19012740                nameSizer.Add(delRB,0,wx.ALIGN_CENTER_VERTICAL)
    19022741            return nameSizer
    19032742           
    1904         def rbRefAtmSizer(rbId,rbData):
     2743        def rbRefAtmSizer(rbid,rbData):
    19052744           
    19062745            def OnRefSel(event):
     
    19092748                sel = Obj.GetValue()
    19102749                rbData['rbRef'][iref] = atNames.index(sel)
    1911                 FillRefChoice(rbId,rbData)
     2750                FillRefChoice(rbid,rbData)
    19122751           
    19132752            refAtmSizer = wx.BoxSizer(wx.HORIZONTAL)
     
    19232762                    'Orientation reference atoms A-B-C: '),0,wx.ALIGN_CENTER_VERTICAL)
    19242763                for i in range(3):
    1925                     choices = [atNames[j] for j in refChoice[rbId][i]]
     2764                    choices = [atNames[j] for j in refChoice[rbid][i]]
    19262765                    refSel = wx.ComboBox(VectorRBDisplay,-1,value='',
    19272766                        choices=choices,style=wx.CB_READONLY|wx.CB_DROPDOWN)
     
    19322771            return refAtmSizer
    19332772                       
    1934         def rbVectMag(rbId,imag,rbData):
     2773        def rbVectMag(rbid,imag,rbData):
    19352774           
    19362775            def OnRBVectorMag(event):
    19372776                event.Skip()
    19382777                Obj = event.GetEventObject()
    1939                 rbId,imag = Indx[Obj.GetId()]
     2778                rbid,imag = Indx[Obj.GetId()]
    19402779                try:
    19412780                    val = float(Obj.GetValue())
     
    19472786                Obj.SetValue('%8.4f'%(val))
    19482787                wx.CallAfter(UpdateVectorRB,VectorRB.GetScrollPos(wx.VERTICAL))
    1949                 G2plt.PlotRigidBody(G2frame,'Vector',AtInfo,data['Vector'][rbId],plotDefaults)
     2788                G2plt.PlotRigidBody(G2frame,'Vector',AtInfo,data['Vector'][rbid],plotDefaults)
    19502789               
    19512790            def OnRBVectorRef(event):
    19522791                Obj = event.GetEventObject()
    1953                 rbId,imag = Indx[Obj.GetId()]
     2792                rbid,imag = Indx[Obj.GetId()]
    19542793                rbData['VectRef'][imag] = Obj.GetValue()
    19552794                       
     
    19582797                0,wx.ALIGN_CENTER_VERTICAL)
    19592798            magValue = wx.TextCtrl(VectorRBDisplay,-1,'%8.4f'%(rbData['VectMag'][imag]))
    1960             Indx[magValue.GetId()] = [rbId,imag]
     2799            Indx[magValue.GetId()] = [rbid,imag]
    19612800            magValue.Bind(wx.EVT_TEXT_ENTER,OnRBVectorMag)
    19622801            magValue.Bind(wx.EVT_KILL_FOCUS,OnRBVectorMag)
     
    19662805            magref.SetValue(rbData['VectRef'][imag])
    19672806            magref.Bind(wx.EVT_CHECKBOX,OnRBVectorRef)
    1968             Indx[magref.GetId()] = [rbId,imag]
     2807            Indx[magref.GetId()] = [rbid,imag]
    19692808            magSizer.Add(magref,0,wx.ALIGN_CENTER_VERTICAL)
    19702809            return magSizer
    19712810           
    1972         def rbVectors(rbId,imag,mag,XYZ,rbData):
     2811        def rbVectors(rbid,imag,mag,XYZ,rbData):
    19732812
    19742813            def TypeSelect(event):
     
    19962835                    except ValueError:
    19972836                        pass
    1998                 G2plt.PlotRigidBody(G2frame,'Vector',AtInfo,data['Vector'][rbId],plotDefaults)
     2837                G2plt.PlotRigidBody(G2frame,'Vector',AtInfo,data['Vector'][rbid],plotDefaults)
    19992838                wx.CallAfter(UpdateVectorRB,VectorRB.GetScrollPos(wx.VERTICAL))
    20002839
     
    20172856                vecGrid.Bind(wg.EVT_GRID_CELL_LEFT_DCLICK, TypeSelect)
    20182857            attr = wx.grid.GridCellAttr()
     2858            attr.IncRef()
    20192859            attr.SetEditor(G2G.GridFractionEditor(vecGrid))
    20202860            for c in range(3):
     2861                attr.IncRef()
    20212862                vecGrid.SetColAttr(c, attr)
    20222863            for row in range(vecTable.GetNumberRows()):
     
    20302871            return vecSizer
    20312872       
    2032         def FillRefChoice(rbId,rbData):
     2873        def FillRefChoice(rbid,rbData):
    20332874            choiceIds = [i for i in range(len(rbData['rbTypes']))]
    20342875           
     
    20362877            for i in range(3):
    20372878                choiceIds.remove(rbRef[i])
    2038             refChoice[rbId] = [choiceIds[:],choiceIds[:],choiceIds[:]]
     2879            refChoice[rbid] = [choiceIds[:],choiceIds[:],choiceIds[:]]
    20392880            for i in range(3):
    2040                 refChoice[rbId][i].append(rbRef[i])
    2041                 refChoice[rbId][i].sort()     
     2881                refChoice[rbid][i].append(rbRef[i])
     2882                refChoice[rbid][i].sort()     
    20422883           
    20432884        if VectorRB.GetSizer(): VectorRB.GetSizer().Clear(True)
    20442885        VectorRBSizer = wx.BoxSizer(wx.VERTICAL)
    2045         for rbId in data['RBIds']['Vector']:
    2046             if rbId != 'AtInfo':
    2047                 rbData = data['Vector'][rbId]
    2048                 FillRefChoice(rbId,rbData)
    2049                 VectorRBSizer.Add(rbNameSizer(rbId,rbData),0)
    2050                 VectorRBSizer.Add(rbRefAtmSizer(rbId,rbData),0)
     2886        first = True
     2887        for rbid in data['RBIds']['Vector']:
     2888            if rbid != 'AtInfo':
     2889                rbData = data['Vector'][rbid]
     2890                FillRefChoice(rbid,rbData)
     2891                if not first:
     2892                    G2G.HorizontalLine(VectorRBSizer,VectorRBDisplay)
     2893                VectorRBSizer.Add(rbNameSizer(rbid,rbData),0)
     2894                VectorRBSizer.Add(rbRefAtmSizer(rbid,rbData),0)
    20512895                XYZ = np.array([[0.,0.,0.] for Ty in rbData['rbTypes']])
    20522896                for imag,mag in enumerate(rbData['VectMag']):
    20532897                    XYZ += mag*rbData['rbVect'][imag]
    2054                     VectorRBSizer.Add(rbVectMag(rbId,imag,rbData),0)
    2055                     VectorRBSizer.Add(rbVectors(rbId,imag,mag,XYZ,rbData),0)
     2898                    VectorRBSizer.Add(rbVectMag(rbid,imag,rbData),0)
     2899                    VectorRBSizer.Add(rbVectors(rbid,imag,mag,XYZ,rbData),0)
    20562900                VectorRBSizer.Add((5,5),0)
    2057                 data['Vector'][rbId]['rbXYZ'] = XYZ       
     2901                data['Vector'][rbid]['rbXYZ'] = XYZ       
     2902                first = False
    20582903        VectorRBSizer.Layout()   
    20592904        VectorRBDisplay.SetSizer(VectorRBSizer,True)
     
    20682913        '''Draw the contents of the Residue Rigid Body tab for Rigid Bodies tree entry
    20692914        '''
    2070         global rbId
    2071         def rbNameSizer(rbId,rbData):
     2915        global resRBsel
     2916        def rbNameSizer(rbid,rbData):
    20722917
    20732918            def OnDelRB(event):
    20742919                Obj = event.GetEventObject()
    2075                 rbId = Indx[Obj.GetId()]
    2076                 if rbId in data['Residue']:
    2077                     del data['Residue'][rbId]
    2078                     data['RBIds']['Residue'].remove(rbId)
     2920                rbid = Indx[Obj.GetId()]
     2921                if rbid in data['Residue']:
     2922                    del data['Residue'][rbid]
     2923                    data['RBIds']['Residue'].remove(rbid)
    20792924                wx.CallAfter(UpdateResidueRB)
    20802925               
    20812926            def OnStripH(event):
    20822927                Obj = event.GetEventObject()
    2083                 rbId = Indx[Obj.GetId()]
    2084                 if rbId in data['Residue']:
     2928                rbid = Indx[Obj.GetId()]
     2929                if rbid in data['Residue']:
    20852930                    newNames = []
    20862931                    newTypes = []
     
    20992944            def OnPlotRB(event):
    21002945                Obj = event.GetEventObject()
    2101                 Obj.SetValue(False)
    21022946                G2plt.PlotRigidBody(G2frame,'Residue',AtInfo,rbData,plotDefaults)
    21032947               
     
    21082952            nameSizer.Add(G2G.ValidatedTxtCtrl(ResidueRBDisplay,rbData,'RBname'),0,WACV)
    21092953            nameSizer.Add((5,0),)
    2110             plotRB = wx.CheckBox(ResidueRBDisplay,-1,'Plot?')
    2111             Indx[plotRB.GetId()] = rbId
    2112             plotRB.Bind(wx.EVT_CHECKBOX,OnPlotRB)
     2954            plotRB =  wx.Button(ResidueRBDisplay,wx.ID_ANY,'Plot',
     2955                                style=wx.BU_EXACTFIT)
     2956            plotRB.Bind(wx.EVT_BUTTON, OnPlotRB)
     2957            Indx[plotRB.GetId()] = rbid
    21132958            nameSizer.Add(plotRB,0,wx.ALIGN_CENTER_VERTICAL)
    21142959            nameSizer.Add((5,0),)
    21152960            if not rbData['useCount']:
    2116                 delRB = wx.CheckBox(ResidueRBDisplay,-1,'Delete?')
    2117                 Indx[delRB.GetId()] = rbId
    2118                 delRB.Bind(wx.EVT_CHECKBOX,OnDelRB)
     2961                delRB = wx.Button(ResidueRBDisplay,wx.ID_ANY,"Delete",
     2962                                style=wx.BU_EXACTFIT)
     2963                delRB.Bind(wx.EVT_BUTTON, OnDelRB)
     2964                Indx[delRB.GetId()] = rbid
    21192965                nameSizer.Add(delRB,0,wx.ALIGN_CENTER_VERTICAL)
    21202966                if 'H'  in rbData['rbTypes']:
    2121                     stripH = wx.CheckBox(ResidueRBDisplay,-1,'Strip H-atoms?')
    2122                     Indx[stripH.GetId()] = rbId
    2123                     stripH.Bind(wx.EVT_CHECKBOX,OnStripH)
     2967                    stripH = wx.Button(ResidueRBDisplay,wx.ID_ANY,
     2968                                "Strip H-atoms",
     2969                                style=wx.BU_EXACTFIT)
     2970                    stripH.Bind(wx.EVT_BUTTON, OnStripH)
     2971                    Indx[stripH.GetId()] = rbid
    21242972                    nameSizer.Add(stripH,0,wx.ALIGN_CENTER_VERTICAL)
    21252973            return nameSizer
    21262974           
    2127         def rbResidues(rbId,rbData):
     2975        def rbResidues(rbid,rbData):
    21282976           
    21292977            def TypeSelect(event):
    21302978                AtInfo = data['Residue']['AtInfo']
    21312979                r,c = event.GetRow(),event.GetCol()
    2132                 if vecGrid.GetColLabelValue(c) == 'Type':
     2980                if resGrid.GetColLabelValue(c) == 'Type':
    21332981                    PE = G2elemGUI.PickElement(G2frame,oneOnly=True)
    21342982                    if PE.ShowModal() == wx.ID_OK:
     
    21392987                                AtInfo[El] = [Info['Drad']['Color']]
    21402988                            rbData['rbTypes'][r] = El
    2141                             vecGrid.SetCellValue(r,c,El)
     2989                            resGrid.SetCellValue(r,c,El)
    21422990                    PE.Destroy()
    21432991
     
    21462994                if r >= 0 and (0 <= c < 3):
    21472995                    try:
    2148                         val = float(vecGrid.GetCellValue(r,c))
     2996                        val = float(resGrid.GetCellValue(r,c))
    21492997                        rbData['rbXYZ'][r][c] = val
    21502998                    except ValueError:
     
    21543002                r,c =  event.GetRow(),event.GetCol()
    21553003                if c < 0:                   #only row clicks
    2156                     for vecgrid in resList:
    2157                         vecgrid.ClearSelection()
    2158                     vecGrid.SelectRow(r,True)
     3004                    for iGrid in resList:
     3005                        iGrid.ClearSelection()
     3006                    resGrid.SelectRow(r,True)
    21593007
    21603008            def OnRefSel(event):
    2161                
    21623009                Obj = event.GetEventObject()
    21633010                iref,res,jref = Indx[Obj.GetId()]
     
    21673014                    G2G.G2MessageBox(G2frame,'You should not select an H-atom for rigid body orientation')
    21683015                rbData['rbRef'][iref] = ind
    2169                 FillRefChoice(rbId,rbData)
     3016                FillRefChoice(rbid,rbData)
    21703017                for i,ref in enumerate(RefObjs[jref]):
    2171                     ref.SetItems([atNames[j] for j in refChoice[rbId][i]])
     3018                    ref.SetItems([atNames[j] for j in refChoice[rbid][i]])
    21723019                    ref.SetValue(atNames[rbData['rbRef'][i]])                   
    21733020                rbXYZ = rbData['rbXYZ']
     
    21993046                rowLabels.append(str(ivec))
    22003047            vecTable = G2G.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
    2201             vecGrid = G2G.GSGrid(ResidueRBDisplay)
    2202             Indx[vecGrid.GetId()] = rbId
    2203             resList.append(vecGrid)
    2204             vecGrid.SetTable(vecTable, True)
     3048            resGrid = G2G.GSGrid(ResidueRBDisplay)
     3049            Indx[resGrid.GetId()] = rbid
     3050            resList.append(resGrid)
     3051            resGrid.SetTable(vecTable, True)
    22053052            if 'phoenix' in wx.version():
    2206                 vecGrid.Bind(wg.EVT_GRID_CELL_CHANGED, ChangeCell)
     3053                resGrid.Bind(wg.EVT_GRID_CELL_CHANGED, ChangeCell)
    22073054            else:
    2208                 vecGrid.Bind(wg.EVT_GRID_CELL_CHANGE, ChangeCell)
    2209             vecGrid.Bind(wg.EVT_GRID_CELL_LEFT_DCLICK, TypeSelect)
    2210             vecGrid.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK, RowSelect)
     3055                resGrid.Bind(wg.EVT_GRID_CELL_CHANGE, ChangeCell)
     3056            resGrid.Bind(wg.EVT_GRID_CELL_LEFT_DCLICK, TypeSelect)
     3057            resGrid.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK, RowSelect)
    22113058            attr = wx.grid.GridCellAttr()
    2212             attr.SetEditor(G2G.GridFractionEditor(vecGrid))
     3059            attr.IncRef()
     3060            attr.SetEditor(G2G.GridFractionEditor(resGrid))
    22133061            for c in range(3):
    2214                 vecGrid.SetColAttr(c, attr)
     3062                attr.IncRef()
     3063                resGrid.SetColAttr(c, attr)
    22153064            for row in range(vecTable.GetNumberRows()):
    22163065                for col in range(5):
    2217                     vecGrid.SetCellStyle(row,col,VERY_LIGHT_GREY,True)
    2218             vecGrid.AutoSizeColumns(False)
     3066                    resGrid.SetCellStyle(row,col,VERY_LIGHT_GREY,True)
     3067            resGrid.AutoSizeColumns(False)
    22193068            vecSizer = wx.BoxSizer()
    2220             vecSizer.Add(vecGrid)
     3069            vecSizer.Add(resGrid)
    22213070           
    22223071            refAtmSizer = wx.BoxSizer(wx.HORIZONTAL)
     
    22323081                refObj = [0,0,0]
    22333082                for i in range(3):
    2234                     choices = [atNames[j] for j in refChoice[rbId][i]]
     3083                    choices = [atNames[j] for j in refChoice[rbid][i]]
    22353084                    refSel = wx.ComboBox(ResidueRBDisplay,-1,value='',
    22363085                        choices=choices,style=wx.CB_READONLY|wx.CB_DROPDOWN)
    22373086                    refSel.SetValue(atNames[rbRef[i]])
    22383087                    refSel.Bind(wx.EVT_COMBOBOX, OnRefSel)
    2239                     Indx[refSel.GetId()] = [i,vecGrid,len(RefObjs)]
     3088                    Indx[refSel.GetId()] = [i,resGrid,len(RefObjs)]
    22403089                    refObj[i] = refSel
    22413090                    refAtmSizer.Add(refSel,0,wx.ALIGN_CENTER_VERTICAL)
     
    22473096            return mainSizer
    22483097           
    2249         def SeqSizer(angSlide,rbId,iSeq,Seq,atNames):
     3098        def Add2SeqSizer(seqSizer,angSlide,rbid,iSeq,Seq,atNames):
    22503099           
    22513100            def ChangeAngle(event):
    22523101                event.Skip()
    22533102                Obj = event.GetEventObject()
    2254                 rbId,Seq = Indx[Obj.GetId()][:2]
     3103                rbid,Seq = Indx[Obj.GetId()][:2]
    22553104                val = Seq[2]
    22563105                try:
     
    22603109                    pass
    22613110                Obj.SetValue('%8.2f'%(val))
    2262                 G2plt.PlotRigidBody(G2frame,'Residue',AtInfo,data['Residue'][rbId],plotDefaults)
     3111                G2plt.PlotRigidBody(G2frame,'Residue',AtInfo,data['Residue'][rbid],plotDefaults)
    22633112               
    22643113            def OnRadBtn(event):
    22653114                Obj = event.GetEventObject()
    22663115                Seq,iSeq,angId = Indx[Obj.GetId()]
    2267                 data['Residue'][rbId]['SelSeq'] = [iSeq,angId]
     3116                data['Residue'][rbid]['SelSeq'] = [iSeq,angId]
    22683117                angSlide.SetValue(int(100*Seq[2]))
    22693118               
    22703119            def OnDelBtn(event):
    22713120                Obj = event.GetEventObject()
    2272                 rbId,Seq = Indx[Obj.GetId()]
    2273                 data['Residue'][rbId]['rbSeq'].remove(Seq)       
     3121                rbid,Seq = Indx[Obj.GetId()]
     3122                data['Residue'][rbid]['rbSeq'].remove(Seq)       
    22743123                wx.CallAfter(UpdateResidueRB)
    22753124           
    2276             seqSizer = wx.FlexGridSizer(0,5,2,2)
    2277             seqSizer.AddGrowableCol(3,0)
    22783125            iBeg,iFin,angle,iMove = Seq
    2279             ang = wx.TextCtrl(ResidueRBDisplay,-1,'%8.2f'%(angle),size=(50,20))
     3126            ang = wx.TextCtrl(ResidueRBDisplay,wx.ID_ANY,
     3127                    '%8.2f'%(angle),size=(70,-1),style=wx.TE_PROCESS_ENTER)
    22803128            if not iSeq:
    2281                 radBt = wx.RadioButton(ResidueRBDisplay,-1,'',style=wx.RB_GROUP)
    2282                 data['Residue'][rbId]['SelSeq'] = [iSeq,ang.GetId()]
     3129                radBt = wx.RadioButton(ResidueRBDisplay,wx.ID_ANY,
     3130                                           '',style=wx.RB_GROUP)
     3131                data['Residue'][rbid]['SelSeq'] = [iSeq,ang.GetId()]
     3132                radBt.SetValue(True)
    22833133            else:
    2284                 radBt = wx.RadioButton(ResidueRBDisplay,-1,'')
     3134                radBt = wx.RadioButton(ResidueRBDisplay,wx.ID_ANY,'')
    22853135            radBt.Bind(wx.EVT_RADIOBUTTON,OnRadBtn)                   
    22863136            seqSizer.Add(radBt)
    2287             delBt = wx.RadioButton(ResidueRBDisplay,-1,'')
    2288             delBt.Bind(wx.EVT_RADIOBUTTON,OnDelBtn)
     3137            delBt =  wx.Button(ResidueRBDisplay,wx.ID_ANY,'Del',
     3138                                style=wx.BU_EXACTFIT)
     3139            delBt.Bind(wx.EVT_BUTTON,OnDelBtn)
    22893140            seqSizer.Add(delBt)
    2290             bond = wx.TextCtrl(ResidueRBDisplay,-1,'%s %s'%(atNames[iBeg],atNames[iFin]),size=(50,20))
     3141            bond = wx.StaticText(ResidueRBDisplay,wx.ID_ANY,
     3142                        '%s %s'%(atNames[iBeg],atNames[iFin]),size=(50,20))
    22913143            seqSizer.Add(bond,0,wx.ALIGN_CENTER_VERTICAL)
    22923144            Indx[radBt.GetId()] = [Seq,iSeq,ang.GetId()]
    2293             Indx[delBt.GetId()] = [rbId,Seq]
    2294             Indx[ang.GetId()] = [rbId,Seq,ang]
     3145            Indx[delBt.GetId()] = [rbid,Seq]
     3146            Indx[ang.GetId()] = [rbid,Seq,ang]
    22953147            ang.Bind(wx.EVT_TEXT_ENTER,ChangeAngle)
    22963148            ang.Bind(wx.EVT_KILL_FOCUS,ChangeAngle)
     
    22993151            for i in iMove:   
    23003152                atms += ' %s,'%(atNames[i])
    2301             moves = wx.TextCtrl(ResidueRBDisplay,-1,atms[:-1],size=(200,20))
     3153            moves = wx.StaticText(ResidueRBDisplay,wx.ID_ANY,
     3154                            atms[:-1],size=(200,20))
    23023155            seqSizer.Add(moves,1,wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.RIGHT)
    23033156            return seqSizer
     
    23253178            return slideSizer,angSlide
    23263179           
    2327         def FillRefChoice(rbId,rbData):
     3180        def FillRefChoice(rbid,rbData):
    23283181            choiceIds = [i for i in range(len(rbData['atNames']))]
    23293182            for seq in rbData['rbSeq']:
     
    23393192                except ValueError:
    23403193                    pass
    2341             refChoice[rbId] = [choiceIds[:],choiceIds[:],choiceIds[:]]
     3194            refChoice[rbid] = [choiceIds[:],choiceIds[:],choiceIds[:]]
    23423195            for i in range(3):
    2343                 refChoice[rbId][i].append(rbRef[i])
    2344                 refChoice[rbId][i].sort()
     3196                refChoice[rbid][i].append(rbRef[i])
     3197                refChoice[rbid][i].sort()
    23453198               
    23463199        def OnSelect(event):
    2347             global rbId
    2348             rbname = rbchoice[select.GetSelection()]
    2349             rbId = RBnames[rbname]
     3200            global resRBsel
     3201            sel = select.GetSelection()
     3202            if sel == 0: return # 1st entry is blank
     3203            rbname = rbchoice[sel-1]
     3204            resRBsel = RBnames[rbname]
    23503205            wx.CallLater(100,UpdateResidueRB)
    23513206           
     
    23743229        if len(RBnames) > 1:
    23753230            selSizer = wx.BoxSizer(wx.HORIZONTAL)
    2376             selSizer.Add(wx.StaticText(ResidueRBDisplay,label=' Select residue to view:'),0)
     3231            selSizer.Add(wx.StaticText(ResidueRBDisplay,
     3232                                label=' Select residue to view:'),0)
    23773233            rbchoice.sort()
    2378             select = wx.ComboBox(ResidueRBDisplay,choices=rbchoice)
     3234            select = wx.ComboBox(ResidueRBDisplay,choices=['']+rbchoice)
    23793235            select.Bind(wx.EVT_COMBOBOX,OnSelect)
    23803236            selSizer.Add(select,0)
    23813237            ResidueRBSizer.Add(selSizer,0)
    2382         try:
    2383             if not rbId:
    2384                 rbId = RBnames[rbchoice[0]]
    2385         except NameError:
    2386             rbId = RBnames[rbchoice[0]]
    2387         rbData = data['Residue'][rbId]
    2388         FillRefChoice(rbId,rbData)
    2389         ResidueRBSizer.Add(rbNameSizer(rbId,rbData),0)
    2390         ResidueRBSizer.Add(rbResidues(rbId,rbData),0)
    2391         ResidueRBSizer.Add((5,5),0)
    2392         if rbData['rbSeq']:
     3238        if resRBsel not in data['RBIds']['Residue']:
     3239            resRBsel = RBnames[rbchoice[0]]
     3240        rbData = data['Residue'][resRBsel]
     3241        FillRefChoice(resRBsel,rbData)
     3242        ResidueRBSizer.Add(rbNameSizer(resRBsel,rbData),0)
     3243        ResidueRBSizer.Add(rbResidues(resRBsel,rbData),0)
     3244        if len(rbData['rbSeq']):
     3245            ResidueRBSizer.Add((-1,15),0)
    23933246            slideSizer,angSlide = SlideSizer()
    2394         if len(rbData['rbSeq']):
    2395             ResidueRBSizer.Add(wx.StaticText(ResidueRBDisplay,-1,
    2396                 'Sel  Del  Bond             Angle      Riding atoms'),
    2397                 0,wx.ALIGN_CENTER_VERTICAL)                       
    2398         for iSeq,Seq in enumerate(rbData['rbSeq']):
    2399             ResidueRBSizer.Add(SeqSizer(angSlide,rbId,iSeq,Seq,rbData['atNames']))
    2400         if rbData['rbSeq']:
     3247            seqSizer = wx.FlexGridSizer(0,5,4,8)
     3248            for lbl in 'Sel','','Bond','Angle','Riding atoms':
     3249                seqSizer.Add(wx.StaticText(ResidueRBDisplay,wx.ID_ANY,lbl))
     3250            ResidueRBSizer.Add(seqSizer)
     3251#            for iSeq,Seq in enumerate(rbData['rbSeq']):
     3252#                ResidueRBSizer.Add(SeqSizer(angSlide,resRBsel,iSeq,Seq,rbData['atNames']))
     3253            for iSeq,Seq in enumerate(rbData['rbSeq']):
     3254                Add2SeqSizer(seqSizer,angSlide,resRBsel,iSeq,Seq,rbData['atNames'])
    24013255            ResidueRBSizer.Add(slideSizer,)
    24023256
  • trunk/GSASIIctrlGUI.py

    r4410 r4421  
    3636                                   a filter to select choices and buttons to make selection
    3737                                   of multiple items more simple.
     38:class:`G2MultiChoiceWindow`       Similar to :class:`G2MultiChoiceDialog` but provides
     39                                   a sizer that can be placed in a frame or panel.
    3840:class:`G2SingleChoiceDialog`      Dialog similar to wx.SingleChoiceDialog, but provides
    3941                                   a filter to help search through choices.
     
    10391041def HorizontalLine(sizer,parent):
    10401042    '''Draws a horizontal line as wide as the window.
    1041     This shows up on the Mac as a very thin line, no matter what I do
    10421043    '''
    1043     line = wx.StaticLine(parent, size=(-1,3), style=wx.LI_HORIZONTAL)
     1044    if sys.platform == "darwin":
     1045        line = wx.StaticLine(parent, size=(-1,1), style=wx.LI_HORIZONTAL)
     1046        line.SetBackgroundColour((128,128,128))
     1047    else:
     1048        line = wx.StaticLine(parent, size=(-1,3), style=wx.LI_HORIZONTAL)
    10441049    sizer.Add(line, 0, wx.EXPAND|wx.ALIGN_CENTER|wx.ALL, 5)
    10451050
     
    17371742        self.OKbtn.Enable(True)
    17381743
     1744###############################################  Multichoice in a sizer with set all, toggle & filter options
     1745class G2MultiChoiceWindow(wx.BoxSizer):
     1746    '''Creates a sizer similar to G2MultiChoiceDialog except that
     1747    buttons are added to set all choices and to toggle all choices. This
     1748    is placed in a sizer, so that it can be used in a frame or panel.
     1749
     1750    :param parent: reference to parent frame/panel
     1751    :param str title: heading above list of choices
     1752    :param list ChoiceList: a list of choices where one more will be selected
     1753    :param list SelectList: a list of selected choices
     1754    :param bool toggle: If True (default) the toggle and select all buttons
     1755      are displayed
     1756    :param bool monoFont: If False (default), use a variable-spaced font;
     1757      if True use a equally-spaced font.
     1758    :param bool filterBox: If True (default) an input widget is placed on
     1759      the window and only entries matching the entered text are shown.
     1760    :param function OnChange: a reference to a callable object, that
     1761      is called each time any a choice is changed. Default is None which
     1762      will not be called.
     1763    :param list OnChangeArgs: a list of arguments to be supplied to function
     1764      OnChange. The default is a null list.
     1765    :returns: the name of the created sizer
     1766    '''
     1767    def __init__(self, parent, title, ChoiceList, SelectList, toggle=True,
     1768                 monoFont=False, filterBox=True,
     1769                     OnChange=None, OnChangeArgs=[]):
     1770        self.SelectList = SelectList
     1771        self.ChoiceList = ['%4d) %s'%(i,item) for i,item in enumerate(ChoiceList)] # numbered list of choices (list of str values)
     1772        self.frm = parent
     1773        self.Selections = len(self.ChoiceList) * [False,] # selection status for each choice (list of bools)
     1774        self.filterlist = range(len(self.ChoiceList)) # list of the choice numbers that have been filtered (list of int indices)
     1775        self.Stride = 1
     1776        self.OnChange = OnChange
     1777        self.OnChangeArgs = OnChangeArgs
     1778        # fill frame
     1779        wx.BoxSizer.__init__(self,wx.VERTICAL)
     1780        # fill the sizer
     1781        Sizer = self
     1782        topSizer = wx.BoxSizer(wx.HORIZONTAL)
     1783        topSizer.Add(wx.StaticText(self.frm,wx.ID_ANY,title,size=(-1,35)),
     1784            1,wx.ALL|wx.EXPAND|WACV,1)
     1785        if filterBox:
     1786            self.timer = wx.Timer()
     1787            self.timer.Bind(wx.EVT_TIMER,self.Filter)
     1788            topSizer.Add(wx.StaticText(self.frm,wx.ID_ANY,'Name \nFilter: '),0,wx.ALL|WACV,1)
     1789            self.filterBox = wx.TextCtrl(self.frm, wx.ID_ANY, size=(80,-1),style=wx.TE_PROCESS_ENTER)
     1790            self.filterBox.Bind(wx.EVT_TEXT,self.onChar)
     1791            self.filterBox.Bind(wx.EVT_TEXT_ENTER,self.Filter)
     1792            topSizer.Add(self.filterBox,0,wx.ALL|WACV,0)
     1793        Sizer.Add(topSizer,0,wx.ALL|wx.EXPAND,8)
     1794        self.settingRange = False
     1795        self.rangeFirst = None
     1796        self.clb = wx.CheckListBox(self.frm, wx.ID_ANY, (30,30), wx.DefaultSize, self.ChoiceList)
     1797        self.clb.Bind(wx.EVT_CHECKLISTBOX,self.OnCheck)
     1798        if monoFont:
     1799            font1 = wx.Font(self.clb.GetFont().GetPointSize(),
     1800                            wx.MODERN, wx.NORMAL, wx.NORMAL, False)
     1801            self.clb.SetFont(font1)
     1802        Sizer.Add(self.clb,1,wx.LEFT|wx.RIGHT|wx.EXPAND,10)
     1803        Sizer.Add((-1,10))
     1804        # set/toggle buttons
     1805        if toggle:
     1806            tSizer = wx.BoxSizer(wx.HORIZONTAL)
     1807            tSizer.Add(wx.StaticText(self.frm,label=' Apply stride:'),0,WACV)
     1808            numbs = [str(i+1) for i in range(9)]+[str(2*i+10) for i in range(6)]
     1809            self.stride = wx.ComboBox(self.frm,value='1',choices=numbs,style=wx.CB_READONLY|wx.CB_DROPDOWN)
     1810            self.stride.Bind(wx.EVT_COMBOBOX,self.OnStride)
     1811            tSizer.Add(self.stride,0,WACV)
     1812            Sizer.Add(tSizer,0,wx.LEFT,12)
     1813            tSizer = wx.BoxSizer(wx.HORIZONTAL)
     1814            setBut = wx.Button(self.frm,wx.ID_ANY,'Set All')
     1815            setBut.Bind(wx.EVT_BUTTON,self._SetAll)
     1816            tSizer.Add(setBut)
     1817            togBut = wx.Button(self.frm,wx.ID_ANY,'Toggle All')
     1818            togBut.Bind(wx.EVT_BUTTON,self._ToggleAll)
     1819            tSizer.Add(togBut)
     1820            self.rangeBut = wx.ToggleButton(self.frm,wx.ID_ANY,'Set Range')
     1821            self.rangeBut.Bind(wx.EVT_TOGGLEBUTTON,self.SetRange)
     1822            tSizer.Add(self.rangeBut)
     1823            Sizer.Add(tSizer,0,wx.LEFT,12)
     1824            tSizer = wx.BoxSizer(wx.HORIZONTAL)
     1825            self.rangeCapt = wx.StaticText(self.frm,wx.ID_ANY,'')
     1826            tSizer.Add(self.rangeCapt,1,wx.EXPAND,1)
     1827            Sizer.Add(tSizer,0,wx.LEFT,12)
     1828        self.SetSelections(self.SelectList)
     1829               
     1830    def OnStride(self,event):
     1831        self.Stride = int(self.stride.GetValue())
     1832
     1833    def SetRange(self,event):
     1834        '''Respond to a press of the Set Range button. Set the range flag and
     1835        the caption next to the button
     1836        '''
     1837        self.settingRange = self.rangeBut.GetValue()
     1838        if self.settingRange:
     1839            self.rangeCapt.SetLabel('Select range start')
     1840        else:
     1841            self.rangeCapt.SetLabel('')           
     1842        self.rangeFirst = None
     1843       
     1844    def GetSelections(self):
     1845        'Returns a list of the indices for the selected choices'
     1846        # update self.Selections with settings for displayed items
     1847        for i in range(len(self.filterlist)):
     1848            self.Selections[self.filterlist[i]] = self.clb.IsChecked(i)
     1849        # return all selections, shown or hidden
     1850        return [i for i in range(len(self.Selections)) if self.Selections[i]]
     1851       
     1852    def SetSelections(self,selList):
     1853        '''Sets the selection indices in selList as selected. Resets any previous
     1854        selections for compatibility with wx.MultiChoiceDialog. Note that
     1855        the state for only the filtered items is shown.
     1856
     1857        :param list selList: indices of items to be selected. These indices
     1858          are referenced to the order in self.ChoiceList
     1859        '''
     1860        self.Selections = len(self.ChoiceList) * [False,] # reset selections
     1861        for sel in selList:
     1862            self.Selections[sel] = True
     1863        self._ShowSelections()
     1864
     1865    def _ShowSelections(self):
     1866        'Show the selection state for displayed items'
     1867        if 'phoenix' in wx.version():
     1868            self.clb.SetCheckedItems(
     1869                [i for i in range(len(self.filterlist)) if self.Selections[self.filterlist[i]]]
     1870            ) # Note anything previously checked will be cleared.
     1871        else:
     1872            self.clb.SetChecked(
     1873                [i for i in range(len(self.filterlist)) if self.Selections[self.filterlist[i]]]
     1874            ) # Note anything previously checked will be cleared.
     1875        if self.OnChange:
     1876            self.OnChange(self.GetSelections(),*self.OnChangeArgs)
     1877        self.SelectList.clear()
     1878        for i,val in enumerate(self.Selections):
     1879            if val: self.SelectList.append(i)
     1880
     1881    def _SetAll(self,event):
     1882        'Set all viewed choices on'
     1883        if 'phoenix' in wx.version():
     1884            self.clb.SetCheckedItems(range(0,len(self.filterlist),self.Stride))
     1885        else:
     1886            self.clb.SetChecked(range(0,len(self.filterlist),self.Stride))
     1887        self.stride.SetValue('1')
     1888        self.Stride = 1
     1889        self.GetSelections() # record current selections
     1890        self._ShowSelections()
     1891       
     1892    def _ToggleAll(self,event):
     1893        'flip the state of all viewed choices'
     1894        for i in range(len(self.filterlist)):
     1895            self.clb.Check(i,not self.clb.IsChecked(i))
     1896        self.GetSelections() # record current selections
     1897        self._ShowSelections()
     1898           
     1899    def onChar(self,event):
     1900        'Respond to keyboard events in the Filter box'
     1901        if self.timer.IsRunning():
     1902            self.timer.Stop()
     1903        self.timer.Start(1000,oneShot=True)
     1904        if event: event.Skip()
     1905       
     1906    def OnCheck(self,event):
     1907        '''for CheckListBox events; if Set Range is in use, this sets/clears all
     1908        entries in range between start and end according to the value in start.
     1909        Repeated clicks on the start change the checkbox state, but do not trigger
     1910        the range copy.
     1911        The caption next to the button is updated on the first button press.
     1912        '''
     1913        if self.settingRange:
     1914            id = event.GetInt()
     1915            if self.rangeFirst is None:
     1916                name = self.clb.GetString(id)
     1917                self.rangeCapt.SetLabel(name+' to...')
     1918                self.rangeFirst = id
     1919            elif self.rangeFirst == id:
     1920                pass
     1921            else:
     1922                for i in range(min(self.rangeFirst,id), max(self.rangeFirst,id)+1,self.Stride):
     1923                    self.clb.Check(i,self.clb.IsChecked(self.rangeFirst))
     1924                self.rangeBut.SetValue(False)
     1925                self.rangeCapt.SetLabel('')
     1926                self.settingRange = False
     1927                self.rangeFirst = None
     1928        self.GetSelections() # record current selections
     1929        self._ShowSelections()
     1930
     1931    def Filter(self,event):
     1932        '''Read text from filter control and select entries that match. Called by
     1933        Timer after a delay with no input or if Enter is pressed.
     1934        '''
     1935        if self.timer.IsRunning():
     1936            self.timer.Stop()
     1937        self.GetSelections() # record current selections
     1938        txt = self.filterBox.GetValue()
     1939        self.clb.Clear()
     1940       
     1941        self.filterlist = []
     1942        if txt:
     1943            txt = txt.lower()
     1944            ChoiceList = []
     1945            for i,item in enumerate(self.ChoiceList):
     1946                if item.lower().find(txt) != -1:
     1947                    ChoiceList.append(item)
     1948                    self.filterlist.append(i)
     1949        else:
     1950            self.filterlist = range(len(self.ChoiceList))
     1951            ChoiceList = self.ChoiceList
     1952        self.clb.AppendItems(ChoiceList)
     1953        self._ShowSelections()
     1954       
    17391955def SelectEdit1Var(G2frame,array,labelLst,elemKeysLst,dspLst,refFlgElem):
    17401956    '''Select a variable from a list, then edit it and select histograms
  • trunk/GSASIIdataGUI.py

    r4412 r4421  
    37723772    def OnAddPhase(self,event):
    37733773        'Add a new, empty phase to the tree. Called by Data/Add Phase menu'
     3774        self.CheckNotebook()
    37743775        if not GetGPXtreeItemId(self,self.root,'Phases'):
    37753776            sub = self.GPXtree.AppendItem(parent=self.root,text='Phases')
     
    54265427        self.ResidueRBMenu = wx.Menu(title='')
    54275428        self.ResidueRBMenu.Append(G2G.wxID_RIGIDBODYIMPORT,'Import XYZ','Import rigid body XYZ from file')
    5428         self.ResidueRBMenu.Append(G2G.wxID_RIGIDBODYSAVE,'Save PDB','Save rigid body to PDB file')       
    5429         self.ResidueRBMenu.Append(G2G.wxID_RESIDUETORSSEQ,'Define sequence','Define torsion sequence')
     5429        G2G.Define_wxId('wxID_RIGIDBODYIMP')
     5430        self.ResidueRBMenu.Append(G2G.wxID_RIGIDBODYIMP,'Extract from file',
     5431                                'Extract rigid body from phase file')
     5432        self.ResidueRBMenu.Append(G2G.wxID_RIGIDBODYSAVE,'Save as PDB','Save rigid body to PDB file')       
     5433        self.ResidueRBMenu.Append(G2G.wxID_RESIDUETORSSEQ,'Define torsion','Define torsion sequence')
    54305434        self.ResidueRBMenu.Append(G2G.wxID_RIGIDBODYADD,'Import residues','Import residue rigid bodies from macro file')
     5435        G2G.Define_wxId('wxID_RESBODYSAV')
     5436        self.ResidueRBMenu.Append(G2G.wxID_RESBODYSAV,'Save rigid body','Write a rigid body to a file')
     5437        G2G.Define_wxId('wxID_RESBODYRD')
     5438        self.ResidueRBMenu.Append(G2G.wxID_RESBODYRD,'Read rigid body','Read a rigid body from a file')
    54315439        self.RigidBodyMenu.Append(menu=self.ResidueRBMenu, title='Edit Residue Body')
    54325440        self.PostfillDataMenu()
     
    54375445        self.VectorRBEdit.Append(G2G.wxID_VECTORBODYADD,'Add rigid body','Add vector rigid body')
    54385446        self.VectorBodyMenu.Append(menu=self.VectorRBEdit, title='Edit Vector Body')
     5447        G2G.Define_wxId('wxID_VECTORBODYIMP')
     5448        self.VectorRBEdit.Append(G2G.wxID_VECTORBODYIMP,'Extract from file',
     5449                                'Extract rigid body from phase file')
     5450        G2G.Define_wxId('wxID_VECTORBODYSAV')
     5451        self.VectorRBEdit.Append(G2G.wxID_VECTORBODYSAV,'Save rigid body','Write a rigid body to a file')
     5452        G2G.Define_wxId('wxID_VECTORBODYRD')
     5453        self.VectorRBEdit.Append(G2G.wxID_VECTORBODYRD,'Read rigid body','Read a rigid body from a file')
     5454        G2G.Define_wxId('wxID_VECTORBODYEXTD')
     5455        self.VectorRBEdit.Append(G2G.wxID_VECTORBODYEXTD,'Add translation',
     5456                                'Add translation to existing rigid body')
    54395457        self.PostfillDataMenu()
    54405458
     
    83868404            if grid.IsCellEditControlEnabled(): # complete any grid edits in progress
    83878405                if GSASIIpath.GetConfigValue('debug'): print ('Completing grid edit in%s'%str(grid))
     8406                grid.SaveEditControlValue()
     8407                # not sure if the next two things do anything
    83888408                grid.HideCellEditControl()
    83898409                grid.DisableCellEditControl()
  • trunk/GSASIIlattice.py

    r4415 r4421  
    1919The "*A* tensor" terms are defined as
    2020:math:`A = (\\begin{matrix} G_{11} & G_{22} & G_{33} & 2G_{12} & 2G_{13} & 2G_{23}\\end{matrix})` and *A* can be used in this fashion:
    21 :math:`d^* = \sqrt {A_1 h^2 + A_2 k^2 + A_3 l^2 + A_4 hk + A_5 hl + A_6 kl}`, where
     21:math:`d^* = \sqrt {A_0 h^2 + A_1 k^2 + A_2 l^2 + A_3 hk + A_4 hl + A_5 kl}`, where
    2222*d* is the d-spacing, and :math:`d^*` is the reciprocal lattice spacing,
    23 :math:`Q = 2 \\pi d^* = 2 \\pi / d`
     23:math:`Q = 2 \\pi d^* = 2 \\pi / d`.
     24Note that GSAS-II variables ``p::Ai`` (``i``=0,1,...5) and ``p`` is a phase number are
     25used for the *Ai* values. See :func:`A2cell`, :func:`cell2A` for interconversion between A and
     26unit cell parameters; :func:`cell2Gmat` :func:`Gmat2cell` for G and cell parameters.
     27
     28When the hydrostatic/elastic strain coefficients (*Dij*, :math:`D_{ij}`) are used, they are added to the
     29*A* tensor terms (Ai, :math:`A_{i}`) so that A is redefined
     30:math:`A = (\\begin{matrix} A_{0} + D_{11} & A_{1} + D_{22} & A_{2} + D_{33} & A_{3} + 2D_{12} & A_{4} + 2D_{13} & A_{5} + 2D_{23}\\end{matrix})`. See :func:`cellDijFill`.
     31Note that GSAS-II variables ``p:h:Dij`` (``i``,``j``=1,2,3) and ``p`` is a phase number
     32and ``h`` a histogram number are used for the *Dij* values.
    2433'''
    2534########### SVN repository information ###################
  • trunk/GSASIImath.py

    r4415 r4421  
    935935
    936936def getAtomXYZ(atoms,cx):
    937     '''default doc string
    938    
    939     :param type name: description
    940    
    941     :returns: type name: description
    942    
     937    '''Create an array of fractional coordinates from the atoms list
     938   
     939    :param list atoms: atoms object as found in tree
     940    :param int cx: offset to where coordinates are found
     941   
     942    :returns: np.array with shape (n,3)   
    943943    '''
    944944    XYZ = []
  • trunk/GSASIIplot.py

    r4419 r4421  
    97039703        s = 1
    97049704        selected = rbData.get('Selection')
     9705        if len(XYZ) != len(rbData['rbTypes']): # H atoms have been removed
     9706            return
    97059707        for iat,atom in enumerate(XYZ):
    97069708            if selected:
  • trunk/GSASIIscriptable.py

    r4411 r4421  
    17871787
    17881788    :param list ImageReaderlist: list of Reader objects for images
    1789     :param object ImageReaderlist: list of Reader objects for images
    1790     :param imageRef: A reference to the desired image. Either the Image
    1791       tree name (str), the image's index (int) or
     1789    :param object proj: references a :class:`G2Project` project
     1790    :param imageRef: A reference to the desired image in the project.
     1791      Either the Image tree name (str), the image's index (int) or
    17921792      a image object (:class:`G2Image`)
    17931793
Note: See TracChangeset for help on using the changeset viewer.