Changeset 1138


Ignore:
Timestamp:
Nov 7, 2013 12:12:55 PM (8 years ago)
Author:
toby
Message:

major constraints revision

Location:
trunk
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/GSASII.py

    r1128 r1138  
    556556            Id = self.PatternTree.AppendItem(parent=self.root,
    557557                                             text='HKLF '+HistName)
    558             self.PatternTree.SetItemPyData(Id,[{'wtFactor':1.0,'Dummy':False},rd.RefDict])
     558            valuesdict = {
     559                'wtFactor':1.0,
     560                'Dummy':False,
     561                'ranId':ran.randint(0,sys.maxint),
     562                }
     563            self.PatternTree.SetItemPyData(Id,[valuesdict,rd.RefDict])
    559564            Sub = self.PatternTree.AppendItem(Id,text='Instrument Parameters')
    560565            self.PatternTree.SetItemPyData(Sub,rd.Parameters)
     
    980985            Tmin = min(rd.powderdata[0])
    981986            Tmax = max(rd.powderdata[0])
    982             self.PatternTree.SetItemPyData(Id,[{'wtFactor':1.0,'Dummy':False},rd.powderdata])
     987            valuesdict = {
     988                'wtFactor':1.0,
     989                'Dummy':False,
     990                'ranId':ran.randint(0,sys.maxint),
     991                }
     992            rd.Sample['ranId'] = valuesdict['ranId'] # this should be removed someday
     993            self.PatternTree.SetItemPyData(Id,[valuesdict,rd.powderdata])
    983994            self.PatternTree.SetItemPyData(
    984995                self.PatternTree.AppendItem(Id,text='Comments'),
     
    10931104        Id = self.PatternTree.AppendItem(parent=self.root,
    10941105                                         text='PWDR '+inp[0])
    1095         self.PatternTree.SetItemPyData(Id,[{'wtFactor':1.0,'Dummy':True},rd.powderdata])
     1106        valuesdict = {
     1107            'wtFactor':1.0,
     1108            'Dummy':True,
     1109            'ranId':ran.randint(0,sys.maxint),
     1110            }
     1111        self.PatternTree.SetItemPyData(Id,[valuesdict,rd.powderdata])
    10961112        self.PatternTree.SetItemPyData(
    10971113            self.PatternTree.AppendItem(Id,text='Comments'),
     
    17371753        def GetData(self):
    17381754            return self.data
    1739            
    1740     class ConstraintDialog(wx.Dialog):
    1741         '''Window to edit Constraint values
    1742         '''
    1743         def __init__(self,parent,title,text,data,separator='*'):
    1744             wx.Dialog.__init__(self,parent,-1,title,
    1745                 pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
    1746             self.data = data
    1747             panel = wx.Panel(self)
    1748             mainSizer = wx.BoxSizer(wx.VERTICAL)
    1749             topLabl = wx.StaticText(panel,-1,text)
    1750             mainSizer.Add((10,10),1)
    1751             mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
    1752             mainSizer.Add((10,10),1)
    1753             dataGridSizer = wx.FlexGridSizer(rows=len(data),cols=2,hgap=2,vgap=2)
    1754             for id,item in enumerate(self.data[:-1]):
    1755                 lbl = item[1]
    1756                 if lbl[-1] != '=': lbl += ' ' + separator + ' '
    1757                 name = wx.StaticText(panel,-1,lbl,size=wx.Size(200,20),
    1758                                      style=wx.ALIGN_RIGHT)
    1759                 scale = wx.TextCtrl(panel,id,'%.3f'%(item[0]),style=wx.TE_PROCESS_ENTER)
    1760                 scale.Bind(wx.EVT_TEXT_ENTER,self.OnScaleChange)
    1761                 scale.Bind(wx.EVT_KILL_FOCUS,self.OnScaleChange)
    1762                 dataGridSizer.Add(name,0,wx.LEFT,10)
    1763                 dataGridSizer.Add(scale,0,wx.RIGHT,10)
    1764             mainSizer.Add(dataGridSizer,0,wx.EXPAND)
    1765             OkBtn = wx.Button(panel,-1,"Ok")
    1766             OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
    1767             cancelBtn = wx.Button(panel,-1,"Cancel")
    1768             cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
    1769             btnSizer = wx.BoxSizer(wx.HORIZONTAL)
    1770             btnSizer.Add((20,20),1)
    1771             btnSizer.Add(OkBtn)
    1772             btnSizer.Add((20,20),1)
    1773             btnSizer.Add(cancelBtn)
    1774             btnSizer.Add((20,20),1)
    1775            
    1776             mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
    1777             panel.SetSizer(mainSizer)
    1778             panel.Fit()
    1779             self.Fit()
    1780             self.CenterOnParent()
    1781            
    1782         def OnNameChange(self,event):
    1783             self.data[-1] = self.name.GetValue()
    1784            
    1785         def OnScaleChange(self,event):
    1786             id = event.GetId()
    1787             value = self.FindWindowById(id).GetValue()
    1788             try:
    1789                 self.data[id][0] = float(value)
    1790                 self.FindWindowById(id).SetValue('%.3f'%(self.data[id][0]))
    1791             except ValueError:
    1792                 if value and '-' not in value[0]:
    1793                     print 'bad input - numbers only'
    1794                     self.FindWindowById(id).SetValue('0.000')
    1795            
    1796         def OnOk(self,event):
    1797             parent = self.GetParent()
    1798             parent.Raise()
    1799             self.EndModal(wx.ID_OK)             
    1800            
    1801         def OnCancel(self,event):
    1802             parent = self.GetParent()
    1803             parent.Raise()
    1804             self.EndModal(wx.ID_CANCEL)             
    1805            
    1806         def GetData(self):
    1807             return self.data
    1808            
     1755                       
    18091756    def OnPwdrSum(self,event):
    18101757        'Sum together powder data(?)'
     
    18861833                    if Id:
    18871834                        Sample = G2pdG.SetDefaultSample()
    1888                         self.PatternTree.SetItemPyData(Id,[{'wtFactor':1.0,'Dummy':False},[np.array(Xsum),np.array(Ysum),np.array(Wsum),
     1835                        valuesdict = {
     1836                            'wtFactor':1.0,
     1837                            'Dummy':False,
     1838                            'ranId':ran.randint(0,sys.maxint),
     1839                            }
     1840                        self.PatternTree.SetItemPyData(Id,[valuesdict,[np.array(Xsum),np.array(Ysum),np.array(Wsum),
    18891841                            np.array(YCsum),np.array(YBsum),np.array(YDsum)]])
    18901842                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)                   
     
    24572409        PWDRdata['Sample Parameters'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Sample Parameters'))
    24582410        PWDRdata['Reflection Lists'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Reflection Lists'))
    2459         if 'ranId' not in PWDRdata['Sample Parameters']:
    2460             PWDRdata['Sample Parameters']['ranId'] = ran.randint(0,sys.maxint)
    2461         PWDRdata['ranId'] = PWDRdata['Sample Parameters']['ranId']
     2411        if 'ranId' not in PWDRdata:  # patch, add a random Id
     2412            PWDRdata['ranId'] = ran.randint(0,sys.maxint)
     2413        if 'ranId' not in PWDRdata['Sample Parameters']:  # I hope this becomes obsolete at some point
     2414            PWDRdata['Sample Parameters']['ranId'] = PWDRdata['ranId']
    24622415        return PWDRdata
    24632416
     
    24832436       
    24842437    def GetPhaseData(self):
    2485         '''Returns a list of defined phases. Used only in GSASIIgrid
    2486         Note routine :meth:`GSASIIstruct.GetPhaseData` also exists.
     2438        '''Returns a dict with defined phases.
     2439        Note routine :func:`GSASIIstrIO.GetPhaseData` also exists to
     2440        get same info from GPX file.
    24872441        '''
    24882442        phaseData = {}
     
    24902444            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
    24912445        else:
    2492             print 'no phases to be refined'
    2493             return
     2446            print 'no phases found in GetPhaseData'
     2447            sub = None
    24942448        if sub:
    24952449            item, cookie = self.PatternTree.GetFirstChild(sub)
     
    25002454                    phaseData[phaseName]['ranId'] = ran.randint(0,sys.maxint)         
    25012455                item, cookie = self.PatternTree.GetNextChild(sub, cookie)
    2502         return phaseData               
     2456        return phaseData
     2457
     2458    def GetPhaseNames(self):
     2459        '''Returns a list of defined phases.
     2460        Note routine :func:`GSASIIstrIO.GetPhaseNames` also exists to
     2461        get same info from GPX file.
     2462        '''
     2463        phaseNames = []
     2464        if G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
     2465            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
     2466        else:
     2467            print 'no phases found in GetPhaseNames'
     2468            sub = None
     2469        if sub:
     2470            item, cookie = self.PatternTree.GetFirstChild(sub)
     2471            while item:
     2472                phase = self.PatternTree.GetItemText(item)
     2473                phaseNames.append(phase)
     2474                item, cookie = self.PatternTree.GetNextChild(sub, cookie)
     2475        return phaseNames
     2476   
     2477    def GetHistogramNames(self,hType):
     2478        """ Returns a list of histogram names found in the GSASII data tree
     2479        Note routine :func:`GSASIIstrIO.GetHistogramNames` also exists to
     2480        get same info from GPX file.
     2481       
     2482        :param str hType: list of histogram types
     2483        :return: list of histogram names
     2484       
     2485        """
     2486        HistogramNames = []
     2487        if self.PatternTree.GetCount():
     2488            item, cookie = self.PatternTree.GetFirstChild(self.root)
     2489            while item:
     2490                name = self.PatternTree.GetItemText(item)
     2491                if name[:4] in hType:
     2492                    HistogramNames.append(name)       
     2493                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)               
     2494
     2495        return HistogramNames
     2496
    25032497                   
    25042498    def GetUsedHistogramsAndPhasesfromTree(self):
    25052499        ''' Returns all histograms that are found in any phase
    2506         and any phase that uses a histogram
    2507         :returns: two dicts:
     2500        and any phase that uses a histogram.
     2501        This also assigns numbers to used phases and histograms by the
     2502        order they appear in the file.
     2503        Note routine :func:`GSASIIstrIO.GetUsedHistogramsAndPhasesfromTree` also exists to
     2504        get same info from GPX file.
     2505
     2506        :returns: (Histograms,Phases)
    25082507
    25092508            * Histograms = dictionary of histograms as {name:data,...}
    25102509            * Phases = dictionary of phases that use histograms
    25112510        '''
    2512         phaseData = self.GetPhaseData()
    2513         if not phaseData:
    2514             return {},{}
    25152511        Histograms = {}
    25162512        Phases = {}
     2513        phaseNames = self.GetPhaseNames()
     2514        phaseData = self.GetPhaseData()
     2515        histoList = self.GetHistogramNames(['PWDR','HKLF'])
     2516
    25172517        for phase in phaseData:
    25182518            Phase = phaseData[phase]
    25192519            if Phase['Histograms']:
    25202520                if phase not in Phases:
     2521                    pId = phaseNames.index(phase)
     2522                    Phase['pId'] = pId
    25212523                    Phases[phase] = Phase
    25222524                for hist in Phase['Histograms']:
    2523                     if hist not in Histograms:
     2525                    if 'Use' not in Phase['Histograms'][hist]:      #patch: add Use flag as True
     2526                        Phase['Histograms'][hist]['Use'] = True         
     2527                    if hist not in Histograms and Phase['Histograms'][hist]['Use']:
    25242528                        item = G2gd.GetPatternTreeItemId(self,self.root,hist)
    2525                         if 'PWDR' in hist[:4]:
    2526                             Histograms[hist] = self.GetPWDRdatafromTree(item)
    2527                         elif 'HKLF' in hist[:4]:
    2528                             Histograms[hist] = self.GetHKLFdatafromTree(item)
    2529                         #future restraint, etc. histograms here
     2529                        if item:
     2530                            if 'PWDR' in hist[:4]:
     2531                                Histograms[hist] = self.GetPWDRdatafromTree(item)
     2532                            elif 'HKLF' in hist[:4]:
     2533                                Histograms[hist] = self.GetHKLFdatafromTree(item)
     2534                            hId = histoList.index(hist)
     2535                            Histograms[hist]['hId'] = hId
     2536                        else: # would happen if a referenced histogram were renamed or deleted
     2537                            print('For phase "'+str(phase)+
     2538                                  '" unresolved reference to histogram "'+str(hist)+'"')
    25302539        return Histograms,Phases
    25312540       
  • trunk/GSASIIIO.py

    r1131 r1138  
    715715#   
    716716def ProjFileOpen(G2frame):
    717     'Read a GSAS-II project file'
     717    'Read a GSAS-II project file and load into the G2 data tree'
    718718    file = open(G2frame.GSASprojectfile,'rb')
    719719    print 'load from file: ',G2frame.GSASprojectfile
     
    731731            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text=datum[0])
    732732            if 'PWDR' in datum[0]:               
    733                 G2frame.PatternTree.SetItemPyData(Id,datum[1][:3])     #temp. trim off junk
     733                if 'ranId' not in datum[1][0]: # patch: add random Id if not present
     734                    datum[1][0]['ranId'] = ran.randint(0,sys.maxint)
     735                G2frame.PatternTree.SetItemPyData(Id,datum[1][:3])  #temp. trim off junk (patch?)
     736            elif datum[0].startswith('HKLF'):
     737                if 'ranId' not in datum[1][0]: # patch: add random Id if not present
     738                    datum[1][0]['ranId'] = ran.randint(0,sys.maxint)
     739                G2frame.PatternTree.SetItemPyData(Id,datum[1])
    734740            else:
    735741                G2frame.PatternTree.SetItemPyData(Id,datum[1])
     
    751757                    G2frame.imageDefault = Data               
    752758        file.close()
    753         print 'project load successful'
     759        print('project load successful')
    754760        G2frame.NewPlot = True
    755761    except:
     
    783789        finally:
    784790            wx.EndBusyCursor()
    785         print 'project save successful'
     791        print('project save successful')
    786792
    787793def SaveIntegration(G2frame,PickId,data):
     
    847853            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Index Peak List'),[])
    848854            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Unit Cells List'),[])
    849             G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Reflection Lists'),{})             
    850         G2frame.PatternTree.SetItemPyData(Id,[[''],[np.array(X),np.array(Y),np.array(W),np.zeros(N),np.zeros(N),np.zeros(N)]])
     855            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Reflection Lists'),{})
     856            valuesdict = {
     857                'wtFactor':1.0,
     858                'Dummy':False,
     859                'ranId':ran.randint(0,sys.maxint),
     860                }
     861        G2frame.PatternTree.SetItemPyData(
     862            Id,[valuesdict,
     863                [np.array(X),np.array(Y),np.array(W),np.zeros(N),np.zeros(N),np.zeros(N)]])
    851864    G2frame.PatternTree.SelectItem(Id)
    852865    G2frame.PatternTree.Expand(Id)
     
    19781991            # old GPX file from before pre-constraint varyList is saved
    19791992            print ' *** Old refinement: Please use Calculate/Refine to redo  ***'
    1980             raise Exception(' *** CIF creation aborted ***')
     1993            raise Exception(' *** Export aborted ***')
    19811994        else:
    19821995            varyList = list(varyList)
  • trunk/GSASIIconstrGUI.py

    r1077 r1138  
    1818import wx
    1919import wx.grid as wg
     20import wx.lib.scrolledpanel as wxscroll
    2021import time
    2122import random as ran
     
    3132import GSASIIgrid as G2gd
    3233import GSASIIplot as G2plt
     34import GSASIIobj as G2obj
    3335VERY_LIGHT_GREY = wx.Colour(235,235,235)
    3436
     
    9597        parent.Raise()
    9698        self.EndModal(wx.ID_CANCEL)
     99
     100class ConstraintDialog(wx.Dialog):
     101    '''Window to edit Constraint values
     102    '''
     103    def __init__(self,parent,title,text,data,separator='*',varname="",varyflag=False):
     104        wx.Dialog.__init__(self,parent,-1,'Edit '+title,
     105            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
     106        self.data = data[:]
     107        self.newvar = [varname,varyflag]
     108        panel = wx.Panel(self)
     109        mainSizer = wx.BoxSizer(wx.VERTICAL)
     110        topLabl = wx.StaticText(panel,-1,text)
     111        mainSizer.Add((10,10),1)
     112        mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
     113        mainSizer.Add((10,10),1)
     114        dataGridSizer = wx.FlexGridSizer(rows=len(data),cols=3,hgap=2,vgap=2)
     115        self.OkBtn = wx.Button(panel,wx.ID_OK)
     116        for id in range(len(self.data)):
     117            lbl1 = lbl = str(self.data[id][1])
     118            if lbl[-1] != '=': lbl1 = lbl + ' ' + separator + ' '
     119            name = wx.StaticText(panel,wx.ID_ANY,lbl1,
     120                                 style=wx.ALIGN_RIGHT)
     121            scale = G2gd.ValidatedTxtCtrl(panel,self.data[id],0,
     122                                          typeHint=float,
     123                                          OKcontrol=self.DisableOK)
     124            dataGridSizer.Add(name,0,wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL,5)
     125            dataGridSizer.Add(scale,0,wx.RIGHT,3)
     126            if ':' in lbl:
     127                dataGridSizer.Add(
     128                    wx.StaticText(panel,-1,G2obj.fmtVarDescr(lbl)),
     129                    0,wx.RIGHT|wx.ALIGN_CENTER_VERTICAL,3)
     130            else:
     131                dataGridSizer.Add((-1,-1))
     132        if title == 'New Variable':
     133            name = wx.StaticText(panel,wx.ID_ANY,"New variable's\nname (optional)",
     134                                 style=wx.ALIGN_CENTER)
     135            scale = G2gd.ValidatedTxtCtrl(panel,self.newvar,0,
     136                                          typeHint=str,notBlank=False)
     137            dataGridSizer.Add(name,0,wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL,5)
     138            dataGridSizer.Add(scale,0,wx.RIGHT|wx.ALIGN_CENTER_VERTICAL,3)
     139            self.refine = wx.CheckBox(panel,label='Refine?')
     140            self.refine.SetValue(self.newvar[1]==True)
     141            self.refine.Bind(wx.EVT_CHECKBOX, self.OnCheckBox)
     142            dataGridSizer.Add(self.refine,0,wx.RIGHT|wx.ALIGN_CENTER_VERTICAL,3)
     143           
     144        mainSizer.Add(dataGridSizer,0,wx.EXPAND)
     145        self.OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
     146        self.OkBtn.SetDefault()
     147        cancelBtn = wx.Button(panel,wx.ID_CANCEL)
     148        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
     149        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
     150        btnSizer.Add((20,20),1)
     151        btnSizer.Add(self.OkBtn)
     152        btnSizer.Add((20,20),1)
     153        btnSizer.Add(cancelBtn)
     154        btnSizer.Add((20,20),1)
     155
     156        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
     157        panel.SetSizer(mainSizer)
     158        panel.Fit()
     159        self.Fit()
     160        self.CenterOnParent()
     161       
     162    def DisableOK(self,setting):
     163        if setting:
     164            self.OkBtn.Enable()
     165        else:
     166            self.OkBtn.Disable()
     167
     168    def OnCheckBox(self,event):
     169        self.newvar[1] = self.refine.GetValue()
     170
     171    def OnOk(self,event):
     172        parent = self.GetParent()
     173        parent.Raise()
     174        self.EndModal(wx.ID_OK)             
     175
     176    def OnCancel(self,event):
     177        parent = self.GetParent()
     178        parent.Raise()
     179        self.EndModal(wx.ID_CANCEL)             
     180
     181    def GetData(self):
     182        return self.data
    97183       
    98184################################################################################
     
    108194    if 'Global' not in data:                                            #patch
    109195        data['Global'] = []
    110     Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree()
    111     rigidbodyDict = G2frame.PatternTree.GetItemPyData(   
     196    # DEBUG code ########################################
     197    #import GSASIIconstrGUI
     198    #reload(GSASIIconstrGUI)
     199    #reload(G2obj)
     200    #reload(G2stIO)
     201    #import GSASIIstrMain
     202    #reload(GSASIIstrMain)   
     203    #reload(G2mv)
     204    #reload(G2gd)
     205    ###################################################
     206    Histograms,Phases = G2obj.IndexAllIds(G2frame)
     207    ##################################################################################
     208    # patch: convert old-style (str) variables in constraints to G2VarObj objects
     209    for key,value in data.items():
     210        j = 0
     211        for cons in value:
     212            #print cons             # DEBUG
     213            for i in range(len(cons[:-3])):
     214                if type(cons[i][1]) is str:
     215                    cons[i][1] = G2obj.G2VarObj(cons[i][1])
     216                    j += 1
     217        if j:
     218            print str(key) + ': '+str(j)+' variable(s) strings converted to objects'
     219    ##################################################################################
     220    rigidbodyDict = G2frame.PatternTree.GetItemPyData(
    112221        G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
    113222    rbIds = rigidbodyDict.get('RBIds',{'Vector':[],'Residue':[]})
     
    152261    histList.sort()
    153262    Indx = {}
    154     scope = {}                          #filled out later
    155263    G2frame.Page = [0,'phs']
    156    
    157     def GetPHlegends(Phases,Histograms):
    158         plegend = '\n In p::name'
    159         hlegend = '\n In :h:name'
    160         phlegend = '\n In p:h:name'
    161         glegend = '\n In ::name'
    162         for phase in Phases:
    163             plegend += '\n p:: = '+str(Phases[phase]['pId'])+':: for '+phase
    164             count = 0
    165             for histogram in Phases[phase]['Histograms']:
    166                 if count < 3:
    167                     phlegend += '\n p:h: = '+str(Phases[phase]['pId'])+':'+str(Histograms[histogram]['hId'])+': for '+phase+' in '+histogram
    168                 else:
    169                     phlegend += '\n ... etc.'
    170                     break
    171                 count += 1
    172         count = 0
    173         for histogram in Histograms:
    174             if count < 3:
    175                 hlegend += '\n :h: = :'+str(Histograms[histogram]['hId'])+': for '+histogram
    176             else:
    177                 hlegend += '\n ... etc.'
    178                 break
    179             count += 1
    180         return plegend,hlegend,phlegend,glegend
    181264       
    182265    def FindEquivVarb(name,nameList):
     266        'Creates a list of variables appropriate to constrain with name'
    183267        outList = []
    184268        phlist = []
     
    205289            if keys[2] in namelist and item != name:
    206290                outList.append(item)
    207         if items[1]:
    208             for key in phlist:
    209                 outList.append(key+':all:'+items[2])
    210291        return outList
    211292       
    212293    def SelectVarbs(page,FrstVarb,varList,legend,constType):
    213         '''Select variables used in Constraints after one variable has
    214         been selected which determines the appropriate variables to be
    215         used here. Then creates the constraint and adds it to the
    216         constraints list.
    217         Called from OnAddEquivalence, OnAddFunction & OnAddConstraint
     294        '''Select variables used in constraints after one variable has
     295        been selected. This routine determines the appropriate variables to be
     296        used based on the one that has been selected and asks for more to be added.
     297
     298        It then creates the constraint and adds it to the constraints list.
     299       
     300        Called from OnAddEquivalence, OnAddFunction & OnAddConstraint (all but
     301        OnAddHold)
     302
     303        :param list page: defines calling page -- type of variables to be used
     304        :parm GSASIIobj.G2VarObj FrstVarb: reference to first selected variable
     305        :param list varList: list of other appropriate variables to select from
     306        :param str legend: header for selection dialog
     307        :param str constType: type of constraint to be generated
     308        :returns: a constraint, as defined in
     309          :ref:`GSASIIobj <Constraint_definitions_table>`
    218310        '''
    219         #future -  add 'all:all:name', '0:all:name', etc. to the varList
     311        atchoice = ["("+i+") "+G2obj.fmtVarDescr(i) for i in varList]
     312        meaning = G2obj.getDescr(FrstVarb.name)
     313        if not meaning:
     314            meaning = "(no definition found!)"
     315        l = str(FrstVarb).split(':')
     316        # make lists of phases & histograms to iterate over
     317        phaselist = [l[0]]
     318        if l[0]:
     319            phaselbl = ['phase #'+l[0]]
     320            if len(Phases) > 1:
     321                phaselist += ['all']
     322                phaselbl += ['all phases']
     323        else:
     324            phaselbl = ['']
     325        histlist = [l[1]]
     326        if l[1]:
     327            histlbl = ['histogram #'+l[1]]
     328            if len(Histograms) > 1:
     329                histlist += ['all']
     330                histlbl += ['all histograms']
     331                typ = Histograms[G2obj.LookupHistName(l[1])[0]]['Instrument Parameters'][0]['Type'][1]
     332                i = 0
     333                for hist in Histograms:
     334                    if Histograms[hist]['Instrument Parameters'][0]['Type'][1] == typ: i += 1
     335                if i > 1:
     336                    histlist += ['all='+typ]
     337                    histlbl += ['all '+typ+' histograms']
     338        else:
     339            histlbl = ['']
     340        # make a list of equivalent parameter names
     341        nameList = [FrstVarb.name]
     342        for var in varList:
     343            nam = var.split(":")[2]
     344            if nam not in nameList: nameList += [nam]
     345        # add "wild-card" names to the list of variables
    220346        if page[1] == 'phs':
    221             atchoice = [item+' for '+phaseAtNames[item] for item in varList]
    222             if 'RB' not in FrstVarb:
    223                 atchoice += [FrstVarb+' for all']
    224                 atchoice += [FrstVarb+' for all '+atype for atype in TypeList]
    225             dlg = wx.MultiChoiceDialog(G2frame,'Select more variables:'+legend,
    226                 'Constrain '+FrstVarb+' and...',atchoice)
     347            if 'RB' in FrstVarb.name:
     348                pass
     349            elif FrstVarb.atom is None:
     350                for nam in nameList:
     351                    for ph,plbl in zip(phaselist,phaselbl):
     352                        if plbl: plbl = 'For ' + plbl
     353                        var = ph+"::"+nam
     354                        if var == str(FrstVarb) or var in varList: continue
     355                        varList += [var]
     356                        atchoice += ['('+var+') '+plbl+": "+meaning]
     357            else:
     358                for nam in nameList:
     359                    for ph,plbl in zip(phaselist,phaselbl):
     360                        if plbl: plbl = ' in ' + plbl
     361                        for atype in ['']+TypeList:
     362                            if atype:
     363                                albl = "For "+atype+" atoms"
     364                                akey = "all="+atype                       
     365                            else:
     366                                albl = "For all atoms"
     367                                akey = "all"
     368                            var = ph+"::"+nam+":"+akey
     369                            if var == str(FrstVarb) or var in varList: continue
     370                            varList += [var]
     371                            atchoice += ['('+var+') '+albl+plbl+": "+meaning]
     372        elif page[1] == 'hap':
     373            for nam in nameList:
     374                for ph,plbl in zip(phaselist,phaselbl):
     375                    if plbl: plbl = 'For ' + plbl
     376                    for hst,hlbl in zip(histlist,histlbl):
     377                        if hlbl:
     378                            if plbl:
     379                                hlbl = ' in ' + hlbl
     380                            else:
     381                                hlbl = 'For ' + hlbl                               
     382                            var = ph+":"+hst+":"+nam
     383                            if var == str(FrstVarb) or var in varList: continue
     384                            varList += [var]
     385                            atchoice += ['('+var+') '+plbl+hlbl+": "+meaning]
     386        elif page[1] == 'hst':
     387            for nam in nameList:
     388                for hst,hlbl in zip(histlist,histlbl):
     389                    if hlbl:
     390                        hlbl = 'For ' + hlbl                               
     391                        var = ":"+hst+":"+nam
     392                        if var == str(FrstVarb) or var in varList: continue
     393                        varList += [var]
     394                        atchoice += ['('+var+') '+hlbl+": "+meaning]
     395        elif page[1] == 'glb':
     396            pass
    227397        else:
    228             dlg = wx.MultiChoiceDialog(G2frame,'Select more variables:'+legend,
    229                 'Constrain '+FrstVarb+' and...',varList)
    230         varbs = [FrstVarb,]
    231         if dlg.ShowModal() == wx.ID_OK:
    232             sel = dlg.GetSelections()
    233             try:
    234                 for x in sel:
    235                     if ':all:' in varList[x]:       #a histogram 'all' - supercedes any individual selection
    236                         varbs = [FrstVarb,]
    237                         items = varList[x].split(':')
    238                         for item in varList:
    239                             if items[0] == item.split(':')[0] and ':all:' not in item:
    240                                 varbs.append(item)
    241                         break
    242                     else:
    243                         varbs.append(varList[x])
    244             except IndexError:      # one of the 'all' chosen - supercedes any individual selection
    245                 varbs = [FrstVarb,]
    246                 Atypes = []
    247                 for x in sel:
    248                     item = atchoice[x]
    249                     if 'all' in item:
    250                         Atypes.append(item.split('all')[1].strip())
    251                 if '' in Atypes:
    252                     varbs += varList
     398            raise Exception, 'Unknown constraint page '+ page[1]                   
     399        if len(atchoice):
     400            dlg = wx.MultiChoiceDialog(
     401                G2frame.dataFrame,legend,
     402                'Constrain '+str(FrstVarb)+' with...',atchoice)
     403            dlg.SetSize((625,250))
     404            dlg.CenterOnParent()
     405            res = dlg.ShowModal()
     406            Selections = dlg.GetSelections()[:]
     407            dlg.Destroy()
     408            if res != wx.ID_OK: return []
     409            if len(Selections) == 0:
     410                dlg = wx.MessageDialog(
     411                    G2frame.dataFrame,
     412                    'No variables were selected to include with '+str(FrstVarb),
     413                    'No variables')
     414                dlg.CenterOnParent()
     415                dlg.ShowModal()
     416                dlg.Destroy()
     417                return []
     418        else:
     419            dlg = wx.MessageDialog(
     420                G2frame.dataFrame,
     421                'There are no appropriate variables to include with '+str(FrstVarb),
     422                'No variables')
     423            dlg.CenterOnParent()
     424            dlg.ShowModal()
     425            dlg.Destroy()
     426            return []
     427        # now process the variables provided by the user
     428        varbs = [str(FrstVarb),] # list of selected variables
     429        for sel in Selections:
     430            var = varList[sel]
     431            # phase(s) included
     432            l = var.split(':')
     433            if l[0] == "all":
     434                phlist = [str(Phases[phase]['pId']) for phase in Phases]
     435            else:
     436                phlist = [l[0]]
     437            # histogram(s) included
     438            if l[1] == "all":
     439                hstlist = [str(Histograms[hist]['hId']) for hist in Histograms]
     440            elif '=' in l[1]:
     441                htyp = l[1].split('=')[1]
     442                hstlist = [str(Histograms[hist]['hId']) for hist in Histograms if
     443                           Histograms[hist]['Instrument Parameters'][0]['Type'][1] == htyp]
     444            else:
     445                hstlist = [l[1]]
     446            if len(l) == 3:
     447                for ph in phlist:
     448                    for hst in hstlist:
     449                        var = ph + ":" + hst + ":" + l[2]
     450                        if var in varbs: continue
     451                        varbs.append(var)
     452            else: # constraints with atoms
     453                if l[3] == "all":
     454                    for ph in phlist:
     455                        key = G2obj.LookupPhaseName(l[0])[0]
     456                        for hst in hstlist: # should be blank
     457                            for iatm,at in enumerate(Phases[key]['Atoms']):
     458                                var = ph + ":" + hst + ":" + l[2] + ":" + str(iatm)
     459                                if var in varbs: continue
     460                                varbs.append(var)
     461                elif '=' in l[3]:
     462                    for ph in phlist:
     463                        key = G2obj.LookupPhaseName(l[0])[0]
     464                        cx,ct,cs,cia = Phases[key]['General']['AtomPtrs']
     465                        for hst in hstlist: # should be blank
     466                            atyp = l[3].split('=')[1]
     467                            for iatm,at in enumerate(Phases[key]['Atoms']):
     468                                if at[ct] != atyp: continue
     469                                var = ph + ":" + hst + ":" + l[2] + ":" + str(iatm)
     470                                if var in varbs: continue
     471                                varbs.append(var)
    253472                else:
    254                     for item in varList:
    255                         if phaseAtTypes[item] in Atypes:
    256                             varbs.append(item) 
    257         dlg.Destroy()
    258         if len(varbs) > 1:
     473                    for ph in phlist:
     474                        key = G2obj.LookupPhaseName(l[0])[0]
     475                        for hst in hstlist: # should be blank
     476                            var = ph + ":" + hst + ":" + l[2] + ":" + l[3]
     477                            if var in varbs: continue
     478                            varbs.append(var)
     479        if len(varbs) >= 1 or 'constraint' in constType:
     480            constr = [[1.0,FrstVarb]]
     481            for item in varbs[1:]:
     482                constr += [[1.0,G2obj.G2VarObj(item)]]
    259483            if 'equivalence' in constType:
    260                 constr = [[1.0,FrstVarb]]
    261                 for item in varbs[1:]:
    262                     constr += [[1.0,item]]
    263                 return [constr+[None,None,'e']]      # list of equivalent variables & mults
     484                return [constr+[None,None,'e']]
    264485            elif 'function' in constType:
    265                 constr = map(list,zip([1.0 for i in range(len(varbs))],varbs))
    266                 return [constr+[None,False,'f']]         #just one constraint
    267             else:       #'constraint'
    268                 constr = map(list,zip([1.0 for i in range(len(varbs))],varbs))
    269                 return [constr+[1.0,None,'c']]          #just one constraint - default sum to one
     486                return [constr+[None,False,'f']]
     487            elif 'constraint' in constType:
     488                return [constr+[1.0,None,'c']]
     489            else:
     490                raise Exception,'Unknown constraint type: '+str(constType)
     491        else:
     492            dlg = wx.MessageDialog(
     493                G2frame.dataFrame,
     494                'There are no selected variables to include with '+str(FrstVarb),
     495                'No variables')
     496            dlg.CenterOnParent()
     497            dlg.ShowModal()
     498            dlg.Destroy()
    270499        return []
    271500
     
    277506        Since the varylist is not available, no warning messages
    278507        should be generated.
    279         Returns True if constraint should be added
     508
     509        :returns: True if constraint should be added
    280510        '''
    281511        allcons = []
     
    303533        Since the varylist is not available, no warning messages
    304534        should be generated.
    305         Returns True if the edit should be retained
     535       
     536        :returns: True if the edit should be retained
    306537        '''
    307538        allcons = []
     
    322553        return True
    323554             
     555    def PageSelection(page):
     556        'Decode page reference'
     557        if page[1] == "phs":
     558            vartype = "phase"
     559            varList = phaseList
     560            constrDictEnt = 'Phase'
     561        elif page[1] == "hap":
     562            vartype = "Histogram*Phase"
     563            varList = hapList
     564            constrDictEnt = 'HAP'
     565        elif page[1] == "hst":
     566            vartype = "Histogram"
     567            varList = histList
     568            constrDictEnt = 'Hist'
     569        elif page[1] == "glb":
     570            vartype = "Global"
     571            varList = globalList
     572            constrDictEnt = 'Global'
     573        else:
     574            raise Exception,'Should not happen!'
     575        return vartype,varList,constrDictEnt
     576
    324577    def OnAddHold(event):
    325         '''add a Hold constraint'''
    326         for phase in Phases:
    327             Phase = Phases[phase]
    328             Atoms = Phase['Atoms']
    329         constr = []
     578        '''Create a new Hold constraint
     579
     580        Hold constraints allows the user to select one variable (the list of available
     581        variables depends on which tab is currently active).
     582        '''
    330583        page = G2frame.Page
    331         choice = scope[page[1]]
    332         if page[1] == 'phs':
    333             atchoice = [item+' for '+phaseAtNames[item] for item in choice[2]]
    334             dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],atchoice)
    335         else:   
    336             dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],choice[2])
     584        vartype,varList,constrDictEnt = PageSelection(page)
     585        title1 = "Hold "+vartype+" variable"
     586        if not varList:
     587            G2frame.ErrorDialog('No variables','There are no variables of type '+vartype,
     588                                parent=G2frame.dataFrame)
     589            return
     590        varListlbl = ["("+i+") "+G2obj.fmtVarDescr(i) for i in varList]
     591        legend = "Select variables to hold (Will not be varied, even if vary flag is set)"
     592        dlg = G2gd.G2MultiChoiceDialog(
     593            G2frame.dataFrame,
     594            legend,title1,varListlbl,toggle=False,size=(625,250))
     595        dlg.CenterOnParent()
    337596        if dlg.ShowModal() == wx.ID_OK:
    338             sel = dlg.GetSelection()
    339             FrstVarb = choice[2][sel]
    340             newcons = [[[0.0,FrstVarb],None,None,'h']]
    341             if CheckAddedConstraint(newcons):
    342                 data[choice[3]] += newcons
     597            for sel in dlg.GetSelections():
     598                Varb = varList[sel]
     599                VarObj = G2obj.G2VarObj(Varb)
     600                newcons = [[[0.0,VarObj],None,None,'h']]
     601                if CheckAddedConstraint(newcons):
     602                    data[constrDictEnt] += newcons
    343603        dlg.Destroy()
    344         choice[4]()
     604        OnPageChanged(None)
    345605       
    346606    def OnAddEquivalence(event):
    347607        '''add an Equivalence constraint'''
    348         constr = []
    349608        page = G2frame.Page
    350         choice = scope[page[1]]
    351         if page[1] == 'phs':
    352             atchoice = [item+' for '+phaseAtNames[item] for item in choice[2]]
    353             dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],atchoice)
    354         else:   
    355             dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],choice[2])
    356         if dlg.ShowModal() == wx.ID_OK:
    357             sel = dlg.GetSelection()
    358             FrstVarb = choice[2][sel]
    359             moreVarb = FindEquivVarb(FrstVarb,choice[2])
    360             newcons = SelectVarbs(page,FrstVarb,moreVarb,choice[1],'equivalence')
    361             if len(newcons) > 0:
    362                 if CheckAddedConstraint(newcons):
    363                     data[choice[3]] += newcons
    364         dlg.Destroy()
    365         choice[4]()
     609        vartype,varList,constrDictEnt = PageSelection(page)
     610        title1 = "Setup equivalent "+vartype+" variables"
     611        title2 = "Select additional "+vartype+" variable(s) to be equivalent with "
     612        if not varList:
     613            G2frame.ErrorDialog('No variables','There are no variables of type '+vartype,
     614                                parent=G2frame.dataFrame)
     615            return
     616        varListlbl = ["("+i+") "+G2obj.fmtVarDescr(i) for i in varList]
     617        legend = "Select variables to make equivalent (only one of the variables will be varied when all are set to be varied)"
     618        GetAddVars(page,title1,title2,varList,varListlbl,constrDictEnt,'equivalence')
    366619   
    367620    def OnAddFunction(event):
    368621        '''add a Function (new variable) constraint'''
    369         constr = []
    370622        page = G2frame.Page
    371         choice = scope[page[1]]
    372         if page[1] == 'phs':
    373             atchoice = [item+' for '+phaseAtNames[item] for item in choice[2]]
    374             dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],atchoice)
    375         else:   
    376             dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],choice[2])
    377         if dlg.ShowModal() == wx.ID_OK:
    378             sel = dlg.GetSelection()
    379             FrstVarb = choice[2][sel]
    380             moreVarb = FindEquivVarb(FrstVarb,choice[2])
    381             newcons = SelectVarbs(page,FrstVarb,moreVarb,choice[1],'function')
    382             if len(newcons) > 0:
    383                 if CheckAddedConstraint(newcons):
    384                     data[choice[3]] += newcons
    385         dlg.Destroy()
    386         choice[4]()
     623        vartype,varList,constrDictEnt = PageSelection(page)
     624        title1 = "Setup new variable based on "+vartype+" variables"
     625        title2 = "Include additional "+vartype+" variable(s) to be included with "
     626        if not varList:
     627            G2frame.ErrorDialog('No variables','There are no variables of type '+vartype,
     628                                parent=G2frame.dataFrame)
     629            return
     630        varListlbl = ["("+i+") "+G2obj.fmtVarDescr(i) for i in varList]
     631        legend = "Select variables to include in a new variable (the new variable will be varied when all included variables are varied)"
     632        GetAddVars(page,title1,title2,varList,varListlbl,constrDictEnt,'function')
    387633                       
    388634    def OnAddConstraint(event):
    389635        '''add a constraint equation to the constraints list'''
    390         constr = []
    391636        page = G2frame.Page
    392         choice = scope[page[1]]
    393         if page[1] == 'phs':
    394             atchoice = [item+' for '+phaseAtNames[item] for item in choice[2]]
    395             dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],atchoice)
    396         else:   
    397             dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],choice[2])
     637        vartype,varList,constrDictEnt = PageSelection(page)
     638        title1 = "Setup constraint on "+vartype+" variables"
     639        title2 = "Select additional "+vartype+" variable(s) to include in constraint with "
     640        if not varList:
     641            G2frame.ErrorDialog('No variables','There are no variables of type '+vartype,
     642                                parent=G2frame.dataFrame)
     643            return
     644        varListlbl = ["("+i+") "+G2obj.fmtVarDescr(i) for i in varList]
     645        legend = "Select variables to include in a constraint equation (the values will be constrainted to equal a specified constant)"
     646        GetAddVars(page,title1,title2,varList,varListlbl,constrDictEnt,'constraint')
     647
     648    def GetAddVars(page,title1,title2,varList,varListlbl,constrDictEnt,constType):
     649        '''Get the variables to be added for OnAddEquivalence, OnAddFunction,
     650        and OnAddConstraint. Then create and check the constraint.
     651        '''
     652        dlg = wx.SingleChoiceDialog(G2frame.dataFrame,'Select 1st variable:',title1,varListlbl)
     653        dlg.SetSize((625,250))
     654        dlg.CenterOnParent()
    398655        if dlg.ShowModal() == wx.ID_OK:
    399656            sel = dlg.GetSelection()
    400             FrstVarb = choice[2][sel]
    401             moreVarb = FindEquivVarb(FrstVarb,choice[2])
    402             newcons = SelectVarbs(page,FrstVarb,moreVarb,choice[1],'constraint')
     657            FrstVarb = varList[sel]
     658            VarObj = G2obj.G2VarObj(FrstVarb)
     659            moreVarb = FindEquivVarb(FrstVarb,varList)
     660            newcons = SelectVarbs(page,VarObj,moreVarb,title2+FrstVarb,constType)
    403661            if len(newcons) > 0:
    404662                if CheckAddedConstraint(newcons):
    405                     data[choice[3]] += newcons
     663                    data[constrDictEnt] += newcons
    406664        dlg.Destroy()
    407         choice[4]()
     665        OnPageChanged(None)
    408666                       
    409     def ConstSizer(name,pageDisplay):
    410         '''This creates a sizer displaying all of the constraints entered
     667    def MakeConstraintsSizer(name,pageDisplay):
     668        '''Creates a sizer displaying all of the constraints entered of
     669        the specified type.
     670
     671        :param str name: the type of constraints to be displayed ('HAP',
     672          'Hist', 'Phase', or 'Global')
     673        :param wx.Panel pageDisplay: parent panel for sizer
     674        :returns: wx.Sizer created by method
    411675        '''
    412         constSizer = wx.FlexGridSizer(1,4,0,0)
     676        constSizer = wx.FlexGridSizer(1,5,0,0)
    413677        maxlen = 70 # characters before wrapping a constraint
    414678        for Id,item in enumerate(data[name]):
     679            helptext = ""
    415680            eqString = ['',]
    416             if item[-1] == 'h':
    417                 constSizer.Add((5,5),0)              # blank space for edit button
    418                 typeString = ' FIXED   '
    419                 eqString[-1] = item[0][1]+'   '
    420             elif isinstance(item[-1],str):
     681            if item[-1] == 'h': # Hold on variable
     682                constSizer.Add((-1,-1),0)              # blank space for edit button
     683                typeString = 'FIXED'
     684                var = str(item[0][1])
     685                varMean = G2obj.fmtVarDescr(var)
     686                eqString[-1] =  var +'   '
     687                helptext = "Prevents variable:\n"+ var + " ("+ varMean + ")\nfrom being changed"
     688            elif isinstance(item[-1],str): # not true on original-style (2011?) constraints
    421689                constEdit = wx.Button(pageDisplay,-1,'Edit',style=wx.BU_EXACTFIT)
    422690                constEdit.Bind(wx.EVT_BUTTON,OnConstEdit)
    423                 constSizer.Add(constEdit)            # edit button
     691                constSizer.Add(constEdit,0,wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER,1)            # edit button
    424692                Indx[constEdit.GetId()] = [Id,name]
    425693                if item[-1] == 'f':
     694                    helptext = "A new variable is created from a linear combination of the following variables:"
    426695                    for term in item[:-3]:
     696                        var = str(term[1])
    427697                        if len(eqString[-1]) > maxlen:
    428698                            eqString.append(' ')
     
    434704                                eqString[-1] += ' - '
    435705                                m = abs(m)
    436                         eqString[-1] += '%.3f*%s '%(m,term[1])
    437                     typeString = ' NEWVAR  '
     706                        eqString[-1] += '%.3f*%s '%(m,var)
     707                        varMean = G2obj.fmtVarDescr(var)
     708                        helptext += "\n" + var + " ("+ varMean + ")"
     709                    typeString = 'NEWVAR'
    438710                    eqString[-1] += ' = New Variable   '
    439711                elif item[-1] == 'c':
     712                    helptext = "The following variables constrained to equal a constant:"
    440713                    for term in item[:-3]:
     714                        var = str(term[1])
    441715                        if len(eqString[-1]) > maxlen:
    442716                            eqString.append(' ')
     
    446720                            else:
    447721                                eqString[-1] += ' - '
    448                         eqString[-1] += '%.3f*%s '%(abs(term[0]),term[1])
    449                     typeString = ' CONSTR  '
     722                        eqString[-1] += '%.3f*%s '%(abs(term[0]),var)
     723                        varMean = G2obj.fmtVarDescr(var)
     724                        helptext += "\n" + var + " ("+ varMean + ")"
     725                    typeString = 'CONST'
    450726                    eqString[-1] += ' = %.3f'%(item[-3])+'  '
    451727                elif item[-1] == 'e':
     728                    helptext = "The following variables are set to be equivalent, noting multipliers:"
    452729                    for term in item[:-3]:
     730                        var = str(term[1])
    453731                        if term[0] == 0: term[0] = 1.0
    454732                        if len(eqString[-1]) > maxlen:
    455733                            eqString.append(' ')
    456734                        if eqString[-1] == '':
    457                             eqString[-1] += '%s '%(term[1])
     735                            eqString[-1] += var+' '
    458736                            first = term[0]
    459737                        else:
    460                             eqString[-1] += ' = %.3f*%s '%(first/term[0],term[1])
    461                     typeString = ' EQUIV   '
     738                            eqString[-1] += ' = %.3f*%s '%(first/term[0],var)
     739                        varMean = G2obj.fmtVarDescr(var)
     740                        helptext += "\n" + var + " ("+ varMean + ")"
     741                    typeString = 'EQUIV'
    462742                else:
    463743                    print 'Unexpected constraint',item
     744               
    464745            else:
    465746                print 'Removing old-style constraints'
     
    469750            constDel.Bind(wx.EVT_BUTTON,OnConstDel)
    470751            Indx[constDel.GetId()] = [Id,name]
    471             constSizer.Add(constDel)             # delete button
    472             constSizer.Add(wx.StaticText(pageDisplay,-1,typeString),0,wx.ALIGN_CENTER_VERTICAL)
    473             EqSizer = wx.BoxSizer(wx.VERTICAL)
    474             for s in eqString:
    475                 EqSizer.Add(wx.StaticText(pageDisplay,-1,s),0,wx.ALIGN_CENTER_VERTICAL)
    476             constSizer.Add(EqSizer,0,wx.ALIGN_CENTER_VERTICAL)
    477             # if item[-1] == 'f':
    478             #     constRef = wx.CheckBox(pageDisplay,-1,label=' Refine?')
    479             #     constRef.SetValue(item[-2])
    480             #     constRef.Bind(wx.EVT_CHECKBOX,OnConstRef)
    481             #     Indx[constRef.GetId()] = item
    482             #     constSizer.Add(constRef)
    483             # else:
    484             #     constSizer.Add((5,5),0)
     752            constSizer.Add(constDel,0,wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER,1)             # delete button
     753            if helptext:
     754                ch = G2gd.HelpButton(pageDisplay,helptext)
     755                constSizer.Add(ch,0,wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER,1)
     756            else:
     757                constSizer.Add((-1,-1))               
     758            constSizer.Add(wx.StaticText(pageDisplay,-1,typeString),0,wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER|wx.RIGHT|wx.LEFT,3)
     759            if len(eqString) > 1:
     760                Eq = wx.BoxSizer(wx.VERTICAL)
     761                for s in eqString:
     762                    Eq.Add(wx.StaticText(pageDisplay,-1,s),0,wx.ALIGN_CENTER_VERTICAL)
     763            else:
     764                Eq = wx.StaticText(pageDisplay,-1,eqString[0])
     765            constSizer.Add(Eq,1,wx.ALIGN_CENTER_VERTICAL)
    485766        return constSizer
    486767               
    487     # def OnConstRef(event):
    488     #     Obj = event.GetEventObject()
    489     #     Indx[Obj.GetId()][-2] = Obj.GetValue()
    490        
    491768    def OnConstDel(event):
     769        'Delete a constraint'
    492770        Obj = event.GetEventObject()
    493771        Id,name = Indx[Obj.GetId()]
     
    496774       
    497775    def OnConstEdit(event):
    498         '''Called to edit an individual contraint by the Edit button'''
     776        '''Called to edit an individual contraint in response to a
     777        click on its Edit button
     778        '''
    499779        Obj = event.GetEventObject()
    500780        Id,name = Indx[Obj.GetId()]
    501         sep = '*'
    502781        if data[name][Id][-1] == 'f':
    503             items = data[name][Id][:-3]+[[],]
     782            items = data[name][Id][:-3]
    504783            constType = 'New Variable'
     784            if data[name][Id][-3]:
     785                varname = data[name][Id][-3]
     786            else:
     787                varname = ""
    505788            lbl = 'Enter value for each term in constraint; sum = new variable'
     789            dlg = ConstraintDialog(G2frame.dataFrame,constType,lbl,items,
     790                                   varname=varname,varyflag=data[name][Id][-2])
    506791        elif data[name][Id][-1] == 'c':
    507792            items = data[name][Id][:-3]+[
    508                 [data[name][Id][-3],'fixed value ='],[]]
     793                [data[name][Id][-3],'fixed value =']]
    509794            constType = 'Constraint'
    510795            lbl = 'Edit value for each term in constant constraint sum'
     796            dlg = ConstraintDialog(G2frame.dataFrame,constType,lbl,items)
    511797        elif data[name][Id][-1] == 'e':
    512             items = data[name][Id][:-3]+[[],]
     798            items = data[name][Id][:-3]
    513799            constType = 'Equivalence'
    514800            lbl = 'The following terms are set to be equal:'
    515             sep = '/'
     801            dlg = ConstraintDialog(G2frame.dataFrame,constType,lbl,items,'/')
    516802        else:
    517803            return
    518         dlg = G2frame.ConstraintDialog(G2frame.dataFrame,constType,lbl,items,sep)
    519804        try:
     805            prev = data[name][Id][:]
    520806            if dlg.ShowModal() == wx.ID_OK:
    521                 prev = data[name][Id]
    522807                result = dlg.GetData()
     808                for i in range(len(data[name][Id][:-3])):
     809                    data[name][Id][i][0] = result[i][0]
    523810                if data[name][Id][-1] == 'c':
    524                     data[name][Id][:-3] = result[:-2]
    525                     data[name][Id][-3] = result[-2][0]
    526                 else:
    527                     data[name][Id][:-3] = result[:-1]
     811                    data[name][Id][-3] = str(result[-1][0])
     812                elif data[name][Id][-1] == 'f':
     813                    # process the variable name to put in global form (::var)
     814                    varname = str(dlg.newvar[0]).strip().replace(' ','_')
     815                    if varname.startswith('::'):
     816                        varname = varname[2:]
     817                    varname = varname.replace(':',';')
     818                    if varname:
     819                        data[name][Id][-3] = '::' + varname
     820                    else:
     821                        data[name][Id][-3] = ''
     822                    data[name][Id][-2] = dlg.newvar[1]
    528823                if not CheckChangedConstraint():
    529824                    data[name][Id] = prev
     
    534829            dlg.Destroy()           
    535830        OnPageChanged(None)                     
    536    
    537     def UpdateHAPConstr():
    538         '''Responds to press on Histogram/Phase Constraints tab,
    539         shows constraints in data window'''
    540         HAPConstr.DestroyChildren()
    541         HAPDisplay = wx.Panel(HAPConstr)
    542         HAPSizer = wx.BoxSizer(wx.VERTICAL)
    543         HAPSizer.Add((5,5),0)
    544         HAPSizer.Add(ConstSizer('HAP',HAPDisplay))
    545         HAPDisplay.SetSizer(HAPSizer,True)
    546         Size = HAPSizer.GetMinSize()
    547         Size[0] += 40
    548         Size[1] = max(Size[1],250) + 20
    549         HAPDisplay.SetSize(Size)
    550         # scroll bar not working, at least not on Mac
    551         HAPConstr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
    552         Size[1] = min(Size[1],250)
    553         G2frame.dataFrame.setSizePosLeft(Size)
    554        
    555     def UpdateHistConstr():
    556         '''Responds to press on Histogram Constraints tab,
    557         shows constraints in data window'''
    558         HistConstr.DestroyChildren()
    559         HistDisplay = wx.Panel(HistConstr)
    560         HistSizer = wx.BoxSizer(wx.VERTICAL)
    561         HistSizer.Add((5,5),0)       
    562         HistSizer.Add(ConstSizer('Hist',HistDisplay))
    563         HistDisplay.SetSizer(HistSizer,True)
    564         Size = HistSizer.GetMinSize()
    565         Size[0] += 40
    566         Size[1] = max(Size[1],250) + 20
    567         HistDisplay.SetSize(Size)
    568         HistConstr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
    569         Size[1] = min(Size[1],250)
    570         G2frame.dataFrame.setSizePosLeft(Size)
    571        
    572     def UpdatePhaseConstr():
    573         '''Responds to press on Phase Constraint tab,
    574         shows constraints in data window'''
    575         PhaseConstr.DestroyChildren()
    576         PhaseDisplay = wx.Panel(PhaseConstr)
    577         PhaseSizer = wx.BoxSizer(wx.VERTICAL)
    578         PhaseSizer.Add((5,5),0)       
    579         PhaseSizer.Add(ConstSizer('Phase',PhaseDisplay))
    580         PhaseDisplay.SetSizer(PhaseSizer,True)
    581         Size = PhaseSizer.GetMinSize()
    582         Size[0] += 40
    583         Size[1] = max(Size[1],250) + 20
    584         PhaseDisplay.SetSize(Size)
    585         PhaseConstr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
    586         Size[1] = min(Size[1],250)
    587         G2frame.dataFrame.setSizePosLeft(Size)
    588 
    589     def UpdateGlobalConstr():
    590         '''Responds to press on Global Constraint tab,
    591         shows constraints in data window'''
    592         GlobalConstr.DestroyChildren()
    593         GlobalDisplay = wx.Panel(GlobalConstr)
    594         GlobalSizer = wx.BoxSizer(wx.VERTICAL)
    595         GlobalSizer.Add((5,5),0)       
    596         GlobalSizer.Add(ConstSizer('Global',GlobalDisplay))
    597         GlobalDisplay.SetSizer(GlobalSizer,True)
    598         Size = GlobalSizer.GetMinSize()
    599         Size[0] += 40
    600         Size[1] = max(Size[1],250) + 20
    601         GlobalDisplay.SetSize(Size)
    602         GlobalConstr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
    603         Size[1] = min(Size[1],250)
    604         G2frame.dataFrame.setSizePosLeft(Size)
    605    
     831   
     832    def UpdateConstraintPanel(panel,typ):
     833        '''Update the contents of the selected Constraint
     834        notebook tab. Called in :func:`OnPageChanged`
     835        '''
     836        if panel.GetSizer(): panel.GetSizer().Clear(True) # N.B. don't use panel.DestroyChildren()
     837        # because it deletes scrollbars on Mac
     838        Siz = wx.BoxSizer(wx.VERTICAL)
     839        Siz.Add((5,5),0)
     840        Siz.Add(MakeConstraintsSizer(typ,panel))
     841        panel.SetSizer(Siz,True)
     842        G2frame.dataFrame.SetSize((500,250)) # set frame size here
     843        panel.SetAutoLayout(1)
     844        panel.SetupScrolling()
     845
    606846    def OnPageChanged(event):
     847        '''Called when a tab is pressed or when a "select tab" menu button is
     848        used (see RaisePage), or to refresh the current tab contents (event=None)
     849        '''
    607850        if event:       #page change event!
    608851            page = event.GetSelection()
    609         else:
     852        else: # called directly, get current page
    610853            page = G2frame.dataDisplay.GetSelection()
    611854        oldPage = G2frame.dataDisplay.ChangeSelection(page)
     
    613856        if text == 'Histogram/Phase constraints':
    614857            G2frame.Page = [page,'hap']
    615             UpdateHAPConstr()
     858            UpdateConstraintPanel(HAPConstr,'HAP')
    616859        elif text == 'Histogram constraints':
    617860            G2frame.Page = [page,'hst']
    618             UpdateHistConstr()
     861            UpdateConstraintPanel(HistConstr,'Hist')
    619862        elif text == 'Phase constraints':
    620863            G2frame.Page = [page,'phs']
    621             UpdatePhaseConstr()
     864            UpdateConstraintPanel(PhaseConstr,'Phase')
    622865        elif text == 'Global constraints':
    623866            G2frame.Page = [page,'glb']
    624             UpdateGlobalConstr()
    625            
     867            UpdateConstraintPanel(GlobalConstr,'Global')
     868
     869    def RaisePage(event):
     870        'Respond to a "select tab" menu button'
     871        try:
     872            i = (G2gd.wxID_CONSPHASE,
     873                 G2gd.wxID_CONSHAP,
     874                 G2gd.wxID_CONSHIST,
     875                 G2gd.wxID_CONSGLOBAL).index(event.GetId())
     876            G2frame.dataDisplay.SetSelection(i)
     877            OnPageChanged(None)
     878        except ValueError:
     879            print('Unexpected event in RaisePage')
    626880
    627881    def SetStatusLine(text):
    628882        Status.SetStatusText(text)                                     
    629883       
    630     plegend,hlegend,phlegend,glegend = GetPHlegends(Phases,Histograms)
    631     scope = {'hst':['Histogram contraints:',hlegend,histList,'Hist',UpdateHistConstr],
    632         'hap':['Histogram * Phase contraints:',phlegend,hapList,'HAP',UpdateHAPConstr],
    633         'phs':['Phase contraints:',plegend,phaseList,'Phase',UpdatePhaseConstr],
    634         'glb':['Global constraints:',glegend,globalList,'Global',UpdateGlobalConstr]}
    635884    if G2frame.dataDisplay:
    636885        G2frame.dataDisplay.Destroy()
     
    646895    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddEquivalence, id=G2gd.wxID_EQUIVADD)
    647896    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddHold, id=G2gd.wxID_HOLDADD)
    648     G2frame.dataDisplay = G2gd.GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
    649    
    650     PhaseConstr = wx.ScrolledWindow(G2frame.dataDisplay)
     897    # tab commands
     898    for id in (G2gd.wxID_CONSPHASE,
     899               G2gd.wxID_CONSHAP,
     900               G2gd.wxID_CONSHIST,
     901               G2gd.wxID_CONSGLOBAL):
     902        G2frame.dataFrame.Bind(wx.EVT_MENU, RaisePage,id=id)
     903
     904    G2frame.dataDisplay = G2gd.GSNoteBook(parent=G2frame.dataFrame)
     905    # note that order of pages is hard-coded in RaisePage
     906    wxstyle = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER
     907    PhaseConstr = wxscroll.ScrolledPanel(G2frame.dataDisplay, wx.ID_ANY,style=wxstyle)
    651908    G2frame.dataDisplay.AddPage(PhaseConstr,'Phase constraints')
    652     HAPConstr = wx.ScrolledWindow(G2frame.dataDisplay)
     909    HAPConstr = wxscroll.ScrolledPanel(G2frame.dataDisplay, wx.ID_ANY,style=wxstyle)
    653910    G2frame.dataDisplay.AddPage(HAPConstr,'Histogram/Phase constraints')
    654     HistConstr = wx.ScrolledWindow(G2frame.dataDisplay)
     911    HistConstr = wxscroll.ScrolledPanel(G2frame.dataDisplay, wx.ID_ANY,style=wxstyle)
    655912    G2frame.dataDisplay.AddPage(HistConstr,'Histogram constraints')
    656     GlobalConstr = wx.ScrolledWindow(G2frame.dataDisplay)
    657     G2frame.dataDisplay.AddPage(GlobalConstr,'Global constraints')   
    658     UpdatePhaseConstr()
    659 
     913    GlobalConstr = wxscroll.ScrolledPanel(G2frame.dataDisplay, wx.ID_ANY,style=wxstyle)
     914    G2frame.dataDisplay.AddPage(GlobalConstr,'Global constraints')
     915    OnPageChanged(None) # show initial page
    660916    G2frame.dataDisplay.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, OnPageChanged)
    661917    # validate all the constrants -- should not see any errors here normally
     
    8561112            while 'ATOM' not in txtStr[:6] and 'HETATM' not in txtStr[:6]:
    8571113                txtStr = text.readline()
    858                 print txtStr
     1114                #print txtStr
    8591115        items = txtStr.split()
    8601116        while len(items):
  • trunk/GSASIIgrid.py

    r1128 r1138  
    118118
    119119[ wxID_CONSTRAINTADD,wxID_EQUIVADD,wxID_HOLDADD,wxID_FUNCTADD,
    120 ] = [wx.NewId() for item in range(4)]
     120  wxID_CONSPHASE, wxID_CONSHIST, wxID_CONSHAP, wxID_CONSGLOBAL,
     121] = [wx.NewId() for item in range(8)]
    121122
    122123[ wxID_RESTRAINTADD, wxID_RESTSELPHASE,wxID_RESTDELETE, wxID_RESRCHANGEVAL,
     
    279280            else:
    280281                self.invalid = False
     282                self.Bind(wx.EVT_CHAR,self._GetStringValue)
    281283        elif val is None:
    282284            raise Exception,("ValidatedTxtCtrl error: value of "+str(key)+
     
    360362        elif self.OKcontrol and previousInvalid:
    361363            self.OKcontrol(True)
     364        # always store the result
     365        if self.CIFinput: # for CIF make results ASCII
     366            self.result[self.key] = val.encode('ascii','replace')
     367        else:
     368            self.result[self.key] = val
     369
     370    def _GetStringValue(self,event):
     371        '''Get string input and store.
     372        '''
     373        event.Skip() # process keystroke
     374        wx.CallAfter(self._SaveStringValue)
     375       
     376    def _SaveStringValue(self):
     377        val = self.GetValue().strip()
    362378        # always store the result
    363379        if self.CIFinput: # for CIF make results ASCII
     
    13211337    :param str header: Title to place on window frame
    13221338    :param list ChoiceList: a list of choices where one will be selected
     1339    :param bool toggle: If True (default) the toggle and select all buttons
     1340      are displayed
    13231341
    13241342    :param kw: optional keyword parameters for the wx.Dialog may
    1325       be included such as Size [which defaults to `(320,310)`] and
    1326       Style (which defaults to `wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.CENTRE| wx.OK | wx.CANCEL`);
     1343      be included such as size [which defaults to `(320,310)`] and
     1344      style (which defaults to `wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.CENTRE| wx.OK | wx.CANCEL`);
    13271345      note that `wx.OK` and `wx.CANCEL` controls
    13281346      the presence of the eponymous buttons in the dialog.
    13291347    :returns: the name of the created dialog 
    13301348    '''
    1331     def __init__(self,parent, title, header, ChoiceList, **kw):
     1349    def __init__(self,parent, title, header, ChoiceList, toggle=True, **kw):
    13321350        # process keyword parameters, notably Style
    13331351        options = {'size':(320,310), # default Frame keywords
     
    13551373        Sizer.Add((-1,10))
    13561374        # set/toggle buttons
    1357         bSizer = wx.BoxSizer(wx.VERTICAL)
    1358         setBut = wx.Button(self,wx.ID_ANY,'Set All')
    1359         setBut.Bind(wx.EVT_BUTTON,self._SetAll)
    1360         bSizer.Add(setBut,0,wx.ALIGN_CENTER)
    1361         bSizer.Add((-1,5))
    1362         togBut = wx.Button(self,wx.ID_ANY,'Toggle All')
    1363         togBut.Bind(wx.EVT_BUTTON,self._ToggleAll)
    1364         bSizer.Add(togBut,0,wx.ALIGN_CENTER)
    1365         Sizer.Add(bSizer,0,wx.LEFT,12)
     1375        if toggle:
     1376            bSizer = wx.BoxSizer(wx.VERTICAL)
     1377            setBut = wx.Button(self,wx.ID_ANY,'Set All')
     1378            setBut.Bind(wx.EVT_BUTTON,self._SetAll)
     1379            bSizer.Add(setBut,0,wx.ALIGN_CENTER)
     1380            bSizer.Add((-1,5))
     1381            togBut = wx.Button(self,wx.ID_ANY,'Toggle All')
     1382            togBut.Bind(wx.EVT_BUTTON,self._ToggleAll)
     1383            bSizer.Add(togBut,0,wx.ALIGN_CENTER)
     1384            Sizer.Add(bSizer,0,wx.LEFT,12)
    13661385        # OK/Cancel buttons
    13671386        btnsizer = wx.StdDialogButtonSizer()
     
    18521871
    18531872################################################################################
     1873class HelpButton(wx.Button):
     1874    '''Create a help button that displays help information.
     1875    The text is displayed in a modal message window.
     1876
     1877    TODO: it might be nice if it were non-modal: e.g. it stays around until
     1878    the parent is deleted or the user closes it, but this did not work for
     1879    me.
     1880
     1881    :param parent: the panel which will be the parent of the button
     1882    :param str msg: the help text to be displayed
     1883    '''
     1884    def __init__(self,parent,msg):
     1885        if sys.platform == "darwin":
     1886            wx.Button.__init__(self,parent,wx.ID_HELP)
     1887        else:
     1888            wx.Button.__init__(self,parent,wx.ID_ANY,'?',style=wx.BU_EXACTFIT)
     1889        self.Bind(wx.EVT_BUTTON,self._onPress)
     1890        self.msg=msg
     1891        self.parent = parent
     1892    def _onPress(self,event):
     1893        'Respond to a button press by displaying the requested text'
     1894        dlg = wx.MessageDialog(self.parent,self.msg,'Help info',wx.OK)
     1895        dlg.ShowModal()
     1896        dlg.Destroy()
     1897################################################################################
    18541898class MyHtmlPanel(wx.Panel):
    18551899    '''Defines a panel to display HTML help information, as an alternative to
     
    19882032        self.ConstraintMenu = wx.MenuBar()
    19892033        self.PrefillDataMenu(self.ConstraintMenu,helpType='Constraints')
     2034        self.ConstraintTab = wx.Menu(title='')
     2035        self.ConstraintMenu.Append(menu=self.ConstraintTab, title='Select tab')
     2036        for id,txt in (
     2037            (wxID_CONSPHASE,'Phase'),
     2038            (wxID_CONSHAP,'Histogram/Phase'),
     2039            (wxID_CONSHIST,'Histogram'),
     2040            (wxID_CONSGLOBAL,'Global')):
     2041            self.ConstraintTab.Append(
     2042                id=id, kind=wx.ITEM_NORMAL,text=txt,
     2043                help='Select '+txt+' constraint editing tab')
    19902044        self.ConstraintEdit = wx.Menu(title='')
    19912045        self.ConstraintMenu.Append(menu=self.ConstraintEdit, title='Edit')
     
    19982052        self.ConstraintEdit.Append(id=wxID_FUNCTADD, kind=wx.ITEM_NORMAL,text='Add New Var',
    19992053            help='Add variable composed of existing parameter')
     2054
     2055        # item = self.ConstraintEdit.Append(id=wx.ID_ANY,kind=wx.ITEM_NORMAL,text='Update GUI')
     2056        # def UpdateGSASIIconstrGUI(event):
     2057        #     import GSASIIconstrGUI
     2058        #     reload(GSASIIconstrGUI)
     2059        #     import GSASIIobj
     2060        #     reload(GSASIIobj)
     2061        # self.Bind(wx.EVT_MENU,UpdateGSASIIconstrGUI,id=item.GetId())
     2062
    20002063        self.PostfillDataMenu()
    20012064       
  • trunk/GSASIImapvars.py

    r1046 r1138  
    221221
    222222# prefix for parameter names
    223 paramPrefix = "::constr:"
     223paramPrefix = "::constr;"
    224224consNum = 0 # number of the next constraint to be created
    225225
     
    248248    :returns: two lists of lists:
    249249   
    250       * a list of grouped contraints where each constraint grouped containts a list of indices for constraint constrDict entries
     250      * a list of grouped contraints where each constraint grouped containts a list
     251        of indices for constraint constrDict entries
    251252      * a list containing lists of parameter names contained in each group
    252253     
     
    284285    :param list varyList: a list of parameters names that will be varied
    285286
    286     :param dict constrDict: a list of dicts defining relationships/constraints (as defined in :func:`GroupConstraints`)
    287 
    288     :param list fixedList: a list of values specifying a fixed value for each dict in constrDict. Values are
    289       either strings that can be converted to floats or None if the constraint defines a new parameter rather
     287    :param dict constrDict: a list of dicts defining relationships/constraints
     288      (as created in :func:`GSASIIstrIO.ProcessConstraints` and
     289      documented in :func:`GroupConstraints`)
     290
     291    :param list fixedList: a list of values specifying a fixed value for each
     292      dict in constrDict. Values are either strings that can be converted to
     293      floats or ``None`` if the constraint defines a new parameter rather
    290294      than a constant.
    291295
     
    491495    conflicts or inconsistencies in parameter/variable definitions.
    492496
    493     :param list groups: a list of grouped contraints where each constraint grouped containts a list of
    494       indices for constraint constrDict entries, created in :func:`GroupConstraints` (returned as 1st value)
    495 
    496     :param list parmlist: a list containing lists of parameter names contained in each group,
     497    :param list groups: a list of grouped contraints where each constraint
     498      grouped containts a list of indices for constraint constrDict entries,
    497499      created in :func:`GroupConstraints` (returned as 1st value)
    498500
    499     :param list varyList: a list of parameters names (strings of form ``<ph>:<hst>:<nam>``) that will be varied
     501    :param list parmlist: a list containing lists of parameter names
     502      contained in each group, created in :func:`GroupConstraints`
     503      (returned as 2nd value)
     504
     505    :param list varyList: a list of parameters names (strings of form
     506      ``<ph>:<hst>:<nam>``) that will be varied
    500507   
    501     :param dict constrDict: a list of dicts defining relationships/constraints (as defined in :func:`GroupConstraints`)
    502 
    503     :param list fixedList: a list of values specifying a fixed value for each dict in constrDict. Values are
    504       either strings that can be converted to floats, float values or None if the constraint defines a new
    505       parameter
     508    :param dict constrDict: a list of dicts defining relationships/constraints
     509      (as defined in :func:`GroupConstraints`)
     510
     511    :param list fixedList: a list of values specifying a fixed value for each
     512      dict in constrDict. Values are either strings that can be converted to
     513      floats, float values or None if the constraint defines a new parameter.
    506514     
    507     :param dict constrDict: a list of dicts defining relationships/constraints
     515    :param dict constrDict: a list of dicts defining relationships/constraints.
    508516
    509517    '''
     
    537545                if mv not in indepVarList: indepVarList.append(mv)
    538546                for v,m in zip(varlist,invmultarr):
    539                     #if len(s): s += '  & '
    540                     #s += str(v)
    541                     #if m != 1:
    542                     #    s += " / " + str(m[0])                       
    543547                    if m == 0: zeromult = True
    544548                    if v in varyList:
     
    551555                    else:
    552556                        depVarList.append(v)
    553                 #print str(mv) + ' is equivalent to parameter(s): '+s
    554557            if varied > 0 and varied != len(varlist)+1:
    555558                msg += "\nNot all variables refined in equivalence:\n\t"
     
    587590        msg += '\t'+ s + '\n'
    588591    equivVarList = list(set(indepVarList).union(set(depVarList)))
    589     #print 'equivVarList',equivVarList
    590 #    inboth = set(fixedVarList).intersection(set(equivVarList))
    591 #    if len(inboth) > 0:
    592 #        msg += "\nError! The following variables are used in both Equivalence and Fixed constraints:\n"
    593 #        s = ''
    594 #        for var in sorted(inboth):
    595 #            if s != "": s+= ", "
    596 #            s += str(var)
    597 #        msg += '\t'+ s + '\n'
    598 #
     592
    599593    # scan through parameters in each relationship. Are all varied? If only some are
    600594    # varied, create an error message.
     
    616610                    msg += '\nError: parameter '+var+" is Fixed and used in a constraint:\n\t"
    617611                    msg += _FormatConstraint(constrDict[rel],fixedList[rel])+"\n"
    618 #                if var in equivVarList:
    619 #                    msg += '\nError: parameter '+var+" is Equivalenced and used in a constraint:\n\t"
    620 #                    msg += _FormatConstraint(constrDict[rel],fixedList[rel])+"\n"
    621612            if varied > 0 and varied != len(constrDict[rel]):
    622613                msg += "\nNot all variables refined in constraint:\n\t"
     
    656647            varied = 0
    657648            notvaried = ''
    658             if len(group) > 0:
     649            if len(group) > 0: # get the original equation reference
    659650                rel = group.pop(0)
     651                if debug:
     652                    print rel
     653                    print fixedList[rel]
     654                    print constrDict[rel]
    660655                fixedval = fixedList[rel]
    661656                for var in constrDict[rel]:
     
    696691    if debug: # on debug, show what is parsed & generated, semi-readable
    697692        print 50*'-'
    698         for group,varlist,multarr,inv,mapvar in zip(groups,parmlist,arrayList,invarrayList,indParmList):
    699             print '\n*** relation(s) in group:',group,'\tvars in group:',varlist
    700             print 'new parameters:', mapvar
    701             print 'Input relationship matrix'
    702             print multarr[:len(group)]
    703             added = len(group) - len(varlist)
    704             if added < 0:
    705                 print 'added relationship rows'
    706                 print multarr[added:]
    707             print 'Inverse relationship matrix'
    708             print inv
     693        print VarRemapShow(varyList)
    709694
    710695def StoreEquivalence(independentVar,dependentList):
  • trunk/GSASIIobj.py

    r1129 r1138  
    2626Note that the contents of each dict item is a List where each element in the
    2727list is a :ref:`constraint definition objects <Constraint_definitions_table>`.
     28The constraints in this form are converted in
     29:func:`GSASIIstrIO.ProcessConstraints` to the form used in :mod:`GSASIImapvars`
    2830
    2931The keys in the Constraints dict are:
     
    5456   single: Data object descriptions; Constraint Definition
    5557
    56 Each constraint is defined as a list using a series of terms of form
    57 
    58 ::
    59 
    60 [[<mult1>, <var1>], [<mult2>, <var2>],..., <fixed val>, <vary flag>, <cons type>]
    61 
    62 Where the variable pair list item containing two values [<mult>, <var>],
     58Each constraint is defined as an item in a list. Each constraint is of form::
     59
     60[[<mult1>, <var1>], [<mult2>, <var2>],..., <fixedval>, <varyflag>, <constype>]
     61
     62Where the variable pair list item containing two values [<mult>, <var>], where:
    6363
    6464  * <mult> is a multiplier for the constraint (float)
    65   * <var> is the name of the variable (str) (or to be implemented a :class:`VarName` object.)
     65  * <var> a :class:`G2VarObj` object (previously a str variable name of form
     66      'p:h:name[:at]')
    6667
    6768Note that the last three items in the list play a special role:
    6869
    69  * <fixed val> is the fixed value for a constraint equation or is None
    70  * <vary flag> is True, False or None and is intended to use to indicate if new variables
     70 * <fixedval> is the fixed value for a `constant equation` (``constype=c``)
     71   constraint or is None. For a `New variable` (``constype=f``) constraint,
     72   a variable name can be specified as a str (but this is not yet used).
     73 * <varyflag> is True or False for `New variable` (``constype=f``) constraints
     74   or is None. This will be implemented in the future to indicate if these variables
    7175   should be refined.
    72  * <cons type> is one of four letters, 'e', 'c', 'h', 'f' that determines the type of constraint.
     76 * <constype> is one of four letters, 'e', 'c', 'h', 'f' that determines the type of constraint:
    7377
    7478    * 'e' defines a set of equivalent variables. Only the first variable is refined (if the
    7579      appropriate refine flag is set) and and all other equivalent variables in the list
    76       are generated from that variable. The vary flag for those variables is ignored.
    77     * 'c' defines a constraint equation of form, :math:`m_1 \\times var_1 + m_2 \\times var_2 + ... = c`
    78     * 'h' defines a variable to hold (not vary). Any variable on this list is not varied, even if its refinement
    79       flag is set. This is of particular value when needing to hold one or more variables in a set such as
     80      are generated from that variable, using the appropriate multipliers.
     81    * 'c' defines a constraint equation of form,
     82      :math:`m_1 \\times var_1 + m_2 \\times var_2 + ... = c`
     83    * 'h' defines a variable to hold (not vary). Any variable on this list is not varied,
     84      even if its refinement flag is set. Only one [mult,var] pair is allowed in a hold
     85      constraint and the mult value is ignored.
     86      This is of particular value when needing to hold one or more variables where a
     87      single flag controls a set of variables such as, coordinates,
    8088      the reciprocal metric tensor or anisotropic displacement parameter.
    81     * 'f' defines a relationship to define a new variable according to relationship
     89    * 'f' defines a new variable (function) according to relationship
    8290      :math:`newvar = m_1 \\times var_1 + m_2 \\times var_2 + ...`
    8391
     
    594602  key                      sub-key        explanation
    595603======================  ===============  ====================================================
    596 Data
    597                                           A dict that contains the
     604Data                          \           A dict that contains the
    598605                                          reflection table,
    599606                                          as described in the
     
    625632hId                           \           The number assigned to the histogram when
    626633                                          the project is loaded or edited (can change)
     634ranId                         \           A random number id for the histogram
     635                                          that does not change
    627636======================  ===============  ====================================================
    628637
     
    662671
    663672'''
     673import random as ran
     674import sys
    664675import GSASIIpath
     676import GSASIImath as G2mth
     677
    665678GSASIIpath.SetVersionNumber("$Revision$")
    666 
    667 def LoadHistogramIDs(histList,idList):
    668     '''Save the Id values for a series of histograms'''
    669     VarName.IDdict['hists'] = {}
    670     for h,i in zip(histList,idList):
    671         VarName.IDdict['hists'][i] = h
    672 
    673 def LoadPhaseIDs(self):
    674     pass
    675 
    676 class VarName(object):
    677     '''Defines a GSAS-II variable either using the phase/atom/histogram
    678     unique Id numbers or using a character string that specifies
    679     variables by phase/atom/histogram number (which can change).
    680     Note that :func:`LoadID` should be used to (re)load the current Ids
    681     before creating or later using the VarName object.
    682 
    683     A :class:`VarName` object can be created with a single parameter:
     679PhaseIdLookup = {}
     680'''dict listing phase name and random Id keyed by sequential phase index as a str;
     681best to access this using :func:`LookupPhaseName`
     682'''
     683PhaseRanIdLookup = {}
     684'''dict listing phase sequential index keyed by phase random Id;
     685best to access this using :func:`LookupPhaseId`
     686'''
     687HistIdLookup = {}
     688'''dict listing histogram name and random Id, keyed by sequential histogram index as a str;
     689best to access this using :func:`LookupHistName`
     690'''
     691HistRanIdLookup = {}
     692'''dict listing histogram sequential index keyed by histogram random Id;
     693best to access this using :func:`LookupHistId`
     694'''
     695AtomIdLookup = {}
     696'''dict listing for each phase index as a str, the atom label and atom random Id,
     697keyed by atom sequential index as a str;
     698best to access this using :func:`LookupAtomLabel`
     699'''
     700AtomRanIdLookup = {}
     701'''dict listing for each phase the atom sequential index keyed by atom random Id;
     702best to access this using :func:`LookupAtomId`
     703'''
     704ShortPhaseNames = {}
     705'''a dict containing a possibly shortened and when non-unique numbered
     706version of the phase name. Keyed by the phase sequential index.
     707'''
     708ShortHistNames = {}
     709'''a dict containing a possibly shortened and when non-unique numbered
     710version of the histogram name. Keyed by the histogram sequential index.
     711'''
     712
     713VarDesc = {}
     714''' This dictionary lists descriptions for GSAS-II variables,
     715as set in :func:`CompileVarDesc`. See that function for a description
     716for how keys and values are written.
     717'''
     718
     719reVarDesc = {}
     720''' This dictionary lists descriptions for GSAS-II variables with
     721the same values as :attr:`VarDesc` except that keys have been compiled as
     722regular expressions. Initialized in :func:`CompileVarDesc`.
     723'''
     724
     725def IndexAllIds(G2frame=None,Histograms=None,Phases=None):
     726    '''Scan through the used phases & histograms and create an index
     727    to the random numbers of phases, histograms and atoms. While doing this,
     728    confirm that assigned random numbers are unique -- just in case lightning
     729    strikes twice in the same place.
     730
     731    Note: this code assumes that the atom random Id (ranId) is the last
     732    element each atom record.
     733
     734    TODO: do we need a lookup for rigid body variables?
     735    '''
     736    if G2frame:
     737        Histograms,phaseDict = G2frame.GetUsedHistogramsAndPhasesfromTree()
     738    else:
     739        Histograms,phaseDict = Histograms,Phases
     740    # process phases and atoms
     741    PhaseIdLookup.clear()
     742    PhaseRanIdLookup.clear()   
     743    AtomIdLookup.clear()
     744    AtomRanIdLookup.clear()
     745    ShortPhaseNames.clear()
     746    for Phase in phaseDict:
     747        cx,ct,cs,cia = phaseDict[Phase]['General']['AtomPtrs']
     748        ranId = phaseDict[Phase]['ranId']
     749        while ranId in PhaseRanIdLookup:
     750            # Found duplicate random Id! note and reassign
     751            print ("\n\n*** Phase "+str(Phase)+" has repeated ranId. Fixing.\n")
     752            phaseDict[Phase]['ranId'] = ranId = ran.randint(0,sys.maxint)
     753        pId = str(phaseDict[Phase]['pId'])
     754        PhaseIdLookup[pId] = (Phase,ranId)
     755        PhaseRanIdLookup[ranId] = pId
     756        shortname = Phase[:10]
     757        while shortname in ShortPhaseNames.values():
     758            shortname = Phase[:8] + ' ('+ pId + ')'
     759        ShortPhaseNames[pId] = shortname
     760        AtomIdLookup[pId] = {}
     761        AtomRanIdLookup[pId] = {}
     762        for iatm,at in enumerate(phaseDict[Phase]['Atoms']):
     763            ranId = at[-1]
     764            while ranId in AtomRanIdLookup[pId]: # check for dups
     765                print ("\n\n*** Phase "+str(Phase)+" atom "+str(iatm)+" has repeated ranId. Fixing.\n")
     766                at[-1] = ranId = ran.randint(0,sys.maxint)
     767            AtomRanIdLookup[pId][ranId] = str(iatm)
     768            if phaseDict[Phase]['General']['Type'] == 'macromolecular':
     769                label = '%s_%s_%s_%s'%(at[ct-1],at[ct-3],at[ct-4],at[ct-2])
     770            else:
     771                label = at[ct-1]
     772            AtomIdLookup[pId][str(iatm)] = (label,ranId)
     773    # process histograms
     774    HistIdLookup.clear()
     775    HistRanIdLookup.clear()
     776    ShortHistNames.clear()
     777    for hist in Histograms:
     778        ranId = Histograms[hist]['ranId']
     779        while ranId in HistRanIdLookup:
     780            # Found duplicate random Id! note and reassign
     781            print ("\n\n*** Histogram "+str(hist)+" has repeated ranId. Fixing.\n")
     782            Histograms[hist]['ranId'] = ranId = ran.randint(0,sys.maxint)
     783        hId = str(Histograms[hist]['hId'])
     784        HistIdLookup[hId] = (hist,ranId)
     785        HistRanIdLookup[ranId] = hId
     786        shortname = hist[:15]
     787        while shortname in ShortHistNames.values():
     788            shortname = hist[:11] + ' ('+ hId + ')'
     789        ShortHistNames[hId] = shortname
     790
     791    return Histograms,phaseDict
     792
     793def LookupAtomId(pId,ranId):
     794    '''Get the atom number from a phase and atom random Id
     795
     796    :param int/str pId: the sequential number of the phase
     797    :param int ranId: the random Id assigned to an atom
     798
     799    :returns: the index number of the atom (str)
     800    '''
     801    if not AtomRanIdLookup:
     802        raise Exception,'Error: LookupAtomId called before IndexAllIds was run'
     803    if pId is None or pId == '':
     804        raise KeyError,'Error: phase is invalid (None or blank)'
     805    pId = str(pId)
     806    if pId not in AtomRanIdLookup:
     807        raise KeyError,'Error: LookupAtomId does not have phase '+pId
     808    if ranId not in AtomRanIdLookup[pId]:
     809        raise KeyError,'Error: LookupAtomId, ranId '+str(ranId)+' not in AtomRanIdLookup['+pId+']'
     810    return AtomRanIdLookup[pId][ranId]
     811
     812def LookupAtomLabel(pId,index):
     813    '''Get the atom label from a phase and atom index number
     814
     815    :param int/str pId: the sequential number of the phase
     816    :param int index: the index of the atom in the list of atoms
     817
     818    :returns: the label for the atom (str) and the random Id of the atom (int)
     819    '''
     820    if not AtomIdLookup:
     821        raise Exception,'Error: LookupAtomLabel called before IndexAllIds was run'
     822    if pId is None or pId == '':
     823        raise KeyError,'Error: phase is invalid (None or blank)'
     824    pId = str(pId)
     825    if pId not in AtomIdLookup:
     826        raise KeyError,'Error: LookupAtomLabel does not have phase '+pId
     827    if index not in AtomIdLookup[pId]:
     828        raise KeyError,'Error: LookupAtomLabel, ranId '+str(index)+' not in AtomRanIdLookup['+pId+']'
     829    return AtomIdLookup[pId][index]
     830
     831def LookupPhaseId(ranId):
     832    '''Get the phase number and name from a phase random Id
     833
     834    :param int ranId: the random Id assigned to a phase
     835    :returns: the sequential Id (pId) number for the phase (str)
     836    '''
     837    if not PhaseRanIdLookup:
     838        raise Exception,'Error: LookupPhaseId called before IndexAllIds was run'
     839    if ranId not in PhaseRanIdLookup:
     840        raise KeyError,'Error: LookupPhaseId does not have ranId '+str(ranId)
     841    return PhaseRanIdLookup[ranId]
     842
     843def LookupPhaseName(pId):
     844    '''Get the phase number and name from a phase Id
     845
     846    :param int/str pId: the sequential assigned to a phase
     847    :returns:  (phase,ranId) where phase is the name of the phase (str)
     848      and ranId is the random # id for the phase (int)
     849    '''
     850    if not PhaseIdLookup:
     851        raise Exception,'Error: LookupPhaseName called before IndexAllIds was run'
     852    if pId is None or pId == '':
     853        raise KeyError,'Error: phase is invalid (None or blank)'
     854    pId = str(pId)
     855    if pId not in PhaseIdLookup:
     856        raise KeyError,'Error: LookupPhaseName does not have index '+pId
     857    return PhaseIdLookup[pId]
     858
     859def LookupHistId(ranId):
     860    '''Get the histogram number and name from a histogram random Id
     861
     862    :param int ranId: the random Id assigned to a histogram
     863    :returns: the sequential Id (hId) number for the histogram (str)
     864    '''
     865    if not HistRanIdLookup:
     866        raise Exception,'Error: LookupHistId called before IndexAllIds was run'
     867    if ranId not in HistRanIdLookup:
     868        raise KeyError,'Error: LookupHistId does not have ranId '+str(ranId)
     869    return HistRanIdLookup[ranId]
     870
     871def LookupHistName(hId):
     872    '''Get the histogram number and name from a histogram Id
     873
     874    :param int/str hId: the sequential assigned to a histogram
     875    :returns:  (hist,ranId) where hist is the name of the histogram (str)
     876      and ranId is the random # id for the histogram (int)
     877    '''
     878    if not HistIdLookup:
     879        raise Exception,'Error: LookupHistName called before IndexAllIds was run'
     880    if hId is None or hId == '':
     881        raise KeyError,'Error: histogram is invalid (None or blank)'
     882    hId = str(hId)
     883    if hId not in HistIdLookup:
     884        raise KeyError,'Error: LookupHistName does not have index '+hId
     885    return HistIdLookup[hId]
     886
     887def fmtVarDescr(varname):
     888    '''Return a string with a more complete description for a GSAS-II variable
     889
     890    TODO: This will not handle rigid body parameters yet
     891
     892    :param str name: A full G2 variable name with 2 or 3
     893       colons (<p>:<h>:name[:<a>])
     894       
     895    :returns: a string with the description
     896    '''
    684897   
    685     :param str varname: a single value can be used to create a :class:`VarName`
    686       object. The string must be of form "p:h:var" or "p:h:var:a", where
    687 
    688      * p is the phase number (which may be left blank);
    689      * h is the histogram number (which may be left blank);
    690      * a is the atom number (which may be left blank in which case the third colon is omitted).
    691 
    692     Alternately, a :class:`VarName` object can be created with exactly four positional parameters:
    693 
    694     :param int phasenum: The number for the phase
    695     :param int histnum: The number for the histogram
    696     :param str varname: a single value can be used to create a :class:`VarName`
    697     :param int atomnum: The number for the atom
     898    l = getVarDescr(varname)
     899    if not l:
     900        return "invalid variable name ("+str(varname)+")!"
     901
     902    if not l[4]:
     903        l[4] = "(variable needs a definition!)"
     904
     905    s = ""
     906    if l[0] is not None and l[1] is not None: # HAP: keep short
     907        lbl = ShortPhaseNames.get(l[0],'? #'+str(l[0]))
     908        hlbl = ShortHistNames.get(l[1],'? #'+str(l[1]))
     909        if hlbl[:4] == 'HKLF':
     910            hlbl = 'Xtl='+hlbl[5:]
     911        elif hlbl[:4] == 'PWDR':
     912            hlbl = 'Pwd='+hlbl[5:]
     913        else:
     914            hlbl = 'Hist='+hlbl
     915        s = "Ph="+str(lbl)+" * "+str(hlbl)+": "
     916    elif l[3] is not None: # atom parameter,
     917        lbl = ShortPhaseNames.get(l[0],'phase?')
     918        try:
     919            albl = LookupAtomLabel(l[0],l[3])[0]
     920        except KeyError:
     921            albl = 'Atom?'
     922        s = "Atom "+str(albl)+" in "+str(lbl)+": "
     923    elif l[0] is not None:
     924        lbl = ShortPhaseNames.get(l[0],'phase?')
     925        s = "Phase "+str(lbl)+": "
     926    elif l[1] is not None:
     927        hlbl = ShortHistNames.get(l[1],'? #'+str(l[1]))
     928        if hlbl[:4] == 'HKLF':
     929            hlbl = 'Xtl='+hlbl[5:]
     930        elif hlbl[:4] == 'PWDR':
     931            hlbl = 'Pwd='+hlbl[5:]
     932        else:
     933            hlbl = 'Hist='+hlbl
     934        s = str(hlbl)+": "   
     935    if not s:
     936        s = 'Global: '
     937    s += l[4]
     938    return s
     939
     940def getVarDescr(varname):
     941    '''Return a short description for a GSAS-II variable
     942
     943    :param str name: A full G2 variable name with 2 or 3
     944       colons (<p>:<h>:name[:<a>])
     945     
     946    :returns: a five element list as [`p`,`h`,`name`,`a`,`description`],
     947      where `p`, `h`, `a` are str values or `None`, for the phase number,
     948      the histogram number and the atom number; `name` will always be
     949      an str; and `description` is str or `None`.
     950      If the variable name is incorrectly formed (for example, wrong
     951      number of colons), `None` is returned instead of a list.
     952    '''
     953    l = varname.split(':')
     954    if len(l) == 3:
     955        l += [None]
     956    if len(l) != 4:
     957        return None
     958    for i in (0,1,3):
     959        if l[i] == "":
     960            l[i] = None
     961    l += [getDescr(l[2])]
     962    return l
    698963   
     964def CompileVarDesc():
     965    '''Set the values in the variable description lookup table (:attr:`VarDesc`)
     966    into :attr:`reVarDesc`. This is called in :func:`getDescr` so the initialization
     967    is always done before use.
     968
     969    Note that keys may contain regular expressions, where '[xyz]'
     970    matches 'x' 'y' or 'z' (equivalently '[x-z]' describes this as range of values).
     971    '.*' matches any string. For example::
     972
     973    'AUiso':'Atomic isotropic displacement parameter',
     974
     975    will match variable ``'p::AUiso:a'``.
     976    If parentheses are used in the key, the contents of those parentheses can be
     977    used in the value, such as::
     978
     979    'AU([123][123])':'Atomic anisotropic displacement parameter U\\1',
     980
     981    will match ``AU11``, ``AU23``,.. and `U11`, `U23` etc will be displayed
     982    in the value when used.
     983   
    699984    '''
    700985    import re
    701     IDdict = {}
    702     IDdict['phases'] = {}
    703     IDdict['hists'] = {}
    704     IDdict['atoms'] = {}
    705     # This dictionary lists descriptions for GSAS-II variables.
    706     # Note that keys may contain regular expressions, where '[xyz]'
    707     # matches 'x' 'y' or 'z' (equivalently '[x-z]' describes this as range of values).
    708     # '.*' matches any string
    709     VarDesc = {
     986    if reVarDesc: return # already done
     987    for key,value in {
    710988        # Phase vars (p::<var>)
    711         'A[0-5]' : 'Reciprocal metric tensor component',
     989        'A([0-5])' : 'Reciprocal metric tensor component \\1',
    712990        'Vol' : 'Unit cell volume????',
    713991        # Atom vars (p::<var>:a)
    714         'dA[xyz]' : 'change to atomic position',
     992        'dA([xyz])' : 'change to atomic position \\1',
    715993        'AUiso':'Atomic isotropic displacement parameter',
    716         'AU[123][123]':'Atomic anisotropic displacement parameter',
    717         'AFrac': 'Atomic occupancy parameter',
     994        'AU([123][123])':'Atomic anisotropic displacement parameter U\\1',
     995        'Afrac': 'Atomic occupancy parameter',
    718996        # Hist & Phase (HAP) vars (p:h:<var>)
    719         'Bab[AU]': 'Babinet solvent scattering coef.',
    720         'D[123][123]' : 'Anisotropic strain coef.',
     997        'Bab([AU])': 'Babinet solvent scattering coef. \\1',
     998        'D([123][123])' : 'Anisotropic strain coef. \\1',
    721999        'Extinction' : 'Extinction coef.',
    7221000        'MD' : 'March-Dollase coef.',
     
    7271005        #Histogram vars (:h:<var>)
    7281006        'Absorption' : 'Absorption coef.',
    729         'Displace[XY]' : 'Debye-Scherrer sample displacement',
     1007        'Displace([XY])' : 'Debye-Scherrer sample displacement \\1',
    7301008        'Lam' : 'Wavelength',
    731         'Polariz' : 'Polarization correction',
     1009        'Polariz\.' : 'Polarization correction',
    7321010        'SH/L' : 'FCJ peak asymmetry correction',
    7331011        'Scale' : 'Histogram scale factor',
    734         '[UVW]' : 'Gaussian instrument broadening',
    735         '[XY]' : 'Cauchy instrument broadening',
     1012        '([UVW])' : 'Gaussian instrument broadening \\1',
     1013        '([XY])' : 'Cauchy instrument broadening \\1',
    7361014        'Zero' : 'Debye-Scherrer zero correction',
    7371015        'nDebye' : 'Debye model background corr. terms',
    738         'nPeaks' : 'Fixed peak  background corr. terms',
     1016        'nPeaks' : 'Fixed peak background corr. terms',
    7391017        # Global vars (::<var>)
    740         }
     1018        }.items():
     1019        VarDesc[key] = value
     1020        reVarDesc[re.compile(key)] = value
     1021
     1022def getDescr(name):
     1023    '''Return a short description for a GSAS-II variable
     1024
     1025    :param str name: The descriptive part of the variable name without colons (:)
     1026     
     1027    :returns: a short description or None if not found
     1028    '''
     1029
     1030    CompileVarDesc() # compile the regular expressions, if needed
     1031    for key in reVarDesc:
     1032        m = key.match(name)
     1033        if m:
     1034            return m.expand(reVarDesc[key])
     1035    return None
     1036
     1037def _lookup(dic,key):
     1038    '''Lookup a key in a dictionary, where None returns an empty string
     1039    but an unmatched key returns a question mark. Used in :class:`G2VarObj`
     1040    '''
     1041    if key is None:
     1042        return ""
     1043    else:
     1044        return dic.get(key,'?')
     1045
     1046class G2VarObj(object):
     1047    '''Defines a GSAS-II variable either using the phase/atom/histogram
     1048    unique Id numbers or using a character string that specifies
     1049    variables by phase/atom/histogram number (which can change).
     1050    Note that :func:`LoadID` should be used to (re)load the current Ids
     1051    before creating or later using the G2VarObj object.
     1052
     1053    A :class:`G2VarObj` object can be created with a single parameter:
     1054   
     1055    :param str varname: a single value can be used to create a :class:`G2VarObj`
     1056      object. The string must be of form "p:h:var" or "p:h:var:a", where
     1057
     1058     * p is the phase number (which may be left blank);
     1059     * h is the histogram number (which may be left blank);
     1060     * a is the atom number (which may be left blank in which case the third colon is omitted).
     1061
     1062    Alternately, a :class:`G2VarObj` object can be created with exactly four positional parameters:
     1063
     1064    :param str/int phasenum: The number for the phase
     1065    :param str/int histnum: The number for the histogram
     1066    :param str varname: a single value can be used to create a :class:`G2VarObj`
     1067    :param str/int atomnum: The number for the atom
     1068   
     1069    '''
     1070    IDdict = {}
     1071    IDdict['phases'] = {}
     1072    IDdict['hists'] = {}
     1073    IDdict['atoms'] = {}
    7411074    def __init__(self,*args):
    7421075        self.phase = None
     
    7461079        if len(args) == 1:
    7471080            lst = args[0].split(':')
    748             raise Exception, "Need to look up IDs"
    749             self.phase = lst[0]
    750             self.histogram = lst[1]
     1081            self.phase = PhaseIdLookup.get(lst[0],[None,None])[1]
     1082            self.histogram = HistIdLookup.get(lst[1],[None,None])[1]
    7511083            self.name = lst[2]
    7521084            if len(lst) > 3:
    753                 self.atom = lst[3]
     1085                self.atom = AtomIdLookup[lst[0]].get(lst[3],[None,None])[1]
    7541086        elif len(args) == 4:
    755             self.phase = args[0]
    756             self.histogram = args[1]
     1087            self.phase = PhaseIdLookup.get(str(args[0]),[None,None])[1]
     1088            self.histogram = HistIdLookup.get(str(args[1]),[None,None])[1]
    7571089            self.name = args[2]
    758             self.atom = args[3]
     1090            self.atom = AtomIdLookup[args[0]].get(str(args[3]),[None,None])[1]
    7591091        else:
    7601092            raise Exception,"Incorrectly called GSAS-II parameter name"
    7611093
     1094        #print "DEBUG: created ",self.phase,self.histogram,self.name,self.atom
     1095
    7621096    def __str__(self):
    763         return self.name()
    764 
    765     def name(self):
    766         '''Formats the GSAS-II variable name as a "traditional" string (p:h:<var>:a)
     1097        return self.varname()
     1098
     1099    def varname(self):
     1100        '''Formats the GSAS-II variable name as a "traditional" GSAS-II variable
     1101        string (p:h:<var>:a) or (p:h:<var>)
    7671102
    7681103        :returns: the variable name as a str
    7691104        '''
    770         def _fmt(val):
    771             if val is None:
    772                 return ""
    773             return str(val)
    774         return _fmt(self.phase) + ":" + _fmt(self.histogram) + _fmt(self.name) + _fmt(self.atom)
    775 
     1105        ph = _lookup(PhaseRanIdLookup,self.phase)
     1106        hist = _lookup(HistRanIdLookup,self.histogram)
     1107        s = (ph + ":" + hist + ":" +
     1108             str(self.name))
     1109        if self.atom:
     1110            if ph in AtomRanIdLookup:
     1111                s += ":" + AtomRanIdLookup[ph].get(self.atom,'?')
     1112            else:
     1113                s += ":?"
     1114        return s
     1115   
    7761116    def __repr__(self):
    7771117        '''Return the detailed contents of the object
    7781118        '''
    779         s = ""
    780         if self.phase:
    781             s += "Phase: " + str(self.phase) + "; "
    782 
    783         if self.histogram:
    784             s += "Histogram: " + str(self.histogram) + "; "
    785            
    786         if self.name:
    787             s += "Variable name: " + str(self.name) + "; "
    788 
    789         if self.atom:
    790             s += "Atom number: " + str(self.atom) + "; "
    791 
    792         return s+"("+self.name()+")"
    793 
    794     def getDescr(self):
    795         '''Return a short description for a GSAS-II variable
    796 
    797         :returns: a short description or 'no definition' if not found
    798         '''
    799         # iterating over uncompiled regular expressions is not terribly fast,
    800         # but this routine should not need to be all that speedy
    801         for key in self.VarDesc:
    802             if re.match(key, self.name):
    803                 return self.VarDesc[key]
    804         return 'no definition'
    805 
    806     def getDescr(self):
    807         '''Return a short description for a GSAS-II variable
    808 
    809         :returns: a short description or 'no definition' if not found
    810         '''
    811         # iterating over uncompiled regular expressions is not terribly fast,
    812         # but this routine should not need to be all that speedy
    813         for key in self.VarDesc:
    814             if re.match(key, self.name):
    815                 return self.VarDesc[key]
    816         return 'no definition'
    817 
    818     def fullDescr(self):
    819         '''Return a longer description for a GSAS-II variable
    820 
    821         :returns: a short description or 'no definition' if not found
    822         '''
    823         # iterating over uncompiled regular expressions is not terribly fast,
    824         # but this routine should not need to be all that speedy
    825         str = self.name()
    826        
    827         for key in self.VarDesc:
    828             if re.match(key, self.name):
    829                 return self.VarDesc[key]
    830         return 'no definition'
    831 
     1119        s = "<"
     1120        if self.phase is not None:
     1121            ph =  _lookup(PhaseRanIdLookup,self.phase)
     1122            s += "Phase: rId=" + str(self.phase) + " (#"+ ph + "); "
     1123        if self.histogram is not None:
     1124            hist = _lookup(HistRanIdLookup,self.histogram)
     1125            s += "Histogram: rId=" + str(self.histogram) + " (#"+ hist + "); "
     1126        if self.atom is not None:
     1127            s += "Atom rId=" + str(self.atom)
     1128            if ph in AtomRanIdLookup:
     1129                s += " (#" + AtomRanIdLookup[ph].get(self.atom,'?') + "); "
     1130            else:
     1131                s += " (#? -- no such phase!); "
     1132        s += 'Variable name="' + str(self.name) + '">'
     1133        return s+"("+self.varname()+")"
     1134
     1135    def __eq__(self, other):
     1136        if type(other) is type(self):
     1137            return (self.phase == other.phase and
     1138                    self.histogram == other.histogram and
     1139                    self.name == other.name and
     1140                    self.atom == other.atom)
     1141        return False
    8321142
    8331143    def _show(self):
  • trunk/GSASIIstrIO.py

    r1137 r1138  
    2929import GSASIIlattice as G2lat
    3030import GSASIIspc as G2spc
     31import GSASIIobj as G2obj
    3132import GSASIImapvars as G2mv
    3233import GSASIImath as G2mth
     
    7980    constDict,fixedList,ignored = ProcessConstraints(constList)
    8081    if ignored:
    81         print ignored,'old-style Constraints were rejected'
     82        print ignored,'Constraints were rejected. Was a constrained phase, histogram or atom deleted?'
    8283    return constDict,fixedList
    8384   
    8485def ProcessConstraints(constList):
    8586    """Interpret the constraints in the constList input into a dictionary, etc.
     87    All :class:`GSASIIobj.G2VarObj` objects are mapped to the appropriate
     88    phase/hist/atoms based on the object internals (random Ids). If this can't be
     89    done (if a phase has been deleted, etc.), the variable is ignored.
     90    If the constraint cannot be used due to too many dropped variables,
     91    it is counted as ignored.
    8692   
    8793    :param list constList: a list of lists where each item in the outer list
    88       specifies a constraint of some form. The last item in each inner list
    89       determines which of the four constraints types has been input:
    90 
    91         * h (hold): a single variable that will not be varied. It
    92           will be removed from the varyList later.
    93         * c (constraint): specifies a linear relationship that
    94           can be varied as a new grouped variable
    95           a fixed value.
    96         * f (fixed): specifies a linear relationship that is assigned
    97           a fixed value.
    98         * e (equivalence): specifies a series of variables where the
    99           first variable in the last can be used to generate the
    100           values for all the remaining variables.
     94      specifies a constraint of some form, as described in the :mod:`GSASIIobj`
     95      :ref:`Constraint definition <Constraint_definitions_table>`.
    10196
    10297    :returns:  a tuple of (constDict,fixedList,ignored) where:
    10398     
    104       * constDict (list) contains the constraint relationships
     99      * constDict (list of dicts) contains the constraint relationships
    105100      * fixedList (list) contains the fixed values for type
    106101        of constraint.
    107102      * ignored (int) counts the number of invalid constraint items
    108103        (should always be zero!)
    109 
    110104    """
    111105    constDict = []
     
    116110            # process a hold
    117111            fixedList.append('0')
    118             constDict.append({item[0][1]:0.0})
     112            var = str(item[0][1])
     113            if '?' not in var:
     114                constDict.append({var:0.0})
     115            else:
     116                ignored += 1
    119117        elif item[-1] == 'f':
    120118            # process a new variable
    121119            fixedList.append(None)
    122             constDict.append({})
     120            D = {}
     121            varyFlag = item[-2]
     122            name = item[-3]
    123123            for term in item[:-3]:
    124                 constDict[-1][term[1]] = term[0]
     124                var = str(term[1])
     125                if '?' not in var:
     126                    D[var] = term[0]
     127            if len(D) > 1:
     128                # add extra dict terms for input variable name and vary flag
     129                #if name is not None:
     130                #    D['_name'] = name
     131                #D['_vary'] = varyFlag == True # force to bool
     132                constDict.append(D)
     133            else:
     134                ignored += 1
    125135            #constFlag[-1] = ['Vary']
    126136        elif item[-1] == 'c':
    127137            # process a contraint relationship
    128             fixedList.append(str(item[-3]))
    129             constDict.append({})
     138            D = {}
    130139            for term in item[:-3]:
    131                 constDict[-1][term[1]] = term[0]
    132             #constFlag[-1] = ['VaryFree']
     140                var = str(term[1])
     141                if '?' not in var:
     142                    D[var] = term[0]
     143            if len(D) >= 1:
     144                fixedList.append(str(item[-3]))
     145                constDict.append(D)
     146            else:
     147                ignored += 1
    133148        elif item[-1] == 'e':
    134149            # process an equivalence
     
    137152            for term in item[:-3]:
    138153                if term[0] == 0: term[0] = 1.0
     154                var = str(term[1])
     155                if '?' in var: continue
    139156                if firstmult is None:
    140                     firstmult,firstvar = term
     157                    firstmult = term[0]
     158                    firstvar = var
    141159                else:
    142                     eqlist.append([term[1],firstmult/term[0]])
    143             G2mv.StoreEquivalence(firstvar,eqlist)
     160                    eqlist.append([var,firstmult/term[0]])
     161            if len(eqlist) > 0:
     162                G2mv.StoreEquivalence(firstvar,eqlist)
     163            else:
     164                ignored += 1
    144165        else:
    145166            ignored += 1
     
    156177    if not Histograms:
    157178        return 'Error: no diffraction data',''
     179    G2obj.IndexAllIds(Histograms=Histograms,Phases=Phases)
    158180    rigidbodyDict = GetRigidBodies(GPXfile)
    159181    rbIds = rigidbodyDict.get('RBIds',{'Vector':[],'Residue':[]})
     
    335357def GetUsedHistogramsAndPhases(GPXfile):
    336358    ''' Returns all histograms that are found in any phase
    337     and any phase that uses a histogram
     359    and any phase that uses a histogram. This also
     360    assigns numbers to used phases and histograms by the
     361    order they appear in the file.
    338362
    339363    :param str GPXfile: full .gpx file name
    340     :return: (Histograms,Phases)
     364    :returns: (Histograms,Phases)
    341365
    342366     * Histograms = dictionary of histograms as {name:data,...}
     
    363387                    Phase['Histograms'][hist]['Use'] = True         
    364388                if hist not in Histograms and Phase['Histograms'][hist]['Use']:
    365                     Histograms[hist] = allHistograms[hist]
    366                     hId = histoList.index(hist)
    367                     Histograms[hist]['hId'] = hId
     389                    try:
     390                        Histograms[hist] = allHistograms[hist]
     391                        hId = histoList.index(hist)
     392                        Histograms[hist]['hId'] = hId
     393                    except KeyError: # would happen if a referenced histogram were
     394                        # renamed or deleted
     395                        print('For phase "'+str(phase)+
     396                              '" unresolved reference to histogram "'+str(hist)+'"')
    368397    return Histograms,Phases
    369398   
  • trunk/GSASIIstrMain.py

    r1125 r1138  
    5858    calcControls = {}
    5959    calcControls.update(Controls)           
    60     constrDict,fixedList = G2stIO.GetConstraints(GPXfile)
     60    constrDict,fixedList = G2stIO.GetConstraints(GPXfile) # better to pass in Histograms,Phases
    6161    restraintDict = G2stIO.GetRestraints(GPXfile)
    6262    Histograms,Phases = G2stIO.GetUsedHistogramsAndPhases(GPXfile)
     63    G2obj.IndexAllIds(Histograms=Histograms,Phases=Phases)
    6364    if not Phases:
    6465        print ' *** ERROR - you have no phases! ***'
     
    9192    try:
    9293        groups,parmlist = G2mv.GroupConstraints(constrDict)
     94        #G2mv.debug = True # DEBUG
    9395        G2mv.GenerateConstraints(groups,parmlist,varyList,constrDict,fixedList)
     96        #G2mv.debug = False # DEBUG
    9497    except:
    9598        print ' *** ERROR - your constraints are internally inconsistent ***'
     
    98101        if warnmsg: print 'Warnings',warnmsg
    99102        raise Exception(' *** Refine aborted ***')
     103    #raise Exception(' *** Refine DEBUG ***') # DEBUG
    100104    # # check to see which generated parameters are fully varied
    101105    # msg = G2mv.SetVaryFlags(varyList)
Note: See TracChangeset for help on using the changeset viewer.