source: trunk/GSASII.py @ 1594

Last change on this file since 1594 was 1594, checked in by vondreele, 7 years ago

begin Pawley refinement stuff for incommensurate structures
Pawley SS reflections done
start on Refine for SS
only allow (3+1) supersymmetry - remove all (3+2) & (3+3) stuff
fix more bugs...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 170.4 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#GSASII
4########### SVN repository information ###################
5# $Date: 2014-12-03 22:33:28 +0000 (Wed, 03 Dec 2014) $
6# $Author: vondreele $
7# $Revision: 1594 $
8# $URL: trunk/GSASII.py $
9# $Id: GSASII.py 1594 2014-12-03 22:33:28Z vondreele $
10########### SVN repository information ###################
11'''
12*GSAS-II Main Module*
13=====================
14
15Main routines for the GSAS-II program
16'''
17
18import os
19import sys
20import math
21import copy
22import random as ran
23import time
24import copy
25import glob
26import imp
27import inspect
28import numpy as np
29import scipy as sp
30import wx
31import matplotlib as mpl
32try:
33    import OpenGL as ogl
34except ImportError:
35    print('*******************************************************')
36    print('PyOpenGL is missing from your python installation')
37    print('     - we will try to install it')
38    print('*******************************************************')
39    def install_with_easyinstall(package):
40        try: 
41            print "trying a system-wide PyOpenGl install"
42            easy_install.main(['-f',os.path.split(__file__)[0],package])
43            return
44        except:
45            pass
46        try: 
47            print "trying a user level PyOpenGl install"
48            easy_install.main(['-f',os.path.split(__file__)[0],'--user',package])
49            return
50        except:
51            print "Install of '+package+' failed. Please report this information:"
52            import traceback
53            print traceback.format_exc()
54            sys.exit()
55    from setuptools.command import easy_install
56    install_with_easyinstall('PyOpenGl')
57    print('*******************************************************')         
58    print('OpenGL has been installed. Restarting GSAS-II')
59    print('*******************************************************')         
60    loc = os.path.dirname(__file__)
61    import subprocess
62    subprocess.Popen([sys.executable,os.path.join(loc,'GSASII.py')])
63    sys.exit()
64   
65# load the GSAS routines
66import GSASIIpath
67GSASIIpath.SetVersionNumber("$Revision: 1594 $")
68import GSASIIIO as G2IO
69import GSASIIgrid as G2gd
70import GSASIIplot as G2plt
71import GSASIIpwd as G2pwd
72import GSASIIpwdGUI as G2pdG
73import GSASIIspc as G2spc
74import GSASIIstrMain as G2stMn
75import GSASIIstrIO as G2stIO
76import GSASIImapvars as G2mv
77import GSASIIobj as G2obj
78import GSASIIlattice as G2lat
79import GSASIIlog as log
80
81#wx inspector - use as needed
82wxInspector = False
83
84__version__ = '0.2.0'
85G2gd.__version__ = __version__
86
87# PATCH: for Mavericks (OS X 10.9.x), wx produces an annoying warning about LucidaGrandeUI.
88# In case stderr has been suppressed there, redirect python error output to stdout. Nobody
89# else should care much about this.
90sys.stderr = sys.stdout
91
92def create(parent):
93    return GSASII(parent)
94
95def SetDefaultDData(dType,histoName,NShkl=0,NDij=0):
96    if dType in ['SXC','SNC']:
97        return {'Histogram':histoName,'Show':False,'Scale':[1.0,True],
98            'Babinet':{'BabA':[0.0,False],'BabU':[0.0,False]},
99            'Extinction':['Lorentzian','None', {'Tbar':0.1,'Cos2TM':0.955,
100            'Eg':[1.e-10,False],'Es':[1.e-10,False],'Ep':[1.e-10,False]}]}
101    elif dType == 'SNT':
102        return {'Histogram':histoName,'Show':False,'Scale':[1.0,True],
103            'Babinet':{'BabA':[0.0,False],'BabU':[0.0,False]},
104            'Extinction':['Lorentzian','None', {
105            'Eg':[1.e-10,False],'Es':[1.e-10,False],'Ep':[1.e-10,False]}]}
106    elif 'P' in dType:
107        return {'Histogram':histoName,'Show':False,'Scale':[1.0,False],
108            'Pref.Ori.':['MD',1.0,False,[0,0,1],0,{}],
109            'Size':['isotropic',[1.,1.,1.],[False,False,False],[0,0,1],
110                [1.,1.,1.,0.,0.,0.],6*[False,]],
111            'Mustrain':['isotropic',[1000.0,1000.0,1.0],[False,False,False],[0,0,1],
112                NShkl*[0.01,],NShkl*[False,]],
113            'HStrain':[NDij*[0.0,],NDij*[False,]],                         
114            'Extinction':[0.0,False],'Babinet':{'BabA':[0.0,False],'BabU':[0.0,False]}}
115
116class GSASII(wx.Frame):
117    '''Define the main GSAS-II frame and its associated menu items
118    '''
119    def MenuBinding(self,event):
120        '''Called when a menu is clicked upon; looks up the binding in table
121        '''
122        log.InvokeMenuCommand(event.GetId(),self,event)
123           
124    def Bind(self,eventtype,handler,*args,**kwargs):
125        '''Override the Bind function so that we can wrap calls that will be logged.
126       
127        N.B. This is a bit kludgy. Menu bindings with an id are wrapped and
128        menu bindings with an object and no id are not.
129        '''
130        if eventtype == wx.EVT_MENU and 'id' in kwargs:
131            menulabels = log.SaveMenuCommand(kwargs['id'],self,handler)
132            if menulabels:
133                wx.Frame.Bind(self,eventtype,self.MenuBinding,*args,**kwargs)
134                return
135        wx.Frame.Bind(self,eventtype,handler,*args,**kwargs)     
136   
137    def _Add_FileMenuItems(self, parent):
138        item = parent.Append(
139            help='Open a GSAS-II project file (*.gpx)', id=wx.ID_ANY,
140            kind=wx.ITEM_NORMAL,text='&Open project...')
141        self.Bind(wx.EVT_MENU, self.OnFileOpen, id=item.GetId())
142        item = parent.Append(
143            help='Save project under current name', id=wx.ID_ANY,
144            kind=wx.ITEM_NORMAL,text='&Save project')
145        self.Bind(wx.EVT_MENU, self.OnFileSave, id=item.GetId())
146        item = parent.Append(
147            help='Save current project to new file', id=wx.ID_ANY,
148            kind=wx.ITEM_NORMAL,text='Save project as...')
149        self.Bind(wx.EVT_MENU, self.OnFileSaveas, id=item.GetId())
150        item = parent.Append(
151            help='Create empty new project, saving current is optional', id=wx.ID_ANY,
152            kind=wx.ITEM_NORMAL,text='&New project')
153        self.Bind(wx.EVT_MENU, self.OnFileClose, id=item.GetId())
154        item = parent.Append(
155            help='Exit from GSAS-II', id=wx.ID_ANY,
156            kind=wx.ITEM_NORMAL,text='&Exit')
157        self.Bind(wx.EVT_MENU, self.OnFileExit, id=item.GetId())
158       
159    def _Add_DataMenuItems(self,parent):
160        item = parent.Append(
161            help='',id=wx.ID_ANY,
162            kind=wx.ITEM_NORMAL,
163            text='Read image data...')
164        self.Bind(wx.EVT_MENU, self.OnImageRead, id=item.GetId())
165        item = parent.Append(
166            help='',id=wx.ID_ANY,
167            kind=wx.ITEM_NORMAL,
168            text='Read Powder Pattern Peaks...')
169        self.Bind(wx.EVT_MENU, self.OnReadPowderPeaks, id=item.GetId())
170        item = parent.Append(
171            help='',id=wx.ID_ANY,
172            kind=wx.ITEM_NORMAL,
173            text='Sum powder data')
174        self.Bind(wx.EVT_MENU, self.OnPwdrSum, id=item.GetId())
175        item = parent.Append(
176            help='',id=wx.ID_ANY,
177            kind=wx.ITEM_NORMAL,
178            text='Sum image data')
179        self.Bind(wx.EVT_MENU, self.OnImageSum, id=item.GetId())
180        item = parent.Append(
181            help='',id=wx.ID_ANY,
182            kind=wx.ITEM_NORMAL,
183            text='Add phase')
184        self.Bind(wx.EVT_MENU, self.OnAddPhase, id=item.GetId())
185        item = parent.Append(
186            help='',id=wx.ID_ANY,
187            kind=wx.ITEM_NORMAL,
188            text='Delete phase')
189        self.Bind(wx.EVT_MENU, self.OnDeletePhase, id=item.GetId())
190        item = parent.Append(
191            help='',id=wx.ID_ANY,
192            kind=wx.ITEM_NORMAL,
193            text='Rename data') 
194        self.Bind(wx.EVT_MENU, self.OnRenameData, id=item.GetId())
195        item = parent.Append(
196            help='',id=wx.ID_ANY,
197            kind=wx.ITEM_NORMAL,
198            text='Delete data')
199        self.Bind(wx.EVT_MENU, self.OnDataDelete, id=item.GetId())
200               
201    def _Add_CalculateMenuItems(self,parent):
202        item = parent.Append(help='Make new PDFs from selected powder patterns', 
203            id=wx.ID_ANY, kind=wx.ITEM_NORMAL,text='Make new PDFs')
204        self.MakePDF.append(item)
205#        item.Enable(False)
206        self.Bind(wx.EVT_MENU, self.OnMakePDFs, id=item.GetId())
207       
208        item = parent.Append(help='View least squares parameters', 
209            id=wx.ID_ANY, kind=wx.ITEM_NORMAL,text='&View LS parms')
210        self.Bind(wx.EVT_MENU, self.ShowLSParms, id=item.GetId())
211       
212        item = parent.Append(help='', id=wx.ID_ANY, kind=wx.ITEM_NORMAL,
213            text='&Refine')
214        if len(self.Refine): # extend state for new menus to match main (on mac)
215            state = self.Refine[0].IsEnabled()
216        else:
217            state = False
218        item.Enable(state)
219        self.Refine.append(item)
220        self.Bind(wx.EVT_MENU, self.OnRefine, id=item.GetId())
221       
222        item = parent.Append(help='', id=wx.ID_ANY, kind=wx.ITEM_NORMAL,
223            text='Sequential refine')
224        if len(self.SeqRefine): # extend state for new menus to match main (on mac)
225            state = self.SeqRefine[0].IsEnabled()
226        else:
227            state = False
228        item.Enable(state)
229        self.SeqRefine.append(item) # save menu obj for use in self.EnableSeqRefineMenu
230        self.Bind(wx.EVT_MENU, self.OnSeqRefine, id=item.GetId())
231       
232    def _init_Imports(self):
233        '''import all the G2phase*.py & G2sfact*.py & G2pwd*.py files that
234        are found in the path
235        '''
236
237        self.ImportPhaseReaderlist = []
238        self._init_Import_routines('phase',self.ImportPhaseReaderlist,'Phase')
239        self.ImportSfactReaderlist = []
240        self._init_Import_routines('sfact',self.ImportSfactReaderlist,'Struct_Factor')
241        self.ImportPowderReaderlist = []
242        self._init_Import_routines('pwd',self.ImportPowderReaderlist,'Powder_Data')
243        self.ImportSmallAngleReaderlist = []
244        self._init_Import_routines('sad',self.ImportSmallAngleReaderlist,'SmallAngle_Data')
245        self.ImportMenuId = {}
246
247    def _init_Import_routines(self,prefix,readerlist,errprefix):
248        '''import all the import readers matching the prefix
249        '''
250        #path2GSAS2 = os.path.dirname(os.path.realpath(__file__)) # location of this file
251        #pathlist = sys.path[:]
252        #if path2GSAS2 not in pathlist: pathlist.append(path2GSAS2)
253        #path2GSAS2 = os.path.join(
254        #    os.path.dirname(os.path.realpath(__file__)), # location of this file
255        #    'imports')
256        pathlist = sys.path[:]
257        #if path2GSAS2 not in pathlist: pathlist.append(path2GSAS2)
258
259        filelist = []
260        for path in pathlist:
261            for filename in glob.iglob(os.path.join(
262                path,
263                "G2"+prefix+"*.py")):
264                filelist.append(filename)   
265                #print 'debug: found',filename
266        filelist = sorted(list(set(filelist))) # remove duplicates
267        for filename in filelist:
268            path,rootname = os.path.split(filename)
269            pkg = os.path.splitext(rootname)[0]
270            try:
271                fp = None
272                fp, fppath,desc = imp.find_module(pkg,[path,])
273                pkg = imp.load_module(pkg,fp,fppath,desc)
274                for clss in inspect.getmembers(pkg): # find classes defined in package
275                    if clss[0].startswith('_'): continue
276                    if inspect.isclass(clss[1]):
277                        # check if we have the required methods
278                        for m in 'Reader','ExtensionValidator','ContentsValidator':
279                            if not hasattr(clss[1],m): break
280                            if not callable(getattr(clss[1],m)): break
281                        else:
282                            reader = clss[1]() # create an import instance
283                            readerlist.append(reader)
284            except AttributeError:
285                print 'Import_'+errprefix+': Attribute Error '+str(filename)
286                pass
287            except ImportError:
288                print 'Import_'+errprefix+': Error importing file '+str(filename)
289                pass
290            if fp: fp.close()
291
292    def EnableSeqRefineMenu(self):
293        '''Enable or disable the sequential refinement menu items based on the
294        contents of the Controls 'Seq Data' item (if present)
295        '''
296        controls = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,self.root, 'Controls'))
297        if controls.get('Seq Data'):
298            for i in self.SeqRefine: i.Enable(True)
299        else:
300            for i in self.SeqRefine: i.Enable(False)
301
302    def OnImportGeneric(self,reader,readerlist,label,multiple=False,usedRanIdList=[]):
303        '''Used to import Phases, powder dataset or single
304        crystal datasets (structure factor tables) using reader objects
305        subclassed from :class:`GSASIIIO.ImportPhase`, :class:`GSASIIIO.ImportStructFactor`
306        or :class:`GSASIIIO.ImportPowderData`. If a reader is specified, only
307        that will be attempted, but if no reader is specified, every one
308        that is potentially compatible (by file extension) will
309        be tried on the selected file(s).
310
311        :param readerobject reader: This will be a reference to
312          a particular object to be used to read a file or None,
313          if every appropriate reader should be used.
314
315        :param list readerlist: a list of reader objects appropriate for
316          the current read attempt. At present, this will be either
317          self.ImportPhaseReaderlist, self.ImportSfactReaderlist or
318          self.ImportPowderReaderlist (defined in _init_Imports from
319          the files found in the path), but in theory this list could
320          be tailored. Used only when reader is None.
321
322        :param str label: string to place on the open file dialog:
323          Open `label` input file
324
325        :param bool multiple: True if multiple files can be selected
326          in the file dialog. False is default. At present True is used
327          only for reading of powder data.
328
329        :param list usedRanIdList: an optional list of random Ids that
330          have been used and should not be reused
331
332        :returns: a list of reader objects (rd_list) that were able
333          to read the specified file(s). This list may be empty.
334        '''
335        self.lastimport = ''
336        self.zipfile = None
337        singlereader = True
338        if reader is None:
339            singlereader = False
340            multiple = False
341            #print "use all formats"
342            choices = "any file (*.*)|*.*"
343            choices += "|zip archive (.zip)|*.zip"
344            extdict = {}
345            # compile a list of allowed extensions
346            for rd in readerlist:
347                fmt = rd.formatName
348                for extn in rd.extensionlist:
349                    if not extdict.get(extn): extdict[extn] = []
350                    extdict[extn] += [fmt,]
351            for extn in sorted(extdict.keys(),cmp=lambda x,y: cmp(x.lower(), y.lower())):
352                fmt = ''
353                for f in extdict[extn]:
354                    if fmt != "": fmt += ', '
355                    fmt += f
356                choices += "|" + fmt + " file (*" + extn + ")|*" + extn
357        else:
358            readerlist = [reader,]
359            # compile a list of allowed extensions
360            choices = reader.formatName + " file ("
361            w = ""
362            for extn in reader.extensionlist:
363                if w != "": w += ";"
364                w += "*" + extn
365            choices += w + ")|" + w
366            choices += "|zip archive (.zip)|*.zip"
367            if not reader.strictExtension:
368                choices += "|any file (*.*)|*.*"
369        # get the file(s)
370        if multiple:
371            mode = style=wx.OPEN | wx.CHANGE_DIR | wx.MULTIPLE
372        else:
373            mode = style=wx.OPEN | wx.CHANGE_DIR
374        dlg = wx.FileDialog(self, message="Choose "+label+" input file",
375            defaultFile="",wildcard=choices, style=mode)
376        if self.Tutorials:
377            dlg.SetDirectory(os.path.join(GSASIIpath.path2GSAS2,'Exercises'))
378            self.Tutorials = False
379        try:
380            if dlg.ShowModal() == wx.ID_OK:
381                if multiple:
382                    filelist = dlg.GetPaths()
383                    if len(filelist) == 0: return []
384                else:
385                    filename = dlg.GetPath()
386                    filelist = [filename,]
387                os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
388            else: # cancel was pressed
389                return []
390        finally:
391            dlg.Destroy()
392        rd_list = []
393        filelist1 = []
394        for filename in filelist:
395            # is this a zip file?
396            if os.path.splitext(filename)[1].lower() == '.zip':
397                extractedfiles = G2IO.ExtractFileFromZip(
398                    filename,parent=self,
399                    multipleselect=True)
400                if extractedfiles is None: continue # error or Cancel
401                if extractedfiles != filename:
402                    self.zipfile = filename # save zip name
403                    filelist1 += extractedfiles
404                    continue
405            filelist1.append(filename)
406        filelist = filelist1
407        for filename in filelist:
408            # is this a zip file?
409            if os.path.splitext(filename)[1].lower() == '.zip':
410                extractedfile = G2IO.ExtractFileFromZip(filename,parent=self)
411                if extractedfile is None: continue # error or Cancel
412                if extractedfile != filename:
413                    filename,self.zipfile = extractedfile,filename # now use the file that was created
414            # set what formats are compatible with this file
415            primaryReaders = []
416            secondaryReaders = []
417            for rd in readerlist:
418                flag = rd.ExtensionValidator(filename)
419                if flag is None: 
420                    secondaryReaders.append(rd)
421                elif flag:
422                    primaryReaders.append(rd)
423            if len(secondaryReaders) + len(primaryReaders) == 0:
424                self.ErrorDialog('No Format','No matching format for file '+filename)
425                return []
426
427            fp = None
428            msg = ''
429            try:
430                fp = open(filename,'Ur')
431                if len(filelist) == 1:
432                    # confirm we have the right file
433                    rdmsg = 'File '+str(filename)+' begins:\n\n'
434                    for i in range(3):
435                        rdmsg += fp.readline()
436                    rdmsg += '\n\nDo you want to read this file?'
437                    if not all([ord(c) < 128 and ord(c) != 0 for c in rdmsg]): # show only if ASCII
438                        rdmsg = 'File '+str(
439                            filename)+' is a binary file. Do you want to read this file?'
440                    result = wx.ID_NO
441                    # it would be better to use something that
442                    # would resize better, but this will do for now
443                    dlg = wx.MessageDialog(
444                        self, rdmsg,
445                        'Is this the file you want?', 
446                        wx.YES_NO | wx.ICON_QUESTION,
447                        )
448                    dlg.SetSize((700,300)) # does not resize on Mac
449                    try:
450                        result = dlg.ShowModal()
451                    finally:
452                        dlg.Destroy()
453                    if result == wx.ID_NO: return []
454                           
455                self.lastimport = filename # this is probably not what I want to do -- it saves only the
456                # last name in a series. See rd.readfilename for a better name.
457               
458                # try the file first with Readers that specify the
459                # file's extension and later with ones that merely allow it
460                errorReport = ''
461                for rd in primaryReaders+secondaryReaders:
462                    rd.ReInitialize() # purge anything from a previous read
463                    fp.seek(0)  # rewind
464                    rd.errors = "" # clear out any old errors
465                    if not rd.ContentsValidator(fp): # rejected on cursory check
466                        errorReport += "\n  "+rd.formatName + ' validator error'
467                        if rd.errors: 
468                            errorReport += ': '+rd.errors
469                        continue 
470                    repeat = True
471                    rdbuffer = {} # create temporary storage for file reader
472                    block = 0
473                    while repeat: # loop if the reader asks for another pass on the file
474                        block += 1
475                        repeat = False
476                        fp.seek(0)  # rewind
477                        rd.objname = os.path.basename(filename)
478                        flag = False
479                        try:
480                            flag = rd.Reader(filename,fp,self,
481                                             buffer=rdbuffer,
482                                             blocknum=block,
483                                             usedRanIdList=usedRanIdList,
484                                             )
485                        except rd.ImportException as detail:
486                            rd.errors += "\n  Read exception: "+str(detail)
487                        except Exception as detail:
488                            import traceback
489                            rd.errors += "\n  Unhandled read exception: "+str(detail)
490                            rd.errors += "\n  Traceback info:\n"+str(traceback.format_exc())
491                        if flag: # this read succeeded
492                            rd.readfilename = filename
493                            rd_list.append(copy.deepcopy(rd)) # save the result before it is written over
494                            if rd.repeat:
495                                repeat = True
496                            continue
497                        errorReport += '\n'+rd.formatName + ' read error'
498                        if rd.errors:
499                            errorReport += ': '+rd.errors
500                    if rd_list: # read succeeded, was there a warning or any errors?
501                        if rd.warnings:
502                            self.ErrorDialog('Read Warning','The '+ rd.formatName+
503                                             ' reader reported a warning message:\n\n'+
504                                             rd.warnings)
505                        break # success in reading, try no further
506                else:
507                    if singlereader:
508                        self.ErrorDialog('Read Error','The '+ rd.formatName+
509                                         ' reader was not able to read file '+filename+msg+
510                                         '\n\nError message(s):\n'+errorReport
511                                         )
512                    else:
513                        self.ErrorDialog('Read Error','No reader was able to read file '+filename+msg+
514                                         '\n\nError messages:\n'+errorReport
515                                         )
516            except:
517                import traceback
518                print traceback.format_exc()
519                self.ErrorDialog('Open Error','Unexpected error trying to open or read file '+filename)
520            if fp: fp.close()
521        return rd_list
522
523    def _Add_ImportMenu_Phase(self,parent):
524        '''configure the Import Phase menus accord to the readers found in _init_Imports
525        '''
526        submenu = wx.Menu()
527        item = parent.AppendMenu(wx.ID_ANY, 'Phase',
528            submenu, help='Import phase data')
529        for reader in self.ImportPhaseReaderlist:
530            item = submenu.Append(wx.ID_ANY,help=reader.longFormatName,
531                kind=wx.ITEM_NORMAL,text='from '+reader.formatName+' file')
532            self.ImportMenuId[item.GetId()] = reader
533            self.Bind(wx.EVT_MENU, self.OnImportPhase, id=item.GetId())
534        item = submenu.Append(wx.ID_ANY,
535                              help='Import phase data, use file to try to determine format',
536                              kind=wx.ITEM_NORMAL,
537                              text='guess format from file')
538        self.Bind(wx.EVT_MENU, self.OnImportPhase, id=item.GetId())
539
540    def OnImportPhase(self,event):
541        '''Called in response to an Import/Phase/... menu item
542        to read phase information.
543        dict self.ImportMenuId is used to look up the specific
544        reader item associated with the menu item, which will be
545        None for the last menu item, which is the "guess" option
546        where all appropriate formats will be tried.
547        '''
548        # look up which format was requested
549        reqrdr = self.ImportMenuId.get(event.GetId())
550       
551        # make a list of phase names, ranId's and the histograms used in those phases
552        phaseRIdList,usedHistograms = self.GetPhaseInfofromTree()
553        phaseNameList = usedHistograms.keys() # phase names in use
554        usedHKLFhists = [] # used single-crystal histograms
555        for p in usedHistograms:
556            for h in usedHistograms[p]:
557                if h.startswith('HKLF ') and h not in usedHKLFhists:
558                    usedHKLFhists.append(h)
559        rdlist = self.OnImportGeneric(reqrdr,
560                                  self.ImportPhaseReaderlist,
561                                  'phase',usedRanIdList=phaseRIdList)
562        if len(rdlist) == 0: return
563        # for now rdlist is only expected to have one element
564        # but below will allow multiple phases to be imported
565        # if ever the import routines ever implement multiple phase reads.
566        self.CheckNotebook()
567        newPhaseList = []
568        for rd in rdlist:
569            dlg = wx.TextEntryDialog( # allow editing of phase name
570                self, 'Enter the name for the new phase',
571                'Edit phase name', rd.Phase['General']['Name'],
572                style=wx.OK)
573            dlg.CenterOnParent()
574            if dlg.ShowModal() == wx.ID_OK:
575                rd.Phase['General']['Name'] = dlg.GetValue()
576            dlg.Destroy()
577            # make new phase names unique
578            rd.Phase['General']['Name'] = G2obj.MakeUniqueLabel(rd.Phase['General']['Name'],phaseNameList)
579            PhaseName = rd.Phase['General']['Name']
580            newPhaseList.append(PhaseName)
581            print 'Read phase '+str(PhaseName)+' from file '+str(self.lastimport)
582            if not G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
583                sub = self.PatternTree.AppendItem(parent=self.root,text='Phases')
584            else:
585                sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
586            psub = self.PatternTree.AppendItem(parent=sub,text=PhaseName)
587            self.PatternTree.SetItemPyData(psub,rd.Phase)
588            self.PatternTree.Expand(self.root) # make sure phases are seen
589            self.PatternTree.Expand(sub) 
590            self.PatternTree.Expand(psub)
591            self.PatternTree.SelectItem(psub) # show the page to complete the initialization (yuk!)
592            wx.Yield() # make sure call of GSASII.OnPatternTreeSelChanged happens before we go on
593
594            if rd.Constraints:
595                sub = G2gd.GetPatternTreeItemId(self,self.root,'Constraints') # was created in CheckNotebook if needed
596                Constraints = self.PatternTree.GetItemPyData(sub)               
597                # TODO: make sure that NEWVAR names are unique here?
598                for i in rd.Constraints:
599                    if type(i) is dict:
600                        #for j in i: print j,' --> ',i[j]
601                        if '_Explain' not in Constraints: Constraints['_Explain'] = {}
602                        Constraints['_Explain'].update(i)
603                        continue
604                    Constraints['Phase'].append(i)
605        if not newPhaseList: return # somehow, no new phases
606        # get a list of existing histograms
607        PWDRlist = []
608        HKLFlist = []
609        if self.PatternTree.GetCount():
610            item, cookie = self.PatternTree.GetFirstChild(self.root)
611            while item:
612                name = self.PatternTree.GetItemText(item)
613                if name.startswith('PWDR ') and name not in PWDRlist:
614                    PWDRlist.append(name)
615                if name.startswith('HKLF ') and name not in HKLFlist:
616                    HKLFlist.append(name)
617                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
618        TextList = PWDRlist + HKLFlist
619        if not len(TextList): return # no data loaded yet
620        header = 'Select histogram(s) to add to new phase(s):'
621        for phaseName in newPhaseList:
622            header += '\n  '+str(phaseName)
623
624        notOK = True
625        while notOK:
626            result = G2gd.ItemSelector(TextList,self,header,header='Add histogram(s)',multiple=True)
627            if not result: return
628            # check that selected single crystal histograms are not already in use!
629            used = [TextList[i] for i in result if TextList[i] in usedHKLFhists]
630            #for i in result:
631            #    if TextList[i] in usedHKLFhists: used.append(TextList[i])
632            if used:
633                msg = 'The following single crystal histogram(s) are already in use'
634                for i in used:
635                    msg += '\n  '+str(i)
636                msg += '\nAre you sure you want to add them to this phase? '
637                msg += 'Associating a single crystal dataset to >1 histogram is usually an error, '
638                msg += 'so No is suggested here.'
639                if self.ErrorDialog('Likely error',msg,self,wtype=wx.YES_NO) == wx.ID_YES: notOK = False
640            else:
641                notOK = False
642        # connect new phases to histograms
643        sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
644        if not sub:
645            raise Exception('ERROR -- why are there no phases here?')
646        wx.BeginBusyCursor()
647        item, cookie = self.PatternTree.GetFirstChild(sub)
648        while item: # loop over (new) phases
649            phaseName = self.PatternTree.GetItemText(item)
650            data = self.PatternTree.GetItemPyData(item)
651            item, cookie = self.PatternTree.GetNextChild(sub, cookie)
652            if phaseName not in newPhaseList: continue
653            generalData = data['General']
654            SGData = generalData['SGData']
655            Super = generalData.get('Super',0)
656            SuperVec = []
657            for i in range(Super):
658                SuperVec.append(generalData['SuperVec'][i][0])
659                SuperVec = np.array(SuperVec)
660            UseList = data['Histograms']
661            NShkl = len(G2spc.MustrainNames(SGData))
662            NDij = len(G2spc.HStrainNames(SGData))
663            for i in result:
664                histoName = TextList[i]
665                if histoName in HKLFlist:
666                    #redo UpdateHKLFdata(histoName) here:
667                    Id = G2gd.GetPatternTreeItemId(self,self.root,histoName)
668                    refDict,reflData = self.PatternTree.GetItemPyData(Id)
669                    G,g = G2lat.cell2Gmat(generalData['Cell'][1:7])
670                    Super = reflData.get('Super',0)
671                    for iref,ref in enumerate(reflData['RefList']):
672                        hkl = ref[:3]
673                        H = list(hkl+np.sum(SuperVec*ref[3:3+Super],axis=0))
674                        ref[4+Super] = np.sqrt(1./G2lat.calc_rDsq2(H,G))
675                        iabsnt,ref[3+Super],Uniq,phi = G2spc.GenHKLf(H,SGData)
676                    UseList[histoName] = SetDefaultDData(reflData['Type'],histoName)
677                elif histoName in PWDRlist:
678                    Id = G2gd.GetPatternTreeItemId(self,self.root,histoName)
679                    refList = self.PatternTree.GetItemPyData(
680                        G2gd.GetPatternTreeItemId(self,Id,'Reflection Lists'))
681                    refList[generalData['Name']] = []
682                    UseList[histoName] = SetDefaultDData('PWDR',histoName,NShkl=NShkl,NDij=NDij)
683                else:
684                    raise Exception('Unexpected histogram '+str(histoName))
685        wx.EndBusyCursor()
686        return # success
687       
688    def _Add_ImportMenu_Sfact(self,parent):
689        '''configure the Import Structure Factor menus accord to the readers found in _init_Imports
690        '''
691        submenu = wx.Menu()
692        item = parent.AppendMenu(wx.ID_ANY, 'Structure Factor',
693            submenu, help='Import Structure Factor data')
694        for reader in self.ImportSfactReaderlist:
695            item = submenu.Append(wx.ID_ANY,help=reader.longFormatName,               
696                kind=wx.ITEM_NORMAL,text='from '+reader.formatName+' file')
697            self.ImportMenuId[item.GetId()] = reader
698            self.Bind(wx.EVT_MENU, self.OnImportSfact, id=item.GetId())
699        item = submenu.Append(wx.ID_ANY,
700            help='Import Structure Factor, use file to try to determine format',
701            kind=wx.ITEM_NORMAL,
702            text='guess format from file')
703        self.Bind(wx.EVT_MENU, self.OnImportSfact, id=item.GetId())
704
705    def OnImportSfact(self,event):
706        '''Called in response to an Import/Structure Factor/... menu item
707        to read single crystal datasets.
708        dict self.ImportMenuId is used to look up the specific
709        reader item associated with the menu item, which will be
710        None for the last menu item, which is the "guess" option
711        where all appropriate formats will be tried.
712        '''
713        # get a list of existing histograms
714        HKLFlist = []
715        if self.PatternTree.GetCount():
716            item, cookie = self.PatternTree.GetFirstChild(self.root)
717            while item:
718                name = self.PatternTree.GetItemText(item)
719                if name.startswith('HKLF ') and name not in HKLFlist:
720                    HKLFlist.append(name)
721                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
722        # look up which format was requested
723        reqrdr = self.ImportMenuId.get(event.GetId())
724        rdlist = self.OnImportGeneric(reqrdr,self.ImportSfactReaderlist,
725            'Structure Factor',multiple=True)
726        if len(rdlist) == 0: return
727        self.CheckNotebook()
728        newHistList = []
729        for rd in rdlist:
730            HistName = rd.objname
731            if len(rdlist) <= 2: 
732                dlg = wx.TextEntryDialog( # allow editing of Structure Factor name
733                    self, 'Enter the name for the new Structure Factor',
734                    'Edit Structure Factor name', HistName,
735                    style=wx.OK)
736                dlg.CenterOnParent()
737                if dlg.ShowModal() == wx.ID_OK:
738                    HistName = dlg.GetValue()
739                dlg.Destroy()
740            HistName = 'HKLF '+HistName
741            # make new histogram names unique
742            if len(rd.Banks):
743                for Bank in rd.Banks:
744                    valuesdict = {'wtFactor':1.0,'Dummy':False,'ranId':ran.randint(0,sys.maxint),}
745                    HistName = G2obj.MakeUniqueLabel(HistName,HKLFlist)
746                    print 'Read structure factor table '+str(HistName)+' from file '+str(self.lastimport)
747                    Id = self.PatternTree.AppendItem(parent=self.root,text=HistName)
748                    if not Bank['RefDict'].get('FF'):
749                        Bank['RefDict']['FF'] = [{} for i in range(len(Bank['RefDict']['RefList']))]
750                    self.PatternTree.SetItemPyData(Id,[valuesdict,Bank['RefDict']])
751                    Sub = self.PatternTree.AppendItem(Id,text='Instrument Parameters')
752                    self.PatternTree.SetItemPyData(Sub,copy.copy(rd.Parameters))
753                    self.PatternTree.SetItemPyData(
754                        self.PatternTree.AppendItem(Id,text='Reflection List'),[])  #dummy entry for GUI use
755                    newHistList.append(HistName)
756            else:
757                valuesdict = {'wtFactor':1.0,'Dummy':False,'ranId':ran.randint(0,sys.maxint),}
758                HistName = G2obj.MakeUniqueLabel(HistName,HKLFlist)
759                print 'Read structure factor table '+str(HistName)+' from file '+str(self.lastimport)
760                if not rd.RefDict.get('FF'):
761                    rd.RefDict['FF'] = [{} for i in range(len(rd.RefDict['RefList']))]
762                Id = self.PatternTree.AppendItem(parent=self.root,text=HistName)
763                self.PatternTree.SetItemPyData(Id,[valuesdict,rd.RefDict])
764                Sub = self.PatternTree.AppendItem(Id,text='Instrument Parameters')
765                self.PatternTree.SetItemPyData(Sub,rd.Parameters)
766                self.PatternTree.SetItemPyData(
767                    self.PatternTree.AppendItem(Id,text='Reflection List'),[])  #dummy entry for GUI use
768                newHistList.append(HistName)
769               
770            self.PatternTree.SelectItem(Id)
771            self.PatternTree.Expand(Id)
772            self.Sngl = True
773
774        if not newHistList: return # somehow, no new histograms
775        # make a list of phase names
776        phaseRIdList,usedHistograms = self.GetPhaseInfofromTree()
777        phaseNameList = usedHistograms.keys() # phase names in use
778        if not phaseNameList: return # no phases yet, nothing to do
779        header = 'Select phase(s) to add the new\nsingle crystal dataset(s) to:'
780        for Name in newHistList:
781            header += '\n  '+str(Name)
782        result = G2gd.ItemSelector(phaseNameList,self,header,header='Add to phase(s)',multiple=True)
783        if not result: return
784        # connect new phases to histograms
785        sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
786        if not sub:
787            raise Exception('ERROR -- why are there no phases here?')
788        wx.BeginBusyCursor()
789        item, cookie = self.PatternTree.GetFirstChild(sub)
790        iph = -1
791        while item: # loop over (new) phases
792            iph += 1
793            phaseName = self.PatternTree.GetItemText(item)
794            data = self.PatternTree.GetItemPyData(item)
795            item, cookie = self.PatternTree.GetNextChild(sub, cookie)
796            if iph not in result: continue
797            generalData = data['General']
798            SGData = generalData['SGData']
799            Super = generalData.get('Super',0)
800            SuperVec = []
801            for i in range(Super):
802                SuperVec.append(generalData['SuperVec'][i][0])
803                SuperVec = np.array(SuperVec)
804            UseList = data['Histograms']
805            for histoName in newHistList:
806                #redo UpdateHKLFdata(histoName) here:
807                Id = G2gd.GetPatternTreeItemId(self,self.root,histoName)
808                refDict,reflData = self.PatternTree.GetItemPyData(Id)
809                UseList[histoName] = SetDefaultDData(reflData['Type'],histoName)
810                G,g = G2lat.cell2Gmat(generalData['Cell'][1:7])
811                for iref,ref in enumerate(reflData['RefList']):
812                    hkl = ref[:3]
813                    H = list(hkl+np.sum(SuperVec*ref[3:3+Super],axis=0))
814                    ref[4+Super] = np.sqrt(1./G2lat.calc_rDsq2(H,G))
815                    iabsnt,ref[3+Super],Uniq,phi = G2spc.GenHKLf(H,SGData)
816        wx.EndBusyCursor()
817       
818        return # success
819
820    def _Add_ImportMenu_powder(self,parent):
821        '''configure the Powder Data menus accord to the readers found in _init_Imports
822        '''
823        submenu = wx.Menu()
824        item = parent.AppendMenu(wx.ID_ANY, 'Powder Data',
825            submenu, help='Import Powder data')
826        for reader in self.ImportPowderReaderlist:
827            item = submenu.Append(wx.ID_ANY,help=reader.longFormatName,
828                kind=wx.ITEM_NORMAL,text='from '+reader.formatName+' file')
829            self.ImportMenuId[item.GetId()] = reader
830            self.Bind(wx.EVT_MENU, self.OnImportPowder, id=item.GetId())
831        item = submenu.Append(wx.ID_ANY,
832            help='Import powder data, use file to try to determine format',
833            kind=wx.ITEM_NORMAL,text='guess format from file')
834        self.Bind(wx.EVT_MENU, self.OnImportPowder, id=item.GetId())
835        submenu.AppendSeparator()
836        item = submenu.Append(wx.ID_ANY,
837            help='Create a powder data set entry that will be simulated',
838            kind=wx.ITEM_NORMAL,text='Simulate a dataset')
839        self.Bind(wx.EVT_MENU, self.OnDummyPowder, id=item.GetId())
840       
841    def OpenPowderInstprm(self,instfile):
842        '''Read a GSAS-II (new) instrument parameter file
843
844        :param str instfile: name of instrument parameter file
845
846        '''
847        if os.path.splitext(instfile)[1].lower() != '.instprm': # invalid file
848            return None           
849        if not os.path.exists(instfile): # no such file
850            return None
851        File = open(instfile,'r')
852        lines = File.readlines()
853        File.close()
854        return lines       
855           
856    def ReadPowderInstprm(self,instLines):
857        '''Read lines from a GSAS-II (new) instrument parameter file
858
859        :param list instLines: strings from GSAS-II parameter file; can be concatenated with ';'
860
861        '''
862        if not instLines[0].startswith('#GSAS-II'): # not a valid file
863            return None
864        newItems = []
865        newVals = []
866        for S in instLines:
867            if S[0] == '#':
868                continue
869            S = S.replace(' ','')
870            SS = S[:-1].split(';')
871            for s in SS:
872                [item,val] = s.split(':')
873                newItems.append(item)
874                try:
875                    newVals.append(float(val))
876                except ValueError:
877                    newVals.append(val)                       
878        return G2IO.makeInstDict(newItems,newVals,len(newVals)*[False,]),{}
879       
880    def ReadPowderIparm(self,instfile,bank,databanks,rd):
881        '''Read a GSAS (old) instrument parameter file
882
883        :param str instfile: name of instrument parameter file
884
885        :param int bank: the bank number read in the raw data file
886
887        :param int databanks: the number of banks in the raw data file.
888          If the number of banks in the data and instrument parameter files
889          agree, then the sets of banks are assumed to match up and bank
890          is used to select the instrument parameter file. If not, the user
891          is asked to make a selection.
892
893        :param obj rd: the raw data (histogram) data object. This
894          sets rd.instbank.
895
896        '''
897        if not os.path.exists(instfile): # no such file
898            return {}
899        fp = 0
900        try:
901            fp = open(instfile,'Ur')
902            Iparm = {}
903            for S in fp:
904                if '#' in S[0]:
905                    continue
906                Iparm[S[:12]] = S[12:-1]
907        except IOError:
908            print('Error reading file:'+str(instfile))
909        if fp:       
910            fp.close()
911
912        ibanks = int(Iparm.get('INS   BANK  ','1').strip())
913        hType = Iparm['INS   HTYPE '].strip()
914        if ibanks == 1: # there is only one bank here, return it
915            rd.instbank = 1
916            return Iparm
917        if 'PNT' in hType:
918            rd.instbank = bank
919        elif ibanks != databanks:
920            # number of banks in data and prm file not not agree, need a
921            # choice from a human here
922            choices = []
923            for i in range(1,1+ibanks):
924                choices.append('Bank '+str(i))
925            bank = rd.BlockSelector(
926                choices, self,
927                title='Select an instrument parameter bank for '+
928                os.path.split(rd.powderentry[0])[1]+' BANK '+str(bank)+
929                '\nOr use Cancel to select from the default parameter sets',
930                header='Block Selector')
931        if bank is None: return {}
932        # pull out requested bank # bank from the data, and change the bank to 1
933        IparmS = {}
934        for key in Iparm:
935            if key[4:6] == "  ":
936                IparmS[key] = Iparm[key]
937            elif int(key[4:6].strip()) == bank:
938                IparmS[key[:4]+' 1'+key[6:]] = Iparm[key]
939        rd.instbank = bank
940        return IparmS
941                       
942    def GetPowderIparm(self,rd, prevIparm, lastIparmfile, lastdatafile):
943        '''Open and read an instrument parameter file for a data file
944        Returns the list of parameters used in the data tree
945
946        :param obj rd: the raw data (histogram) data object.
947
948        :param str prevIparm: not used
949
950        :param str lastIparmfile: Name of last instrument parameter
951          file that was read, or a empty string.
952
953        :param str lastdatafile: Name of last data file that was read.
954
955        :returns: a list of two dicts, the first containing instrument parameters
956          and the second used for TOf lookup tables for profile coeff.
957
958        '''
959        def SetPowderInstParms(Iparm, rd):
960            '''extracts values from instrument parameters in rd.instdict
961            or in array Iparm.
962            Create and return the contents of the instrument parameter tree entry.
963            '''
964            DataType = Iparm['INS   HTYPE '].strip()[:3]  # take 1st 3 chars
965            # override inst values with values read from data file
966            if rd.instdict.get('type'):
967                DataType = rd.instdict.get('type')
968            data = [DataType,]
969            instname = Iparm.get('INS  1INAME ')
970            if instname:
971                rd.Sample['InstrName'] = instname.strip()
972            if 'C' in DataType:
973                wave1 = None
974                wave2 = 0.0
975                if rd.instdict.get('wave'):
976                    wl = rd.instdict.get('wave')
977                    wave1 = wl[0]
978                    if len(wl) > 1: wave2 = wl[1]
979                s = Iparm['INS  1 ICONS']
980                if not wave1:
981                    wave1 = G2IO.sfloat(s[:10])
982                    wave2 = G2IO.sfloat(s[10:20])
983                v = (wave1,wave2,
984                     G2IO.sfloat(s[20:30]),G2IO.sfloat(s[55:65]),G2IO.sfloat(s[40:50])) #get lam1, lam2, zero, pola & ratio
985                if not v[1]:
986                    names = ['Type','Lam','Zero','Polariz.','U','V','W','X','Y','SH/L','Azimuth'] 
987                    v = (v[0],v[2],v[4])
988                    codes = [0,0,0,0]
989                else:
990                    names = ['Type','Lam1','Lam2','Zero','I(L2)/I(L1)','Polariz.','U','V','W','X','Y','SH/L','Azimuth']
991                    codes = [0,0,0,0,0,0]
992                data.extend(v)
993                if 'INS  1PRCF  ' in Iparm:
994                    v1 = Iparm['INS  1PRCF  '].split()                                                 
995                    v = Iparm['INS  1PRCF 1'].split()
996                    data.extend([float(v[0]),float(v[1]),float(v[2])])                  #get GU, GV & GW - always here
997                    azm = float(Iparm.get('INS  1DETAZM','0.0'))
998                    v = Iparm['INS  1PRCF 2'].split()
999                    if v1[0] == 3:
1000                        data.extend([float(v[0]),float(v[1]),float(v[2])+float(v[3],azm)])  #get LX, LY, S+H/L & azimuth
1001                    else:
1002                        data.extend([0.0,0.0,0.002,azm])                                      #OK defaults if fxn #3 not 1st in iprm file                   
1003                else:
1004                    v1 = Iparm['INS  1PRCF1 '].split()                                                 
1005                    v = Iparm['INS  1PRCF11'].split()
1006                    data.extend([float(v[0]),float(v[1]),float(v[2])])                  #get GU, GV & GW - always here
1007                    azm = float(Iparm.get('INS  1DETAZM','0.0'))
1008                    v = Iparm['INS  1PRCF12'].split()
1009                    if v1[0] == 3:
1010                        data.extend([float(v[0]),float(v[1]),float(v[2])+float(v[3],azm)])  #get LX, LY, S+H/L & azimuth
1011                    else:
1012                        data.extend([0.0,0.0,0.002,azm])                                      #OK defaults if fxn #3 not 1st in iprm file
1013                codes.extend([0,0,0,0,0,0,0])
1014                return [G2IO.makeInstDict(names,data,codes),{}]
1015            elif 'T' in DataType:
1016                names = ['Type','fltPath','2-theta','difC','difA', 'difB','Zero','alpha','beta-0','beta-1',
1017                    'beta-q','sig-0','sig-1','sig-2','sig-q', 'X','Y','Azimuth',]
1018                codes = [0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,]
1019                azm = 0.
1020                if 'INS  1DETAZM' in Iparm:
1021                    azm = float(Iparm['INS  1DETAZM'])
1022                s = Iparm['INS   FPATH1'].split()
1023                fltPath0 = G2IO.sfloat(s[0])
1024                s = Iparm['INS  1BNKPAR'].split()
1025                fltPath1 = G2IO.sfloat(s[0])
1026                data.extend([fltPath0+fltPath1,])               #Flight path source-sample-detector
1027                data.extend([G2IO.sfloat(s[1]),])               #2-theta for bank
1028                s = Iparm['INS  1 ICONS'].split()
1029                data.extend([G2IO.sfloat(s[0]),G2IO.sfloat(s[1]),0.0,G2IO.sfloat(s[2])])    #difC,difA,difB,Zero
1030                if 'INS  1PRCF  ' in Iparm:
1031                    s = Iparm['INS  1PRCF  '].split()
1032                    pfType = int(s[0])
1033                    s = Iparm['INS  1PRCF 1'].split()
1034                    if abs(pfType) == 1:
1035                        data.extend([G2IO.sfloat(s[1]),G2IO.sfloat(s[2]),G2IO.sfloat(s[3])]) #alpha, beta-0, beta-1
1036                        s = Iparm['INS  1PRCF 2'].split()
1037                        data.extend([0.0,0.0,G2IO.sfloat(s[1]),G2IO.sfloat(s[2]),0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y
1038                    elif abs(pfType) in [3,4,5]:
1039                        data.extend([G2IO.sfloat(s[0]),G2IO.sfloat(s[1]),G2IO.sfloat(s[2])]) #alpha, beta-0, beta-1
1040                        if abs(pfType) == 4:
1041                            data.extend([0.0,0.0,G2IO.sfloat(s[3]),0.0,0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y
1042                        else:
1043                            s = Iparm['INS  1PRCF 2'].split()
1044                            data.extend([0.0,0.0,G2IO.sfloat(s[0]),G2IO.sfloat(s[1]),0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y                       
1045                else:
1046                    s = Iparm['INS  1PRCF1 '].split()
1047                    pfType = int(s[0])
1048                    s = Iparm['INS  1PRCF11'].split()
1049                    if abs(pfType) == 1:
1050                        data.extend([G2IO.sfloat(s[1]),G2IO.sfloat(s[2]),G2IO.sfloat(s[3])]) #alpha, beta-0, beta-1
1051                        s = Iparm['INS  1PRCF12'].split()
1052                        data.extend([0.0,0.0,G2IO.sfloat(s[1]),G2IO.sfloat(s[2]),0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y
1053                    elif abs(pfType) in [3,4,5]:
1054                        data.extend([G2IO.sfloat(s[0]),G2IO.sfloat(s[1]),G2IO.sfloat(s[2])]) #alpha, beta-0, beta-1
1055                        if abs(pfType) == 4:
1056                            data.extend([0.0,0.0,G2IO.sfloat(s[3]),0.0,0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y
1057                        else:
1058                            s = Iparm['INS  1PRCF12'].split()
1059                            data.extend([0.0,0.0,G2IO.sfloat(s[0]),G2IO.sfloat(s[1]),0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y                       
1060                Inst1 = G2IO.makeInstDict(names,data,codes)
1061                Inst2 = {}
1062                if pfType < 0:
1063                    Ipab = 'INS  1PAB'+str(-pfType)
1064                    Npab = int(Iparm[Ipab+'  '].strip())
1065                    Inst2['Pdabc'] = []
1066                    for i in range(Npab):
1067                        k = Ipab+str(i+1).rjust(2)
1068                        s = Iparm[k].split()
1069                        Inst2['Pdabc'].append([float(t) for t in s])
1070                    Inst2['Pdabc'] = np.array(Inst2['Pdabc'])
1071                    Inst2['Pdabc'].T[3] += Inst2['Pdabc'].T[0]*Inst1['difC'][0] #turn 3rd col into TOF
1072                if 'INS  1I ITYP' in Iparm:
1073                    s = Iparm['INS  1I ITYP'].split()
1074                    Ityp = int(s[0])
1075                    Tminmax = [float(s[1])*1000.,float(s[2])*1000.]
1076                    Itypes = ['Exponential','Maxwell/Exponential','','Maxwell/Chebyschev','']
1077                    if Ityp in [1,2,4]:
1078                        Inst2['Itype'] = Itypes[Ityp-1]
1079                        Inst2['Tminmax'] = Tminmax
1080                        Icoeff = []
1081                        Iesd = []
1082                        Icovar = []                   
1083                        for i in range(3):
1084                            s = Iparm['INS  1ICOFF'+str(i+1)].split()
1085                            Icoeff += [float(S) for S in s]
1086                            s = Iparm['INS  1IECOF'+str(i+1)].split()
1087                            Iesd += [float(S) for S in s]
1088                        NT = 10
1089                        for i in range(8):
1090                            s = Iparm['INS  1IECOR'+str(i+1)]
1091                            if i == 7:
1092                                NT = 8
1093                            Icovar += [float(s[6*j:6*j+6]) for j in range(NT)]
1094                        Inst2['Icoeff'] = Icoeff
1095                        Inst2['Iesd'] = Iesd
1096                        Inst2['Icovar'] = Icovar
1097                return [Inst1,Inst2]
1098
1099        # stuff we might need from the reader
1100        filename = rd.powderentry[0]
1101        bank = rd.powderentry[2]
1102        numbanks = rd.numbanks
1103        # is there an instrument parameter file defined for the current data set?
1104        # or if this is a read on a set of set of files, use the last one again
1105        #if rd.instparm or (lastdatafile == filename and lastIparmfile):
1106        if rd.instparm or lastIparmfile:
1107            if rd.instparm:
1108                instfile = os.path.join(os.path.split(filename)[0],
1109                                    rd.instparm)
1110            else:
1111                # for multiple reads of one data file, reuse the inst parm file
1112                instfile = lastIparmfile
1113            if os.path.exists(instfile):
1114                #print 'debug: try read',instfile
1115                Lines = self.OpenPowderInstprm(instfile)
1116                instParmList = None
1117                if Lines is not None:
1118                    instParmList = self.ReadPowderInstprm(Lines)
1119                if instParmList is not None:
1120                    rd.instfile = instfile
1121                    rd.instmsg = 'GSAS-II file '+instfile
1122                    return instParmList
1123                Iparm = self.ReadPowderIparm(instfile,bank,numbanks,rd)
1124                if Iparm:
1125                    #print 'debug: success'
1126                    rd.instfile = instfile
1127                    rd.instmsg = instfile + ' bank ' + str(rd.instbank)
1128                    return SetPowderInstParms(Iparm,rd)
1129            else:
1130                self.ErrorDialog('Open Error','Error opening instrument parameter file '
1131                    +str(instfile)+' requested by file '+ filename)
1132        # is there an instrument parameter file matching the current file
1133        # with extension .inst or .prm? If so read it
1134        basename = os.path.splitext(filename)[0]
1135        for ext in '.instprm','.prm','.inst','.ins':
1136            instfile = basename + ext
1137            Lines = self.OpenPowderInstprm(instfile)
1138            instParmList = None
1139            if Lines is not None:
1140                instParmList = self.ReadPowderInstprm(Lines)
1141            if instParmList is not None:
1142                rd.instfile = instfile
1143                rd.instmsg = 'GSAS-II file '+instfile
1144                return instParmList
1145            Iparm = self.ReadPowderIparm(instfile,bank,numbanks,rd)
1146            if Iparm:
1147                #print 'debug: success'
1148                rd.instfile = instfile
1149                rd.instmsg = instfile + ' bank ' + str(rd.instbank)
1150                return SetPowderInstParms(Iparm,rd)
1151            else:
1152                #print 'debug: open/read failed',instfile
1153                pass # fail silently
1154
1155        # did we read the data file from a zip? If so, look there for a
1156        # instrument parameter file
1157        if self.zipfile:
1158            for ext in '.instprm','.prm','.inst','.ins':
1159                instfile = G2IO.ExtractFileFromZip(
1160                    self.zipfile,
1161                    selection=os.path.split(basename + ext)[1],
1162                    parent=self)
1163                if instfile is not None and instfile != self.zipfile:
1164                    print 'debug:',instfile,'created from ',self.zipfile
1165                    Lines = self.OpenPowderInstprm(instfile)
1166                    instParmList = None
1167                    if Lines is not None:
1168                        instParmList = self.ReadPowderInstprm(Lines)
1169                    if instParmList is not None:
1170                        rd.instfile = instfile
1171                        rd.instmsg = 'GSAS-II file '+instfile
1172                        return instParmList
1173                    Iparm = self.ReadPowderIparm(instfile,bank,numbanks,rd)
1174                    if Iparm:
1175                        rd.instfile = instfile
1176                        rd.instmsg = instfile + ' bank ' + str(rd.instbank)
1177                        return SetPowderInstParms(Iparm,rd)
1178                    else:
1179                        #print 'debug: open/read for',instfile,'from',self.zipfile,'failed'
1180                        pass # fail silently
1181
1182        while True: # loop until we get a file that works or we get a cancel
1183            instfile = ''
1184            dlg = wx.FileDialog(
1185                self,
1186                'Choose inst. param file for "'
1187                +rd.idstring
1188                +'" (or Cancel for default)',
1189                '.', '',
1190                'GSAS iparm file (*.prm,*.inst,*.ins)|*.prm;*.inst;*.ins|'
1191                'GSAS-II iparm file (*.instprm)|*.instprm|'
1192                'All files (*.*)|*.*', 
1193                wx.OPEN|wx.CHANGE_DIR)
1194            if os.path.exists(lastIparmfile):
1195                dlg.SetFilename(lastIparmfile)
1196            if dlg.ShowModal() == wx.ID_OK:
1197                instfile = dlg.GetPath()
1198            dlg.Destroy()
1199            if not instfile: break
1200            Lines = self.OpenPowderInstprm(instfile)
1201            instParmList = None
1202            if Lines is not None:
1203                instParmList = self.ReadPowderInstprm(Lines)
1204            if instParmList is not None:
1205                rd.instfile = instfile
1206                rd.instmsg = 'GSAS-II file '+instfile
1207                return instParmList
1208            Iparm = self.ReadPowderIparm(instfile,bank,numbanks,rd)
1209            if Iparm:
1210                #print 'debug: success with',instfile
1211                rd.instfile = instfile
1212                rd.instmsg = instfile + ' bank ' + str(rd.instbank)
1213                return SetPowderInstParms(Iparm,rd)
1214            else:
1215                self.ErrorDialog('Read Error',
1216                                 'Error opening/reading file '+str(instfile))
1217       
1218        # still no success: offer user choice of defaults
1219        import defaultIparms as dI
1220        while True: # loop until we get a choice
1221            choices = []
1222            head = 'Select from default instrument parameters for '+rd.idstring
1223
1224            for l in dI.defaultIparm_lbl:
1225                choices.append('Defaults for '+l)
1226            res = rd.BlockSelector(
1227                choices,
1228                ParentFrame=self,
1229                title=head,
1230                header='Select default inst parms',
1231                useCancel=False)
1232            if res is None: continue
1233            rd.instfile = ''
1234            rd.instmsg = 'default: '+dI.defaultIparm_lbl[res]
1235            return self.ReadPowderInstprm(dI.defaultIparms[res])
1236
1237    def OnImportPowder(self,event):
1238        '''Called in response to an Import/Powder Data/... menu item
1239        to read a powder diffraction data set.
1240        dict self.ImportMenuId is used to look up the specific
1241        reader item associated with the menu item, which will be
1242        None for the last menu item, which is the "guess" option
1243        where all appropriate formats will be tried.
1244
1245        Also reads an instrument parameter file for each dataset.
1246        '''
1247        # get a list of existing histograms
1248        PWDRlist = []
1249        if self.PatternTree.GetCount():
1250            item, cookie = self.PatternTree.GetFirstChild(self.root)
1251            while item:
1252                name = self.PatternTree.GetItemText(item)
1253                if name.startswith('PWDR ') and name not in PWDRlist:
1254                    PWDRlist.append(name)
1255                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1256        # look up which format was requested
1257        reqrdr = self.ImportMenuId.get(event.GetId()) 
1258        rdlist = self.OnImportGeneric(
1259            reqrdr,self.ImportPowderReaderlist,'Powder Data',multiple=True)
1260        if len(rdlist) == 0: return
1261        self.CheckNotebook()
1262        Iparm = None
1263        lastIparmfile = ''
1264        lastdatafile = ''
1265        newHistList = []
1266        self.EnablePlot = False
1267        for rd in rdlist:
1268            if 'Instrument Parameters' not in rd.pwdparms:
1269                # get instrument parameters for each dataset, unless already set
1270                Iparm1,Iparm2 = self.GetPowderIparm(rd, Iparm, lastIparmfile, lastdatafile)
1271                if rd.repeat_instparm: 
1272                    lastIparmfile = rd.instfile
1273            else:
1274                Iparm1,Iparm2 = rd.pwdparms['Instrument Parameters']
1275            lastdatafile = rd.powderentry[0]
1276            HistName = rd.idstring
1277            HistName = 'PWDR '+HistName
1278            # make new histogram names unique
1279            HistName = G2obj.MakeUniqueLabel(HistName,PWDRlist)
1280            print 'Read powder data '+str(HistName)+ \
1281                ' from file '+str(rd.readfilename) + \
1282                ' with parameters from '+str(rd.instmsg)
1283            # data are read, now store them in the tree
1284            Id = self.PatternTree.AppendItem(parent=self.root,text=HistName)
1285            if 'T' in Iparm1['Type'][0]:
1286                if not rd.clockWd and rd.GSAS:
1287                    rd.powderdata[0] *= 100.        #put back the CW centideg correction
1288                cw = np.diff(rd.powderdata[0])
1289                rd.powderdata[0] = rd.powderdata[0][:-1]+cw/2.
1290                if rd.GSAS:     #NB: old GSAS wanted intensities*CW even if normalized!
1291                    rd.powderdata[1] = rd.powderdata[1][:-1]/cw
1292                    rd.powderdata[2] = rd.powderdata[2][:-1]*cw**2  #1/var=w at this point
1293                else:       #NB: from topas/fullprof type files
1294                    rd.powderdata[1] = rd.powderdata[1][:-1]
1295                    rd.powderdata[2] = rd.powderdata[2][:-1]
1296                if 'Itype' in Iparm2:
1297                    Ibeg = np.searchsorted(rd.powderdata[0],Iparm2['Tminmax'][0])
1298                    Ifin = np.searchsorted(rd.powderdata[0],Iparm2['Tminmax'][1])
1299                    rd.powderdata[0] = rd.powderdata[0][Ibeg:Ifin]
1300                    YI,WYI = G2pwd.calcIncident(Iparm2,rd.powderdata[0])
1301                    rd.powderdata[1] = rd.powderdata[1][Ibeg:Ifin]/YI
1302                    var = 1./rd.powderdata[2][Ibeg:Ifin]
1303                    var += WYI*rd.powderdata[1]**2
1304                    var /= YI**2
1305                    rd.powderdata[2] = 1./var
1306                rd.powderdata[3] = np.zeros_like(rd.powderdata[0])                                       
1307                rd.powderdata[4] = np.zeros_like(rd.powderdata[0])                                       
1308                rd.powderdata[5] = np.zeros_like(rd.powderdata[0])                                       
1309            valuesdict = {
1310                'wtFactor':1.0,
1311                'Dummy':False,
1312                'ranId':ran.randint(0,sys.maxint),
1313                }
1314            rd.Sample['ranId'] = valuesdict['ranId'] # this should be removed someday
1315            self.PatternTree.SetItemPyData(Id,[valuesdict,rd.powderdata])
1316            self.PatternTree.SetItemPyData(
1317                self.PatternTree.AppendItem(Id,text='Comments'),
1318                rd.comments)
1319            Tmin = min(rd.powderdata[0])
1320            Tmax = max(rd.powderdata[0])
1321            self.PatternTree.SetItemPyData(
1322                self.PatternTree.AppendItem(Id,text='Limits'),
1323                rd.pwdparms.get('Limits',[(Tmin,Tmax),[Tmin,Tmax]])
1324                )
1325            self.PatternId = G2gd.GetPatternTreeItemId(self,Id,'Limits')
1326            self.PatternTree.SetItemPyData(
1327                self.PatternTree.AppendItem(Id,text='Background'),
1328                rd.pwdparms.get('Background',
1329                    [['chebyschev',True,3,1.0,0.0,0.0],{'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
1330                    )
1331            self.PatternTree.SetItemPyData(
1332                self.PatternTree.AppendItem(Id,text='Instrument Parameters'),
1333                [Iparm1,Iparm2])
1334            self.PatternTree.SetItemPyData(
1335                self.PatternTree.AppendItem(Id,text='Sample Parameters'),
1336                rd.Sample)
1337            self.PatternTree.SetItemPyData(
1338                self.PatternTree.AppendItem(Id,text='Peak List')
1339                ,{'peaks':[],'sigDict':{}})
1340            self.PatternTree.SetItemPyData(
1341                self.PatternTree.AppendItem(Id,text='Index Peak List'),
1342                [[],[]])
1343            self.PatternTree.SetItemPyData(
1344                self.PatternTree.AppendItem(Id,text='Unit Cells List'),
1345                [])
1346            self.PatternTree.SetItemPyData(
1347                self.PatternTree.AppendItem(Id,text='Reflection Lists'),
1348                {})
1349            newHistList.append(HistName)
1350        else:
1351            self.EnablePlot = True
1352            self.PatternTree.Expand(Id)
1353            self.PatternTree.SelectItem(Id)
1354           
1355        if not newHistList: return # somehow, no new histograms
1356        # make a list of phase names
1357        phaseRIdList,usedHistograms = self.GetPhaseInfofromTree()
1358        phaseNameList = usedHistograms.keys() # phase names in use
1359        if not phaseNameList: return # no phases yet, nothing to do
1360        header = 'Select phase(s) to add the new\npowder dataset(s) to:'
1361        for Name in newHistList:
1362            header += '\n  '+str(Name)
1363
1364        result = G2gd.ItemSelector(phaseNameList,self,header,header='Add to phase(s)',multiple=True)
1365        if not result: return
1366        # connect new phases to histograms
1367        sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
1368        if not sub:
1369            raise Exception('ERROR -- why are there no phases here?')
1370        item, cookie = self.PatternTree.GetFirstChild(sub)
1371        iph = -1
1372        while item: # loop over (new) phases
1373            iph += 1
1374            phaseName = self.PatternTree.GetItemText(item)
1375            data = self.PatternTree.GetItemPyData(item)
1376            item, cookie = self.PatternTree.GetNextChild(sub, cookie)
1377            if iph not in result: continue
1378            generalData = data['General']
1379            SGData = generalData['SGData']
1380            UseList = data['Histograms']
1381            NShkl = len(G2spc.MustrainNames(SGData))
1382            NDij = len(G2spc.HStrainNames(SGData))
1383            for histoName in newHistList:
1384                UseList[histoName] = SetDefaultDData('PWDR',histoName,NShkl=NShkl,NDij=NDij)
1385                Id = G2gd.GetPatternTreeItemId(self,self.root,histoName)
1386                refList = self.PatternTree.GetItemPyData(
1387                    G2gd.GetPatternTreeItemId(self,Id,'Reflection Lists'))
1388                refList[generalData['Name']] = []
1389        return # success
1390
1391    def OnDummyPowder(self,event):
1392        '''Called in response to Import/Powder Data/Simulate menu item
1393        to create a Dummy powder diffraction data set.
1394
1395        Reads an instrument parameter file and then gets input from the user
1396        '''
1397        # get a list of existing histograms
1398        PWDRlist = []
1399        if self.PatternTree.GetCount():
1400            item, cookie = self.PatternTree.GetFirstChild(self.root)
1401            while item:
1402                name = self.PatternTree.GetItemText(item)
1403                if name.startswith('PWDR ') and name not in PWDRlist:
1404                    PWDRlist.append(name)
1405                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1406        # Initialize a base class reader
1407        rd = G2IO.ImportPowderData(
1408            extensionlist=tuple(),
1409            strictExtension=False,
1410            formatName = 'Simulate dataset',
1411            longFormatName = 'Compute a simulated pattern')
1412        rd.powderentry[0] = '' # no filename
1413        # #self.powderentry[1] = pos # bank offset (N/A here)
1414        rd.powderentry[2] = 1 # only one bank
1415        rd.comments.append('This is a dummy dataset for powder pattern simulation')
1416        self.CheckNotebook()
1417        Iparm = None
1418        lastIparmfile = ''
1419        lastdatafile = ''
1420        self.zipfile = None
1421        # get instrument parameters for it
1422        Iparm1,Iparm2 = self.GetPowderIparm(rd, Iparm, lastIparmfile, lastdatafile)
1423        if 'T' in Iparm1['Type'][0]:
1424            print('TOF simulation not supported yet')
1425            return False
1426        else:
1427            # need to get name, 2theta start, end, step
1428            rd.idstring = ' CW'
1429            if 'X' in Iparm1['Type'][0]:
1430                rd.idstring = 'CW x-ray simulation'
1431            else:
1432                rd.idstring = 'CW neutron simulation'
1433            # base initial range on wavelength
1434            wave = Iparm1.get('Lam')
1435            if wave:
1436                wave = wave[0]
1437            else:
1438                wave = Iparm1.get('Lam1')
1439                if wave:
1440                    wave = wave[0]
1441        N = 0
1442        while (N < 3): # insist on a dataset with a few points
1443            names = ('dataset name', 'start angle', 'end angle', 'step size')
1444            if not wave or wave < 1.0:
1445                inp = [rd.idstring, 10.,40.,0.005] # see names for what's what
1446            else:
1447                inp = [rd.idstring, 10.,80.,0.01] # see names for what's what
1448            dlg = G2gd.ScrolledMultiEditor(
1449                self,[inp] * len(inp),range(len(inp)),names,
1450                header='Enter simulation name and range',
1451                minvals=(None,0.001,0.001,0.0001),
1452                maxvals=(None,180.,180.,.1),
1453                sizevals=((225,-1),)
1454                )
1455            dlg.CenterOnParent()
1456            if dlg.ShowModal() == wx.ID_OK:
1457                if inp[1] > inp[2]:
1458                    end,start,step = inp[1:]
1459                else:               
1460                    start,end,step = inp[1:]
1461                step = abs(step)
1462            else:
1463                return False
1464            N = int((end-start)/step)+1
1465            x = np.linspace(start,end,N,True)
1466            N = len(x)
1467        rd.powderdata = [
1468            np.array(x), # x-axis values
1469            np.zeros_like(x), # powder pattern intensities
1470            np.ones_like(x), # 1/sig(intensity)^2 values (weights)
1471            np.zeros_like(x), # calc. intensities (zero)
1472            np.zeros_like(x), # calc. background (zero)
1473            np.zeros_like(x), # obs-calc profiles
1474            ]
1475        Tmin = rd.powderdata[0][0]
1476        Tmax = rd.powderdata[0][-1]
1477        # data are read, now store them in the tree
1478        HistName = inp[0]
1479        HistName = 'PWDR '+HistName
1480        HistName = G2obj.MakeUniqueLabel(HistName,PWDRlist)  # make new histogram names unique
1481        Id = self.PatternTree.AppendItem(parent=self.root,text=HistName)
1482        valuesdict = {
1483            'wtFactor':1.0,
1484            'Dummy':True,
1485            'ranId':ran.randint(0,sys.maxint),
1486            }
1487        self.PatternTree.SetItemPyData(Id,[valuesdict,rd.powderdata])
1488        self.PatternTree.SetItemPyData(
1489            self.PatternTree.AppendItem(Id,text='Comments'),
1490            rd.comments)
1491        self.PatternTree.SetItemPyData(
1492            self.PatternTree.AppendItem(Id,text='Limits'),
1493            [(Tmin,Tmax),[Tmin,Tmax]])
1494        self.PatternId = G2gd.GetPatternTreeItemId(self,Id,'Limits')
1495        self.PatternTree.SetItemPyData(
1496            self.PatternTree.AppendItem(Id,text='Background'),
1497            [['chebyschev',True,3,1.0,0.0,0.0],
1498             {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
1499        self.PatternTree.SetItemPyData(
1500            self.PatternTree.AppendItem(Id,text='Instrument Parameters'),
1501            [Iparm1,Iparm2])
1502        self.PatternTree.SetItemPyData(
1503            self.PatternTree.AppendItem(Id,text='Sample Parameters'),
1504            rd.Sample)
1505        self.PatternTree.SetItemPyData(
1506            self.PatternTree.AppendItem(Id,text='Peak List')
1507            ,{'peaks':[],'sigDict':{}})
1508        self.PatternTree.SetItemPyData(
1509            self.PatternTree.AppendItem(Id,text='Index Peak List'),
1510            [[],[]])
1511        self.PatternTree.SetItemPyData(
1512            self.PatternTree.AppendItem(Id,text='Unit Cells List'),
1513            [])
1514        self.PatternTree.SetItemPyData(
1515            self.PatternTree.AppendItem(Id,text='Reflection Lists'),
1516            {})
1517        self.PatternTree.Expand(Id)
1518        self.PatternTree.SelectItem(Id)
1519        print('Added simulation powder data '+str(HistName)+ 
1520              ' with parameters from '+str(rd.instmsg))
1521
1522        # make a list of phase names
1523        phaseRIdList,usedHistograms = self.GetPhaseInfofromTree()
1524        phaseNameList = usedHistograms.keys() # phase names in use
1525        if not phaseNameList: return # no phases yet, nothing to do
1526        header = 'Select phase(s) to add the new\npowder simulation (dummy) dataset to:'
1527        result = G2gd.ItemSelector(phaseNameList,self,header,header='Add to phase(s)',multiple=True)
1528        if not result: return
1529        # connect new phases to histograms
1530        sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
1531        if not sub:
1532            raise Exception('ERROR -- why are there no phases here?')
1533        item, cookie = self.PatternTree.GetFirstChild(sub)
1534        iph = -1
1535        while item: # loop over (new) phases
1536            iph += 1
1537            phaseName = self.PatternTree.GetItemText(item)
1538            data = self.PatternTree.GetItemPyData(item)
1539            item, cookie = self.PatternTree.GetNextChild(sub, cookie)
1540            if iph not in result: continue
1541            generalData = data['General']
1542            SGData = generalData['SGData']
1543            UseList = data['Histograms']
1544            NShkl = len(G2spc.MustrainNames(SGData))
1545            NDij = len(G2spc.HStrainNames(SGData))
1546            UseList[HistName] = SetDefaultDData('PWDR',histoName,NShkl=NShkl,NDij=NDij)
1547            Id = G2gd.GetPatternTreeItemId(self,self.root,HistName)
1548            refList = self.PatternTree.GetItemPyData(
1549                G2gd.GetPatternTreeItemId(self,Id,'Reflection Lists'))
1550            refList[generalData['Name']] = []
1551        return # success
1552
1553    def _Add_ImportMenu_smallangle(self,parent):
1554        '''configure the Small Angle Data menus accord to the readers found in _init_Imports
1555        '''
1556        submenu = wx.Menu()
1557        item = parent.AppendMenu(wx.ID_ANY, 'Small Angle Data',
1558            submenu, help='Import small angle data')
1559        for reader in self.ImportSmallAngleReaderlist:
1560            item = submenu.Append(wx.ID_ANY,help=reader.longFormatName,
1561                kind=wx.ITEM_NORMAL,text='from '+reader.formatName+' file')
1562            self.ImportMenuId[item.GetId()] = reader
1563            self.Bind(wx.EVT_MENU, self.OnImportSmallAngle, id=item.GetId())
1564        # item = submenu.Append(wx.ID_ANY,
1565        #     help='Import small angle data, use file to try to determine format',
1566        #     kind=wx.ITEM_NORMAL,text='guess format from file')
1567        # self.Bind(wx.EVT_MENU, self.OnImportSmallAngle, id=item.GetId())
1568
1569    def OnImportSmallAngle(self,event):
1570        '''Called in response to an Import/Small Angle Data/... menu item
1571        to read a small angle diffraction data set.
1572        dict self.ImportMenuId is used to look up the specific
1573        reader item associated with the menu item, which will be
1574        None for the last menu item, which is the "guess" option
1575        where all appropriate formats will be tried.
1576
1577        '''
1578       
1579        def GetSASDIparm(reader):
1580            parm = reader.instdict
1581            Iparm = {'Type':[parm['type'],parm['type'],0],'Lam':[parm['wave'],
1582                parm['wave'],0],'Azimuth':[0.,0.,0]}           
1583            return Iparm,{}
1584           
1585        # get a list of existing histograms
1586        SASDlist = []
1587        if self.PatternTree.GetCount():
1588            item, cookie = self.PatternTree.GetFirstChild(self.root)
1589            while item:
1590                name = self.PatternTree.GetItemText(item)
1591                if name.startswith('SASD ') and name not in SASDlist:
1592                    SASDlist.append(name)
1593                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1594        # look up which format was requested
1595        reqrdr = self.ImportMenuId.get(event.GetId()) 
1596        rdlist = self.OnImportGeneric(
1597            reqrdr,self.ImportSmallAngleReaderlist,'Small Angle Data',multiple=True)
1598        if len(rdlist) == 0: return
1599        self.CheckNotebook()
1600        Iparm = None
1601        lastdatafile = ''
1602        newHistList = []
1603        self.EnablePlot = False
1604        for rd in rdlist:
1605            lastdatafile = rd.smallangleentry[0]
1606            HistName = rd.idstring
1607            HistName = 'SASD '+HistName
1608            # make new histogram names unique
1609            HistName = G2obj.MakeUniqueLabel(HistName,SASDlist)
1610            print 'Read small angle data '+str(HistName)+ \
1611                ' from file '+str(self.lastimport)
1612            # data are read, now store them in the tree
1613            Id = self.PatternTree.AppendItem(parent=self.root,text=HistName)
1614            Iparm1,Iparm2 = GetSASDIparm(rd)
1615#            if 'T' in Iparm1['Type'][0]:
1616#                if not rd.clockWd and rd.GSAS:
1617#                    rd.powderdata[0] *= 100.        #put back the CW centideg correction
1618#                cw = np.diff(rd.powderdata[0])
1619#                rd.powderdata[0] = rd.powderdata[0][:-1]+cw/2.
1620#                rd.powderdata[1] = rd.powderdata[1][:-1]/cw
1621#                rd.powderdata[2] = rd.powderdata[2][:-1]*cw**2  #1/var=w at this point
1622#                if 'Itype' in Iparm2:
1623#                    Ibeg = np.searchsorted(rd.powderdata[0],Iparm2['Tminmax'][0])
1624#                    Ifin = np.searchsorted(rd.powderdata[0],Iparm2['Tminmax'][1])
1625#                    rd.powderdata[0] = rd.powderdata[0][Ibeg:Ifin]
1626#                    YI,WYI = G2pwd.calcIncident(Iparm2,rd.powderdata[0])
1627#                    rd.powderdata[1] = rd.powderdata[1][Ibeg:Ifin]/YI
1628#                    var = 1./rd.powderdata[2][Ibeg:Ifin]
1629#                    var += WYI*rd.powderdata[1]**2
1630#                    var /= YI**2
1631#                    rd.powderdata[2] = 1./var
1632#                rd.powderdata[3] = np.zeros_like(rd.powderdata[0])                                       
1633#                rd.powderdata[4] = np.zeros_like(rd.powderdata[0])                                       
1634#                rd.powderdata[5] = np.zeros_like(rd.powderdata[0])                                       
1635            Tmin = min(rd.smallangledata[0])
1636            Tmax = max(rd.smallangledata[0])
1637            valuesdict = {
1638                'wtFactor':1.0,
1639                'Dummy':False,
1640                'ranId':ran.randint(0,sys.maxint),
1641                }
1642            rd.Sample['ranId'] = valuesdict['ranId'] # this should be removed someday
1643            self.PatternTree.SetItemPyData(Id,[valuesdict,rd.smallangledata])
1644            self.PatternTree.SetItemPyData(
1645                self.PatternTree.AppendItem(Id,text='Comments'),
1646                rd.comments)
1647            self.PatternTree.SetItemPyData(
1648                self.PatternTree.AppendItem(Id,text='Limits'),
1649                [(Tmin,Tmax),[Tmin,Tmax]])
1650            self.PatternId = G2gd.GetPatternTreeItemId(self,Id,'Limits')
1651            self.PatternTree.SetItemPyData(
1652                self.PatternTree.AppendItem(Id,text='Instrument Parameters'),
1653                [Iparm1,Iparm2])
1654            self.PatternTree.SetItemPyData(
1655                self.PatternTree.AppendItem(Id,text='Substances'),G2pdG.SetDefaultSubstances())
1656            self.PatternTree.SetItemPyData(
1657                self.PatternTree.AppendItem(Id,text='Sample Parameters'),
1658                rd.Sample)
1659            self.PatternTree.SetItemPyData(
1660                self.PatternTree.AppendItem(Id,text='Models'),G2pdG.SetDefaultSASDModel())
1661            newHistList.append(HistName)
1662        else:
1663            self.EnablePlot = True
1664            self.PatternTree.Expand(Id)
1665            self.PatternTree.SelectItem(Id)
1666           
1667        if not newHistList: return # somehow, no new histograms
1668        return # success
1669
1670    def OnMacroRecordStatus(self,event,setvalue=None):
1671        '''Called when the record macro menu item is used which toggles the
1672        value. Alternately a value to be set can be provided. Note that this
1673        routine is made more complex because on the Mac there are lots of menu
1674        items (listed in self.MacroStatusList) and this loops over all of them.
1675        '''
1676        nextvalue = log.ShowLogStatus() != True
1677        if setvalue is not None:
1678            nextvalue = setvalue
1679        if nextvalue:
1680            log.LogOn()
1681            set2 = True
1682        else:
1683            log.LogOff()
1684            set2 = False
1685        for menuitem in self.MacroStatusList:
1686            menuitem.Check(set2)
1687
1688    def _init_Macro(self):
1689        '''Define the items in the macro menu.
1690        '''
1691        menu = self.MacroMenu
1692        item = menu.Append(
1693                help='Start or stop recording of menu actions, etc.', id=wx.ID_ANY,
1694                kind=wx.ITEM_CHECK,text='Record actions')
1695        self.MacroStatusList.append(item)
1696        item.Check(log.ShowLogStatus())
1697        self.Bind(wx.EVT_MENU, self.OnMacroRecordStatus, item)
1698
1699        # this may only be of value for development work
1700        item = menu.Append(
1701            help='Show logged commands', id=wx.ID_ANY,
1702            kind=wx.ITEM_NORMAL,text='Show log')
1703        def OnShowLog(event):
1704            print 70*'='
1705            print 'List of logged actions'
1706            for i,line in enumerate(log.G2logList):
1707                if line: print i,line
1708            print 70*'='
1709        self.Bind(wx.EVT_MENU, OnShowLog, item)
1710
1711        item = menu.Append(
1712            help='Clear logged commands', id=wx.ID_ANY,
1713            kind=wx.ITEM_NORMAL,text='Clear log')
1714        def OnClearLog(event): log.G2logList=[None]
1715        self.Bind(wx.EVT_MENU, OnClearLog, item)
1716       
1717        item = menu.Append(
1718            help='Save logged commands to file', id=wx.ID_ANY,
1719            kind=wx.ITEM_NORMAL,text='Save log')
1720        def OnSaveLog(event):
1721            import cPickle
1722            defnam = os.path.splitext(
1723                os.path.split(self.GSASprojectfile)[1]
1724                )[0]+'.gcmd'
1725            dlg = wx.FileDialog(self,
1726                'Choose an file to save past actions', '.', defnam, 
1727                'GSAS-II cmd output (*.gcmd)|*.gcmd',
1728                wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1729            dlg.CenterOnParent()
1730            try:
1731                if dlg.ShowModal() == wx.ID_OK:
1732                    filename = dlg.GetPath()
1733                    # make sure extension is correct
1734                    filename = os.path.splitext(filename)[0]+'.gcmd'
1735                else:
1736                    filename = None
1737            finally:
1738                dlg.Destroy()
1739            if filename:
1740                fp = open(filename,'wb')
1741                fp.write(str(len(log.G2logList)-1)+'\n')
1742                for item in log.G2logList:
1743                    if item: cPickle.dump(item,fp)
1744                fp.close()
1745        self.Bind(wx.EVT_MENU, OnSaveLog, item)
1746
1747        item = menu.Append(
1748            help='Load logged commands from file', id=wx.ID_ANY,
1749            kind=wx.ITEM_NORMAL,text='Load log')
1750        def OnLoadLog(event):
1751            # this appends. Perhaps we should ask to clear?
1752            import cPickle
1753            defnam = os.path.splitext(
1754                os.path.split(self.GSASprojectfile)[1]
1755                )[0]+'.gcmd'
1756            dlg = wx.FileDialog(self,
1757                'Choose an file to read saved actions', '.', defnam, 
1758                'GSAS-II cmd output (*.gcmd)|*.gcmd',
1759                wx.OPEN|wx.CHANGE_DIR)
1760            dlg.CenterOnParent()
1761            try:
1762                if dlg.ShowModal() == wx.ID_OK:
1763                    filename = dlg.GetPath()
1764                    # make sure extension is correct
1765                    filename = os.path.splitext(filename)[0]+'.gcmd'
1766                else:
1767                    filename = None
1768            finally:
1769                dlg.Destroy()
1770            if filename and os.path.exists(filename):
1771                fp = open(filename,'rb')
1772                lines = fp.readline()
1773                for i in range(int(lines)):
1774                    log.G2logList.append(cPickle.load(fp))
1775                fp.close()
1776        self.Bind(wx.EVT_MENU, OnLoadLog, item)
1777
1778        item = menu.Append(
1779            help='Replay saved commands', id=wx.ID_ANY,
1780            kind=wx.ITEM_NORMAL,text='Replay log')
1781        self.Bind(wx.EVT_MENU, log.ReplayLog, item)
1782
1783    def _init_Exports(self,menu):
1784        '''Find exporter routines and add them into menus
1785        '''
1786        # set up the top-level menus
1787        projectmenu = wx.Menu()
1788        item = menu.AppendMenu(
1789            wx.ID_ANY, 'Entire project as',
1790            projectmenu, help='Export entire project')
1791
1792        phasemenu = wx.Menu()
1793        item = menu.AppendMenu(
1794            wx.ID_ANY, 'Phase as',
1795            phasemenu, help='Export phase or sometimes phases')
1796
1797        powdermenu = wx.Menu()
1798        item = menu.AppendMenu(
1799            wx.ID_ANY, 'Powder data as',
1800            powdermenu, help='Export powder diffraction histogram(s)')
1801
1802        singlemenu = wx.Menu()
1803        item = menu.AppendMenu(
1804            wx.ID_ANY, 'Single crystal data as',
1805            singlemenu, help='Export single crystal histogram(s)')
1806
1807        imagemenu = wx.Menu()
1808        item = menu.AppendMenu(
1809            wx.ID_ANY, 'Image data as',
1810            imagemenu, help='Export powder image(s) data')
1811
1812        mapmenu = wx.Menu()
1813        item = menu.AppendMenu(
1814            wx.ID_ANY, 'Maps as',
1815            mapmenu, help='Export density map(s)')
1816
1817        # pdfmenu = wx.Menu()
1818        # item = menu.AppendMenu(
1819        #     wx.ID_ANY, 'PDFs as',
1820        #     pdfmenu, help='Export pair distribution function(s)')
1821
1822        # find all the exporter files
1823        pathlist = sys.path
1824        filelist = []
1825        for path in pathlist:
1826            for filename in glob.iglob(os.path.join(path,"G2export*.py")):
1827                filelist.append(filename)   
1828        filelist = sorted(list(set(filelist))) # remove duplicates
1829        exporterlist = []
1830        # go through the routines and import them, saving objects that
1831        # have export routines (method Exporter)
1832        for filename in filelist:
1833            path,rootname = os.path.split(filename)
1834            pkg = os.path.splitext(rootname)[0]
1835            try:
1836                fp = None
1837                fp, fppath,desc = imp.find_module(pkg,[path,])
1838                pkg = imp.load_module(pkg,fp,fppath,desc)
1839                for clss in inspect.getmembers(pkg): # find classes defined in package
1840                    if clss[0].startswith('_'): continue
1841                    if inspect.isclass(clss[1]):
1842                        # check if we have the required methods
1843                        for m in 'Exporter','loadParmDict':
1844                            if not hasattr(clss[1],m): break
1845                            if not callable(getattr(clss[1],m)): break
1846                        else:
1847                            exporter = clss[1](self) # create an export instance
1848                            exporterlist.append(exporter)
1849            except AttributeError:
1850                print 'Import_'+errprefix+': Attribute Error'+str(filename)
1851                pass
1852            except ImportError:
1853                print 'Import_'+errprefix+': Error importing file'+str(filename)
1854                pass
1855            if fp: fp.close()
1856        # Add submenu item(s) for each Exporter by its self-declared type (can be more than one)
1857        for obj in exporterlist:
1858            #print 'exporter',obj
1859            for typ in obj.exporttype:
1860                if typ == "project":
1861                    submenu = projectmenu
1862                elif typ == "phase":
1863                    submenu = phasemenu
1864                elif typ == "powder":
1865                    submenu = powdermenu
1866                elif typ == "single":
1867                    submenu = singlemenu
1868                elif typ == "image":
1869                    submenu = imagemenu
1870                elif typ == "map":
1871                    submenu = mapmenu
1872                # elif typ == "pdf":
1873                #     submenu = pdfmenu
1874                else:
1875                    print("Error, unknown type in "+str(obj))
1876                    break
1877                item = submenu.Append(
1878                    wx.ID_ANY,
1879                    help=obj.longFormatName,
1880                    kind=wx.ITEM_NORMAL,
1881                    text=obj.formatName)
1882                self.Bind(wx.EVT_MENU, obj.Exporter, id=item.GetId())
1883                self.ExportLookup[item.GetId()] = typ # lookup table for submenu item
1884               
1885        #code to debug an Exporter. hard-coded the routine below, to allow a reload before use
1886        # def DebugExport(event):
1887        #      print 'start reload'
1888        #      reload(G2IO)
1889        #      import G2export_pwdr as dev
1890        #      reload(dev)
1891        #      dev.ExportPowderFXYE(self).Exporter(event)
1892        # item = menu.Append(
1893        #     wx.ID_ANY,kind=wx.ITEM_NORMAL,
1894        #     help="debug exporter",text="test Export FXYE")
1895        # self.Bind(wx.EVT_MENU, DebugExport, id=item.GetId())
1896        # # #self.ExportLookup[item.GetId()] = 'image'
1897        # self.ExportLookup[item.GetId()] = 'powder'
1898
1899    def _Add_ExportMenuItems(self,parent):
1900        # item = parent.Append(
1901        #     help='Select PWDR item to enable',id=wx.ID_ANY,
1902        #     kind=wx.ITEM_NORMAL,
1903        #     text='Export Powder Patterns...')
1904        # self.ExportPattern.append(item)
1905        # item.Enable(False)
1906        # self.Bind(wx.EVT_MENU, self.OnExportPatterns, id=item.GetId())
1907
1908        item = parent.Append(
1909            help='',id=wx.ID_ANY,
1910            kind=wx.ITEM_NORMAL,
1911            text='Export All Peak Lists...')
1912        self.ExportPeakList.append(item)
1913        item.Enable(True)
1914        self.Bind(wx.EVT_MENU, self.OnExportPeakList, id=item.GetId())
1915
1916        item = parent.Append(
1917            help='',id=wx.ID_ANY,
1918            kind=wx.ITEM_NORMAL,
1919            text='Export HKLs...')
1920        self.ExportHKL.append(item)
1921        self.Bind(wx.EVT_MENU, self.OnExportHKL, id=item.GetId())
1922
1923        item = parent.Append(
1924            help='Select PDF item to enable',
1925            id=wx.ID_ANY,
1926            kind=wx.ITEM_NORMAL,
1927            text='Export PDF...')
1928        self.ExportPDF.append(item)
1929        item.Enable(False)
1930        self.Bind(wx.EVT_MENU, self.OnExportPDF, id=item.GetId())
1931
1932    def FillMainMenu(self,menubar):
1933        '''Define contents of the main GSAS-II menu for the (main) data tree window.
1934        For the mac, this is also called for the data item windows as well so that
1935        the main menu items are data menu as well.
1936        '''
1937        File = wx.Menu(title='')
1938        menubar.Append(menu=File, title='&File')
1939        self._Add_FileMenuItems(File)
1940        Data = wx.Menu(title='')
1941        menubar.Append(menu=Data, title='Data')
1942        self._Add_DataMenuItems(Data)
1943        Calculate = wx.Menu(title='')       
1944        menubar.Append(menu=Calculate, title='&Calculate')
1945        self._Add_CalculateMenuItems(Calculate)
1946        Import = wx.Menu(title='')       
1947        menubar.Append(menu=Import, title='Import')
1948        self._Add_ImportMenu_Phase(Import)
1949        self._Add_ImportMenu_powder(Import)
1950        self._Add_ImportMenu_Sfact(Import)
1951        self._Add_ImportMenu_smallangle(Import)
1952        #======================================================================
1953        # Code to help develop/debug an importer, much is hard-coded below
1954        # but module is reloaded before each use, allowing faster testing
1955        # def DebugImport(event):
1956        #     print 'start reload'
1957        #     import G2phase_ISO as dev
1958        #     reload(dev)
1959        #     rd = dev.ISODISTORTPhaseReader()
1960        #     self.ImportMenuId[event.GetId()] = rd
1961        #     self.OnImportPhase(event)
1962            # or ----------------------------------------------------------------------
1963            #self.OnImportGeneric(rd,[],'test of ISODISTORTPhaseReader')
1964            # special debug code
1965            # or ----------------------------------------------------------------------
1966            # filename = '/Users/toby/projects/branton/subgroup_cif.txt'
1967            # fp = open(filename,'Ur')
1968            # if not rd.ContentsValidator(fp):
1969            #     print 'not validated'
1970            #     # make a list of used phase ranId's
1971            # phaseRIdList = []
1972            # sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
1973            # if sub:
1974            #     item, cookie = self.PatternTree.GetFirstChild(sub)
1975            #     while item:
1976            #         phaseName = self.PatternTree.GetItemText(item)
1977            #         ranId = self.PatternTree.GetItemPyData(item).get('ranId')
1978            #         if ranId: phaseRIdList.append(ranId)
1979            #         item, cookie = self.PatternTree.GetNextChild(sub, cookie)
1980            # if rd.Reader(filename,fp,usedRanIdList=phaseRIdList):
1981            #     print 'read OK'
1982        # item = Import.Append(
1983        #     wx.ID_ANY,kind=wx.ITEM_NORMAL,
1984        #     help="debug importer",text="test importer")
1985        # self.Bind(wx.EVT_MENU, DebugImport, id=item.GetId())
1986        #======================================================================
1987        self.ExportMenu = wx.Menu(title='')
1988        menubar.Append(menu=self.ExportMenu, title='Export')
1989        self._init_Exports(self.ExportMenu)
1990        self._Add_ExportMenuItems(self.ExportMenu)
1991        if GSASIIpath.GetConfigValue('Enable_logging'):
1992            self.MacroMenu = wx.Menu(title='')
1993            menubar.Append(menu=self.MacroMenu, title='Macro')
1994            self._init_Macro()
1995        HelpMenu=G2gd.MyHelp(self,helpType='Data tree',
1996            morehelpitems=[('&Tutorials','Tutorials')])
1997        menubar.Append(menu=HelpMenu,title='&Help')
1998
1999    def _init_ctrls(self, parent):
2000        wx.Frame.__init__(self, name='GSASII', parent=parent,
2001            size=wx.Size(400, 250),style=wx.DEFAULT_FRAME_STYLE, title='GSAS-II data tree')
2002        clientSize = wx.ClientDisplayRect()
2003        Size = self.GetSize()
2004        xPos = clientSize[2]-Size[0]
2005        self.SetPosition(wx.Point(xPos,clientSize[1]))
2006        self._init_Imports()
2007        #initialize Menu item objects (these contain lists of menu items that are enabled or disabled)
2008        self.MakePDF = []
2009        self.Refine = []
2010        self.SeqRefine = [] # pointer(s) to Sequential Refinement menu objects
2011        #self.ExportPattern = []
2012        self.ExportPeakList = []
2013        self.ExportHKL = []
2014        self.ExportPDF = []
2015        self.ExportPhase = []
2016        self.ExportCIF = []
2017        #
2018        self.GSASIIMenu = wx.MenuBar()
2019        # create a list of all dataframe menus (appended in PrefillDataMenu)
2020        self.dataMenuBars = [self.GSASIIMenu]
2021        self.MacroStatusList = []
2022        self.FillMainMenu(self.GSASIIMenu)
2023        self.SetMenuBar(self.GSASIIMenu)
2024        self.Bind(wx.EVT_SIZE, self.OnSize)
2025        self.Status = self.CreateStatusBar()
2026        self.mainPanel = wx.Panel(self,-1)
2027       
2028        wxID_PATTERNTREE = wx.NewId()
2029        #self.PatternTree = wx.TreeCtrl(id=wxID_PATTERNTREE, # replaced for logging
2030        self.PatternTree = G2gd.G2TreeCtrl(id=wxID_PATTERNTREE,
2031            parent=self.mainPanel, pos=wx.Point(0, 0),style=wx.TR_DEFAULT_STYLE )
2032        self.PatternTree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnPatternTreeSelChanged)
2033        self.PatternTree.Bind(wx.EVT_TREE_ITEM_COLLAPSED,
2034            self.OnPatternTreeItemCollapsed, id=wxID_PATTERNTREE)
2035        self.PatternTree.Bind(wx.EVT_TREE_ITEM_EXPANDED,
2036            self.OnPatternTreeItemExpanded, id=wxID_PATTERNTREE)
2037        self.PatternTree.Bind(wx.EVT_TREE_DELETE_ITEM,
2038            self.OnPatternTreeItemDelete, id=wxID_PATTERNTREE)
2039        self.PatternTree.Bind(wx.EVT_TREE_KEY_DOWN,
2040            self.OnPatternTreeKeyDown, id=wxID_PATTERNTREE)
2041        self.PatternTree.Bind(wx.EVT_TREE_BEGIN_RDRAG,
2042            self.OnPatternTreeBeginRDrag, id=wxID_PATTERNTREE)       
2043        self.PatternTree.Bind(wx.EVT_TREE_END_DRAG,
2044            self.OnPatternTreeEndDrag, id=wxID_PATTERNTREE)       
2045        #self.root = self.PatternTree.AddRoot('Loaded Data: ')
2046        self.root = self.PatternTree.root
2047        plotFrame = wx.Frame(None,-1,'GSASII Plots',size=wx.Size(700,600), \
2048            style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX)
2049        self.G2plotNB = G2plt.G2PlotNoteBook(plotFrame)
2050        plotFrame.Show()
2051       
2052        self.dataDisplay = None
2053       
2054    def __init__(self, parent):
2055        self.ExportLookup = {}
2056        self._init_ctrls(parent)
2057        self.Image = wx.Image(
2058            os.path.join(GSASIIpath.path2GSAS2,'gsas2.ico'),
2059            wx.BITMAP_TYPE_ICO)
2060        if "wxMSW" in wx.PlatformInfo:
2061            img = self.Image.Scale(16, 16).ConvertToBitmap()
2062        elif "wxGTK" in wx.PlatformInfo:
2063            img = self.Image.Scale(22, 22).ConvertToBitmap()
2064        else:
2065            img = self.Image.ConvertToBitmap()
2066        self.SetIcon(wx.IconFromBitmap(img))
2067        self.Bind(wx.EVT_CLOSE, self.ExitMain)
2068        # various defaults
2069        self.oldFocus = None
2070        self.GSASprojectfile = ''
2071        self.dirname = os.path.expanduser('~')       #start in the users home directory by default; may be meaningless
2072        self.exportDir = None  # the last directory used for exports, if any.
2073        self.undofile = ''
2074        self.TreeItemDelete = False
2075        self.Offset = [0.0,0.0]
2076        self.delOffset = .02
2077        self.refOffset = -1.0
2078        self.refDelt = .01
2079        self.Weight = False
2080        self.IparmName = ''  # to be removed when SelectPowderData & GetInstrumentFile is
2081        self.IfPlot = False
2082        self.PatternId = 0
2083        self.PickId = 0
2084        self.PeakTable = []
2085        self.LimitsTable = []
2086        self.ifX20 = True   #use M20 /= (1+X20)
2087        self.HKL = []
2088        self.Lines = []
2089        self.itemPicked = None
2090        self.dataFrame = None
2091        self.Interpolate = 'nearest'
2092        self.ContourColor = 'Paired'
2093        self.VcovColor = 'RdYlGn'
2094        self.RamaColor = 'Blues'
2095        self.Projection = 'equal area'
2096        self.logPlot = False
2097        self.qPlot = False
2098        self.dPlot = False
2099        self.sqPlot = False
2100        self.SqrtPlot = False
2101        self.ErrorBars = False
2102        self.Contour = False
2103        self.Legend = False
2104        self.SinglePlot = True
2105        self.SubBack = False
2106        self.seqReverse = False
2107        self.plotView = 0
2108        self.Image = 0
2109        self.oldImagefile = ''
2110        self.ImageZ = []
2111        self.Integrate = 0
2112        self.imageDefault = {}
2113        self.Sngl = False
2114        self.ifGetRing = False
2115        self.MaskKey = ''           #trigger for making image masks
2116        self.StrainKey = ''         #ditto for new strain d-zeros
2117        self.EnablePlot = True
2118        self.Tutorials = False      #used for changing default directory
2119        arg = sys.argv
2120        if len(arg) > 1 and arg[1]:
2121            self.GSASprojectfile = os.path.splitext(arg[1])[0]+'.gpx'
2122            self.dirname = os.path.dirname(arg[1])
2123            if self.dirname: os.chdir(self.dirname)
2124            try:
2125                G2IO.ProjFileOpen(self)
2126                self.PatternTree.Expand(self.root)
2127                for item in self.Refine: item.Enable(True)
2128                self.EnableSeqRefineMenu()
2129            except:
2130                print 'Error opening file',arg[1]
2131
2132    def OnSize(self,event):
2133        'Called when the main window is resized. Not sure why'
2134        w,h = self.GetClientSizeTuple()
2135        self.mainPanel.SetSize(wx.Size(w,h))
2136        self.PatternTree.SetSize(wx.Size(w,h))
2137                       
2138    def OnPatternTreeSelChanged(self, event):
2139        '''Called when a data tree item is selected'''
2140        if self.TreeItemDelete:
2141            self.TreeItemDelete = False
2142        else:
2143            pltNum = self.G2plotNB.nb.GetSelection()
2144            if pltNum >= 0:                         #to avoid the startup with no plot!
2145                pltPage = self.G2plotNB.nb.GetPage(pltNum)
2146                pltPlot = pltPage.figure
2147            item = event.GetItem()
2148            G2gd.MovePatternTreeToGrid(self,item)
2149            if self.oldFocus:
2150                self.oldFocus.SetFocus()
2151       
2152    def OnPatternTreeItemCollapsed(self, event):
2153        'Called when a tree item is collapsed'
2154        event.Skip()
2155
2156    def OnPatternTreeItemExpanded(self, event):
2157        'Called when a tree item is expanded'
2158        event.Skip()
2159       
2160    def OnPatternTreeItemDelete(self, event):
2161        'Called when a tree item is deleted -- not sure what this does'
2162        self.TreeItemDelete = True
2163
2164    def OnPatternTreeItemActivated(self, event):
2165        'Called when a tree item is activated'
2166        event.Skip()
2167       
2168    def OnPatternTreeBeginRDrag(self,event):
2169        # testing this - doesn't work! Binds commented out above
2170        event.Allow()
2171        self.BeginDragId = event.GetItem()
2172        self.ParentId = self.PatternTree.GetItemParent(self.BeginDragId)
2173        DragText = self.PatternTree.GetItemText(self.BeginDragId)
2174        self.DragData = [[DragText,self.PatternTree.GetItemPyData(self.BeginDragId)],]
2175        item, cookie = self.PatternTree.GetFirstChild(self.BeginDragId)
2176        while item:     #G2 data tree has no sub children under a child of a tree item
2177            name = self.PatternTree.GetItemText(item)
2178            self.DragData.append([name,self.PatternTree.GetItemPyData(item)])
2179            item, cookie = self.PatternTree.GetNextChild(self.BeginDragId, cookie)                           
2180       
2181    def OnPatternTreeEndDrag(self,event):
2182        # testing this - doesn't work! Binds commented out above
2183        event.Allow()
2184        self.EndDragId = event.GetItem()
2185        try:
2186            NewParent = self.PatternTree.GetItemParent(self.EndDragId)
2187        except:
2188            self.EndDragId = self.PatternTree.GetLastChild(self.root)
2189            NewParent = self.root
2190        if self.ParentId != NewParent:
2191            self.ErrorDialog('Drag not allowed','Wrong parent for item dragged')
2192        else:
2193            Name,Item = self.DragData[0]
2194            NewId = self.PatternTree.InsertItem(self.ParentId,self.EndDragId,Name,data=None)
2195            self.PatternTree.SetItemPyData(NewId,Item)
2196            for name,item in self.DragData[1:]:     #loop over children
2197                Id = self.PatternTree.AppendItem(parent=NewId,text=name)
2198                self.PatternTree.SetItemPyData(Id,item)
2199            self.PatternTree.Delete(self.BeginDragId)
2200            G2gd.MovePatternTreeToGrid(self,NewId)
2201       
2202    def OnPatternTreeKeyDown(self,event):
2203        'Allows stepping through the tree with the up/down arrow keys'
2204        key = event.GetKeyCode()
2205        item = self.PickId
2206        if type(item) is int: return # is this the toplevel in tree?
2207        if key == wx.WXK_UP:
2208            self.oldFocus = wx.Window.FindFocus()
2209            self.PatternTree.GetPrevSibling(item)
2210        elif key == wx.WXK_DOWN:
2211            self.oldFocus = wx.Window.FindFocus()
2212            self.PatternTree.GetNextSibling(item)
2213               
2214    def OnReadPowderPeaks(self,event):
2215        'Bound to menu Data/Read Powder Peaks -- still needed?'
2216        Cuka = 1.54052
2217        self.CheckNotebook()
2218        dlg = wx.FileDialog(self, 'Choose file with peak list', '.', '', 
2219            'peak files (*.txt)|*.txt|All files (*.*)|*.*',wx.OPEN|wx.CHANGE_DIR)
2220        try:
2221            if dlg.ShowModal() == wx.ID_OK:
2222                self.HKL = []
2223                self.powderfile = dlg.GetPath()
2224                comments,peaks = G2IO.GetPowderPeaks(self.powderfile)
2225                Id = self.PatternTree.AppendItem(parent=self.root,text='PKS '+os.path.basename(self.powderfile))
2226                data = ['PKS',Cuka,0.0]
2227                names = ['Type','Lam','Zero'] 
2228                codes = [0,0,0]
2229                inst = [G2IO.makeInstDict(names,data,codes),{}]
2230                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Instrument Parameters'),inst)
2231                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),comments)
2232                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Index Peak List'),[peaks,[]])
2233                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Unit Cells List'),[])             
2234                self.PatternTree.Expand(Id)
2235                self.PatternTree.SelectItem(Id)
2236                os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
2237        finally:
2238            dlg.Destroy()
2239                       
2240    def OnImageRead(self,event):
2241        'Called to read in an image in any known format'
2242        self.CheckNotebook()
2243        dlg = wx.FileDialog(
2244            self, 'Choose image files', '.', '',
2245            'Any supported image file (*.edf;*.tif;*.tiff;*.mar*;*.ge*;*.avg;*.sum;*.img;*.G2img;*.png)|'
2246            '*.edf;*.tif;*.tiff;*.mar*;*.ge*;*.avg;*.sum;*.img;*.G2img;*.png;*.zip|'
2247            'European detector file (*.edf)|*.edf|'
2248            'Any detector tif (*.tif;*.tiff)|*.tif;*.tiff|'
2249            'MAR file (*.mar*)|*.mar*|'
2250            'GE Image (*.ge*;*.avg;*.sum)|*.ge*;*.avg;*.sum|'
2251            'ADSC Image (*.img)|*.img|'
2252            'GSAS-II Image (*.G2img)|*.G2img|'
2253            'Portable Network Graphics image (*.png)|*.png|'
2254            'Zip archive (*.zip)|*.zip|'
2255            'All files (*.*)|*.*',
2256            wx.OPEN | wx.MULTIPLE|wx.CHANGE_DIR)
2257        try:
2258            if dlg.ShowModal() == wx.ID_OK:
2259                imagefiles = dlg.GetPaths()
2260                imagefiles.sort()
2261                for imagefile in imagefiles:
2262                    # if a zip file, open and extract
2263                    if os.path.splitext(imagefile)[1].lower() == '.zip':
2264                        extractedfile = G2IO.ExtractFileFromZip(imagefile,parent=self)
2265                        if extractedfile is not None and extractedfile != imagefile:
2266                            imagefile = extractedfile
2267                    Comments,Data,Npix,Image = G2IO.GetImageData(self,imagefile)
2268                    if Comments:
2269                        Id = self.PatternTree.AppendItem(parent=self.root,text='IMG '+os.path.basename(imagefile))
2270                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)
2271                        Imax = np.amax(Image)
2272                        Imin = max(0.0,np.amin(Image))          #force positive
2273                        if self.imageDefault:
2274                            Data = copy.copy(self.imageDefault)
2275                            Data['showLines'] = True
2276                            Data['ring'] = []
2277                            Data['rings'] = []
2278                            Data['cutoff'] = 10
2279                            Data['pixLimit'] = 20
2280                            Data['edgemin'] = 100000000
2281                            Data['calibdmin'] = 0.5
2282                            Data['calibskip'] = 0
2283                            Data['ellipses'] = []
2284                            Data['calibrant'] = ''
2285                            Data['GonioAngles'] = [0.,0.,0.]
2286                            Data['DetDepthRef'] = False
2287                        else:
2288                            Data['type'] = 'PWDR'
2289                            Data['color'] = 'Paired'
2290                            Data['tilt'] = 0.0
2291                            Data['rotation'] = 0.0
2292                            Data['showLines'] = False
2293                            Data['ring'] = []
2294                            Data['rings'] = []
2295                            Data['cutoff'] = 10
2296                            Data['pixLimit'] = 20
2297                            Data['calibdmin'] = 0.5
2298                            Data['calibskip'] = 0
2299                            Data['edgemin'] = 100000000
2300                            Data['ellipses'] = []
2301                            Data['GonioAngles'] = [0.,0.,0.]
2302                            Data['DetDepth'] = 0.
2303                            Data['DetDepthRef'] = False
2304                            Data['calibrant'] = ''
2305                            Data['IOtth'] = [2.0,5.0]
2306                            Data['LRazimuth'] = [135,225]
2307                            Data['azmthOff'] = 0.0
2308                            Data['outChannels'] = 2500
2309                            Data['outAzimuths'] = 1
2310                            Data['centerAzm'] = False
2311                            Data['fullIntegrate'] = False
2312                            Data['setRings'] = False
2313                            Data['background image'] = ['',-1.0]                           
2314                            Data['dark image'] = ['',-1.0]
2315                        Data['setDefault'] = False
2316                        Data['range'] = [(Imin,Imax),[Imin,Imax]]
2317                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Image Controls'),Data)
2318                        Masks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Frames':[],'Thresholds':[(Imin,Imax),[Imin,Imax]]}
2319                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Masks'),Masks)
2320                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Stress/Strain'),
2321                            {'Type':'True','d-zero':[],'Sample phi':0.0,'Sample z':0.0,'Sample load':0.0})
2322                        self.PatternTree.SetItemPyData(Id,[Npix,imagefile])
2323                        self.PickId = Id
2324                        self.Image = Id
2325                os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!               
2326                self.PatternTree.SelectItem(G2gd.GetPatternTreeItemId(self,Id,'Image Controls'))             #show last one
2327        finally:
2328            path = dlg.GetDirectory()           # to get Mac/Linux to change directory!
2329            os.chdir(path)
2330            dlg.Destroy()
2331
2332    def CheckNotebook(self):
2333        '''Make sure the data tree has the minimally expected controls.
2334        (BHT) correct?
2335        '''
2336        if not G2gd.GetPatternTreeItemId(self,self.root,'Notebook'):
2337            sub = self.PatternTree.AppendItem(parent=self.root,text='Notebook')
2338            self.PatternTree.SetItemPyData(sub,[''])
2339        if not G2gd.GetPatternTreeItemId(self,self.root,'Controls'):
2340            sub = self.PatternTree.AppendItem(parent=self.root,text='Controls')
2341            self.PatternTree.SetItemPyData(sub,copy.copy(G2obj.DefaultControls))
2342        if not G2gd.GetPatternTreeItemId(self,self.root,'Covariance'):
2343            sub = self.PatternTree.AppendItem(parent=self.root,text='Covariance')
2344            self.PatternTree.SetItemPyData(sub,{})
2345        if not G2gd.GetPatternTreeItemId(self,self.root,'Constraints'):
2346            sub = self.PatternTree.AppendItem(parent=self.root,text='Constraints')
2347            self.PatternTree.SetItemPyData(sub,{'Hist':[],'HAP':[],'Phase':[]})
2348        if not G2gd.GetPatternTreeItemId(self,self.root,'Restraints'):
2349            sub = self.PatternTree.AppendItem(parent=self.root,text='Restraints')
2350            self.PatternTree.SetItemPyData(sub,{})
2351        if not G2gd.GetPatternTreeItemId(self,self.root,'Rigid bodies'):
2352            sub = self.PatternTree.AppendItem(parent=self.root,text='Rigid bodies')
2353            self.PatternTree.SetItemPyData(sub,{'Vector':{'AtInfo':{}},
2354                'Residue':{'AtInfo':{}},'RBIds':{'Vector':[],'Residue':[]}})
2355               
2356    class CopyDialog(wx.Dialog):
2357        '''Creates a dialog for copying control settings between
2358        data tree items'''
2359        def __init__(self,parent,title,text,data):
2360            wx.Dialog.__init__(self,parent,-1,title, 
2361                pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
2362            self.data = data
2363            panel = wx.Panel(self)
2364            mainSizer = wx.BoxSizer(wx.VERTICAL)
2365            topLabl = wx.StaticText(panel,-1,text)
2366            mainSizer.Add((10,10),1)
2367            mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
2368            mainSizer.Add((10,10),1)
2369            ncols = len(data)/40+1
2370            dataGridSizer = wx.FlexGridSizer(cols=ncols,hgap=2,vgap=2)
2371            for id,item in enumerate(self.data):
2372                ckbox = wx.CheckBox(panel,id,item[1])
2373                ckbox.Bind(wx.EVT_CHECKBOX,self.OnCopyChange)                   
2374                dataGridSizer.Add(ckbox,0,wx.LEFT,10)
2375            mainSizer.Add(dataGridSizer,0,wx.EXPAND)
2376            OkBtn = wx.Button(panel,-1,"Ok")
2377            OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
2378            cancelBtn = wx.Button(panel,-1,"Cancel")
2379            cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
2380            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
2381            btnSizer.Add((20,20),1)
2382            btnSizer.Add(OkBtn)
2383            btnSizer.Add((20,20),1)
2384            btnSizer.Add(cancelBtn)
2385            btnSizer.Add((20,20),1)
2386           
2387            mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
2388            panel.SetSizer(mainSizer)
2389            panel.Fit()
2390            self.Fit()
2391       
2392        def OnCopyChange(self,event):
2393            id = event.GetId()
2394            self.data[id][0] = self.FindWindowById(id).GetValue()       
2395           
2396        def OnOk(self,event):
2397            parent = self.GetParent()
2398            parent.Raise()
2399            self.EndModal(wx.ID_OK)             
2400           
2401        def OnCancel(self,event):
2402            parent = self.GetParent()
2403            parent.Raise()
2404            self.EndModal(wx.ID_CANCEL)             
2405           
2406        def GetData(self):
2407            return self.data
2408       
2409    class SumDialog(wx.Dialog):
2410        'Allows user to supply scale factor(s) when summing data'
2411        def __init__(self,parent,title,text,dataType,data):
2412            wx.Dialog.__init__(self,parent,-1,title, 
2413                pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
2414            self.data = data
2415            panel = wx.Panel(self)
2416            mainSizer = wx.BoxSizer(wx.VERTICAL)
2417            topLabl = wx.StaticText(panel,-1,text)
2418            mainSizer.Add((10,10),1)
2419            mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
2420            mainSizer.Add((10,10),1)
2421            dataGridSizer = wx.FlexGridSizer(cols=2,hgap=2,vgap=2)
2422            for id,item in enumerate(self.data[:-1]):
2423                name = wx.TextCtrl(panel,-1,item[1],size=wx.Size(200,20))
2424                name.SetEditable(False)
2425                scale = wx.TextCtrl(panel,id,'%.3f'%(item[0]),style=wx.TE_PROCESS_ENTER)
2426                scale.Bind(wx.EVT_TEXT_ENTER,self.OnScaleChange)
2427                scale.Bind(wx.EVT_KILL_FOCUS,self.OnScaleChange)
2428                dataGridSizer.Add(scale,0,wx.LEFT,10)
2429                dataGridSizer.Add(name,0,wx.RIGHT,10)
2430            if dataType:
2431                dataGridSizer.Add(wx.StaticText(panel,-1,'Sum result name: '+dataType),0, \
2432                    wx.LEFT|wx.TOP|wx.ALIGN_CENTER_VERTICAL,10)
2433                self.name = wx.TextCtrl(panel,-1,self.data[-1],size=wx.Size(200,20),style=wx.TE_PROCESS_ENTER)
2434                self.name.Bind(wx.EVT_TEXT_ENTER,self.OnNameChange)
2435                self.name.Bind(wx.EVT_KILL_FOCUS,self.OnNameChange)
2436                dataGridSizer.Add(self.name,0,wx.RIGHT|wx.TOP,10)
2437            mainSizer.Add(dataGridSizer,0,wx.EXPAND)
2438            OkBtn = wx.Button(panel,-1,"Ok")
2439            OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
2440            cancelBtn = wx.Button(panel,-1,"Cancel")
2441            cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
2442            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
2443            btnSizer.Add((20,20),1)
2444            btnSizer.Add(OkBtn)
2445            btnSizer.Add((20,20),1)
2446            btnSizer.Add(cancelBtn)
2447            btnSizer.Add((20,20),1)
2448           
2449            mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
2450            panel.SetSizer(mainSizer)
2451            panel.Fit()
2452            self.Fit()
2453
2454        def OnScaleChange(self,event):
2455            id = event.GetId()
2456            value = self.FindWindowById(id).GetValue()
2457            try:
2458                self.data[id][0] = float(value)
2459                self.FindWindowById(id).SetValue('%.3f'%(self.data[id][0]))
2460            except ValueError:
2461                if value and '-' not in value[0]:
2462                    print 'bad input - numbers only'
2463                    self.FindWindowById(id).SetValue('0.000')
2464           
2465        def OnNameChange(self,event):
2466            self.data[-1] = self.name.GetValue() 
2467           
2468        def OnOk(self,event):
2469            parent = self.GetParent()
2470            parent.Raise()
2471            self.EndModal(wx.ID_OK)             
2472           
2473        def OnCancel(self,event):
2474            parent = self.GetParent()
2475            parent.Raise()
2476            self.EndModal(wx.ID_CANCEL)             
2477           
2478        def GetData(self):
2479            return self.data
2480                       
2481    def OnPwdrSum(self,event):
2482        'Sum together powder data(?)'
2483        TextList = []
2484        DataList = []
2485        SumList = []
2486        Names = []
2487        Inst = None
2488        SumItemList = []
2489        Comments = ['Sum equals: \n']
2490        if self.PatternTree.GetCount():
2491            item, cookie = self.PatternTree.GetFirstChild(self.root)
2492            while item:
2493                name = self.PatternTree.GetItemText(item)
2494                Names.append(name)
2495                if 'PWDR' in name:
2496                    TextList.append([0.0,name])
2497                    DataList.append(self.PatternTree.GetItemPyData(item)[1])    # (x,y,w,yc,yb,yd)
2498                    if not Inst:
2499                        Inst = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,item, 'Instrument Parameters'))
2500                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
2501            if len(TextList) < 2:
2502                self.ErrorDialog('Not enough data to sum','There must be more than one "PWDR" pattern')
2503                return
2504            TextList.append('default_sum_name')               
2505            dlg = self.SumDialog(self,'Sum data','Enter scale for each pattern in summation','PWDR',TextList)
2506            try:
2507                if dlg.ShowModal() == wx.ID_OK:
2508                    lenX = 0
2509                    Xminmax = [0,0]
2510                    Xsum = []
2511                    Ysum = []
2512                    Vsum = []
2513                    result = dlg.GetData()
2514                    for i,item in enumerate(result[:-1]):
2515                        scale,name = item
2516                        data = DataList[i]
2517                        if scale:
2518                            Comments.append("%10.3f %s" % (scale,' * '+name))
2519                            x,y,w,yc,yb,yd = data   #numpy arrays!
2520                            v = 1./w
2521                            if lenX:
2522                                if lenX != len(x):
2523                                    self.ErrorDialog('Data length error','Data to be summed must have same number of points'+ \
2524                                        '\nExpected:'+str(lenX)+ \
2525                                        '\nFound:   '+str(len(x))+'\nfor '+name)
2526                                    return
2527                            else:
2528                                lenX = len(x)
2529                            if Xminmax[1]:
2530                                if Xminmax != [x[0],x[-1]]:
2531                                    self.ErrorDialog('Data range error','Data to be summed must span same range'+ \
2532                                        '\nExpected:'+str(Xminmax[0])+' '+str(Xminmax[1])+ \
2533                                        '\nFound:   '+str(x[0])+' '+str(x[-1])+'\nfor '+name)
2534                                    return
2535                                else:
2536                                    for j,yi in enumerate(y):
2537                                         Ysum[j] += scale*yi
2538                                         Vsum[j] += abs(scale)*v[j]
2539                            else:
2540                                Xminmax = [x[0],x[-1]]
2541                                YCsum = YBsum = YDsum = [0.0 for i in range(lenX)]
2542                                for j,yi in enumerate(y):
2543                                    Xsum.append(x[j])
2544                                    Ysum.append(scale*yi)
2545                                    Vsum.append(abs(scale*v[j]))
2546                    Wsum = 1./np.array(Vsum)
2547                    outname = 'PWDR '+result[-1]
2548                    Id = 0
2549                    if outname in Names:
2550                        dlg2 = wx.MessageDialog(self,'Overwrite data?','Duplicate data name',wx.OK|wx.CANCEL)
2551                        try:
2552                            if dlg2.ShowModal() == wx.ID_OK:
2553                                Id = G2gd.GetPatternTreeItemId(self,self.root,name)
2554                                self.PatternTree.Delete(Id)
2555                        finally:
2556                            dlg2.Destroy()
2557                    Id = self.PatternTree.AppendItem(parent=self.root,text=outname)
2558                    if Id:
2559                        Sample = G2pdG.SetDefaultSample()
2560                        valuesdict = {
2561                            'wtFactor':1.0,
2562                            'Dummy':False,
2563                            'ranId':ran.randint(0,sys.maxint),
2564                            }
2565                        self.PatternTree.SetItemPyData(Id,[valuesdict,[np.array(Xsum),np.array(Ysum),np.array(Wsum),
2566                            np.array(YCsum),np.array(YBsum),np.array(YDsum)]])
2567                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)                   
2568                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Limits'),[tuple(Xminmax),Xminmax])
2569                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Background'),[['chebyschev',True,3,1.0,0.0,0.0],
2570                            {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
2571                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Instrument Parameters'),Inst)
2572                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Sample Parameters'),Sample)
2573                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Peak List'),{'peaks':[],'sigDict':{}})
2574                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Index Peak List'),[[],[]])
2575                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Unit Cells List'),[])             
2576                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Reflection Lists'),{})             
2577                        self.PatternTree.SelectItem(Id)
2578                        self.PatternTree.Expand(Id)
2579            finally:
2580                dlg.Destroy()
2581
2582    def OnImageSum(self,event):
2583        'Sum together image data(?)'
2584        TextList = []
2585        DataList = []
2586        SumList = []
2587        Names = []
2588        Inst = []
2589        SumItemList = []
2590        Comments = ['Sum equals: \n']
2591        if self.PatternTree.GetCount():
2592            item, cookie = self.PatternTree.GetFirstChild(self.root)
2593            while item:
2594                name = self.PatternTree.GetItemText(item)
2595                Names.append(name)
2596                if 'IMG' in name:
2597                    TextList.append([0.0,name])
2598                    DataList.append(self.PatternTree.GetItemPyData(item))        #Size,Image
2599                    Data = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,item,'Image Controls'))
2600                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
2601            if len(TextList) < 2:
2602                self.ErrorDialog('Not enough data to sum','There must be more than one "IMG" pattern')
2603                return
2604            TextList.append('default_sum_name')               
2605            dlg = self.SumDialog(self,'Sum data','Enter scale for each image in summation','IMG',TextList)
2606            try:
2607                if dlg.ShowModal() == wx.ID_OK:
2608                    imSize = 0
2609                    result = dlg.GetData()
2610                    First = True
2611                    Found = False
2612                    for i,item in enumerate(result[:-1]):
2613                        scale,name = item
2614                        data = DataList[i]
2615                        if scale:
2616                            Found = True                               
2617                            Comments.append("%10.3f %s" % (scale,' * '+name))
2618                            Npix,imagefile = data
2619                            image = G2IO.GetImageData(self,imagefile,imageOnly=True)
2620                            if First:
2621                                newImage = np.zeros_like(image)
2622                                First = False
2623                            if imSize:
2624                                if imSize != Npix:
2625                                    self.ErrorDialog('Image size error','Images to be summed must be same size'+ \
2626                                        '\nExpected:'+str(imSize)+ \
2627                                        '\nFound:   '+str(Npix)+'\nfor '+name)
2628                                    return
2629                                newImage = newImage+scale*image
2630                            else:
2631                                imSize = Npix
2632                                newImage = newImage+scale*image
2633                            del(image)
2634                    if not Found:
2635                        self.ErrorDialog('Image sum error','No nonzero image multipliers found')
2636                        return
2637                       
2638                    newImage = np.asfarray(newImage,dtype=np.float32)                       
2639                    outname = 'IMG '+result[-1]
2640                    Id = 0
2641                    if outname in Names:
2642                        dlg2 = wx.MessageDialog(self,'Overwrite data?','Duplicate data name',wx.OK|wx.CANCEL)
2643                        try:
2644                            if dlg2.ShowModal() == wx.ID_OK:
2645                                Id = G2gd.GetPatternTreeItemId(self,self.root,name)
2646                        finally:
2647                            dlg2.Destroy()
2648                    else:
2649                        Id = self.PatternTree.AppendItem(parent=self.root,text=outname)
2650                    if Id:
2651                        dlg = wx.FileDialog(self, 'Choose sum image filename', '.', '', 
2652                            'G2img files (*.G2img)|*.G2img', 
2653                            wx.SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
2654                        if dlg.ShowModal() == wx.ID_OK:
2655                            newimagefile = dlg.GetPath()
2656                            newimagefile = G2IO.FileDlgFixExt(dlg,newimagefile)
2657                            G2IO.PutG2Image(newimagefile,Comments,Data,Npix,newImage)
2658                            Imax = np.amax(newImage)
2659                            Imin = np.amin(newImage)
2660                            newImage = []
2661                            self.PatternTree.SetItemPyData(Id,[imSize,newimagefile])
2662                            self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)
2663                        del(newImage)
2664                        if self.imageDefault:
2665                            Data = copy.copy(self.imageDefault)
2666                        Data['showLines'] = True
2667                        Data['ring'] = []
2668                        Data['rings'] = []
2669                        Data['cutoff'] = 10
2670                        Data['pixLimit'] = 20
2671                        Data['ellipses'] = []
2672                        Data['calibrant'] = ''
2673                        Data['range'] = [(Imin,Imax),[Imin,Imax]]
2674                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Image Controls'),Data)                                           
2675                        Masks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Frames':[],'Thresholds':[(Imin,Imax),[Imin,Imax]]}
2676                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Masks'),Masks)
2677                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Stress/Strain'),
2678                            {'Type':'True','d-zero':[],'Sample phi':0.0,'Sample z':0.0,'Sample load':0.0})
2679                        self.PatternTree.SelectItem(Id)
2680                        self.PatternTree.Expand(Id)
2681                        self.PickId = G2gd.GetPatternTreeItemId(self,self.root,outname)
2682                        self.Image = self.PickId
2683            finally:
2684                dlg.Destroy()
2685                     
2686    def OnAddPhase(self,event):
2687        'Add a new, empty phase to the tree. Called by Data/Add Phase menu'
2688        if not G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
2689            sub = self.PatternTree.AppendItem(parent=self.root,text='Phases')
2690        else:
2691            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
2692        PhaseName = ''
2693        dlg = wx.TextEntryDialog(None,'Enter a name for this phase','Phase Name Entry','New phase',
2694            style=wx.OK)
2695        if dlg.ShowModal() == wx.ID_OK:
2696            PhaseName = dlg.GetValue()
2697        dlg.Destroy()
2698        sub = self.PatternTree.AppendItem(parent=sub,text=PhaseName)
2699        E,SGData = G2spc.SpcGroup('P 1')
2700        self.PatternTree.SetItemPyData(sub,G2IO.SetNewPhase(Name=PhaseName,SGData=SGData))
2701       
2702    def OnDeletePhase(self,event):
2703        'Delete a phase from the tree. Called by Data/Delete Phase menu'
2704        #Hmm, also need to delete this phase from Reflection Lists for each PWDR histogram
2705        if self.dataFrame:
2706            self.dataFrame.Clear() 
2707        TextList = []
2708        DelList = []
2709        DelItemList = []
2710        if G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
2711            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
2712        else:
2713            return
2714        if sub:
2715            item, cookie = self.PatternTree.GetFirstChild(sub)
2716            while item:
2717                TextList.append(self.PatternTree.GetItemText(item))
2718                item, cookie = self.PatternTree.GetNextChild(sub, cookie)               
2719            dlg = wx.MultiChoiceDialog(self, 'Which phase to delete?', 'Delete phase', TextList, wx.CHOICEDLG_STYLE)
2720            try:
2721                if dlg.ShowModal() == wx.ID_OK:
2722                    result = dlg.GetSelections()
2723                    for i in result: DelList.append([i,TextList[i]])
2724                    item, cookie = self.PatternTree.GetFirstChild(sub)
2725                    i = 0
2726                    while item:
2727                        if [i,self.PatternTree.GetItemText(item)] in DelList: DelItemList.append(item)
2728                        item, cookie = self.PatternTree.GetNextChild(sub, cookie)
2729                        i += 1
2730                    for item in DelItemList:
2731                        name = self.PatternTree.GetItemText(item)
2732                        self.PatternTree.Delete(item)
2733                        self.G2plotNB.Delete(name)
2734                    item, cookie = self.PatternTree.GetFirstChild(self.root)
2735                    while item:
2736                        name = self.PatternTree.GetItemText(item)
2737                        if 'PWDR' in name:
2738                            Id = G2gd.GetPatternTreeItemId(self,item, 'Reflection Lists')
2739                            refList = self.PatternTree.GetItemPyData(Id)
2740                            if len(refList):
2741                                for i,item in DelList:
2742                                    del(refList[item])
2743                            self.PatternTree.SetItemPyData(Id,refList)
2744                        item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
2745            finally:
2746                dlg.Destroy()
2747               
2748    def OnRenameData(self,event):
2749        'Renames an existing phase. Called by Data/Rename Phase menu'
2750        name = self.PatternTree.GetItemText(self.PickId)     
2751        if 'PWDR' in name or 'HKLF' in name or 'IMG' in name:
2752            dataType = name[:name.index(' ')+1]                 #includes the ' '
2753            dlg = wx.TextEntryDialog(self,'Data name: '+dataType,'Change data name',
2754                defaultValue=name[name.index(' ')+1:])
2755            try:
2756                if dlg.ShowModal() == wx.ID_OK:
2757                    self.PatternTree.SetItemText(self.PickId,dataType+dlg.GetValue())
2758            finally:
2759                dlg.Destroy()
2760       
2761    def GetFileList(self,fileType,skip=None):        #potentially useful?
2762        'Appears unused. Note routine of same name in GSASIIpwdGUI'
2763        fileList = []
2764        Source = ''
2765        id, cookie = self.PatternTree.GetFirstChild(self.root)
2766        while id:
2767            name = self.PatternTree.GetItemText(id)
2768            if fileType in name:
2769                if id == skip:
2770                    Source = name
2771                else:
2772                    fileList.append([False,name,id])
2773            id, cookie = self.PatternTree.GetNextChild(self.root, cookie)
2774        if skip:
2775            return fileList,Source
2776        else:
2777            return fileList
2778           
2779    def OnDataDelete(self, event):
2780        '''Delete one or more histograms from data tree. Called by the
2781        Data/DeleteData menu
2782        '''
2783        TextList = ['All Data']
2784        DelList = []
2785        DelItemList = []
2786        ifPWDR = False
2787        ifSASD = False
2788        ifIMG = False
2789        ifHKLF = False
2790        ifPDF = False
2791        if self.PatternTree.GetCount():
2792            item, cookie = self.PatternTree.GetFirstChild(self.root)
2793            while item:
2794                name = self.PatternTree.GetItemText(item)
2795                if name not in ['Notebook','Controls','Covariance','Constraints',
2796                    'Restraints','Phases','Rigid bodies']:
2797                    if 'PWDR' in name: ifPWDR = True
2798                    if 'SASD' in name: ifSASD = True
2799                    if 'IMG' in name: ifIMG = True
2800                    if 'HKLF' in name: ifHKLF = True
2801                    if 'PDF' in name: ifPDF = True
2802                    TextList.append(name)
2803                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
2804            if ifPWDR: TextList.insert(1,'All PWDR')
2805            if ifSASD: TextList.insert(1,'All SASD')
2806            if ifIMG: TextList.insert(1,'All IMG')
2807            if ifHKLF: TextList.insert(1,'All HKLF')
2808            if ifPDF: TextList.insert(1,'All PDF')               
2809            dlg = wx.MultiChoiceDialog(self, 'Which data to delete?', 'Delete data', TextList, wx.CHOICEDLG_STYLE)
2810            try:
2811                if dlg.ShowModal() == wx.ID_OK:
2812                    result = dlg.GetSelections()
2813                    for i in result: DelList.append(TextList[i])
2814                    if 'All Data' in DelList:
2815                        DelList = [item for item in TextList if item[:3] != 'All']
2816                    elif 'All PWDR' in DelList:
2817                        DelList = [item for item in TextList if item[:4] == 'PWDR']
2818                    elif 'All SASD' in DelList:
2819                        DelList = [item for item in TextList if item[:4] == 'SASD']
2820                    elif 'All IMG' in DelList:
2821                        DelList = [item for item in TextList if item[:3] == 'IMG']
2822                    elif 'All HKLF' in DelList:
2823                        DelList = [item for item in TextList if item[:4] == 'HKLF']
2824                    elif 'All PDF' in DelList:
2825                        DelList = [item for item in TextList if item[:3] == 'PDF']
2826                    item, cookie = self.PatternTree.GetFirstChild(self.root)
2827                    while item:
2828                        if self.PatternTree.GetItemText(item) in DelList: DelItemList.append(item)
2829                        item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
2830                    for item in DelItemList:
2831                        self.PatternTree.Delete(item)
2832                    self.PickId = 0
2833                    wx.CallAfter(G2plt.PlotPatterns,self,True)                        #so plot gets updated
2834            finally:
2835                dlg.Destroy()
2836
2837    def OnFileOpen(self, event, filename=None):
2838        '''Reads in a GSAS-II .gpx project file in response to the
2839        File/Open Project menu button
2840        '''
2841        result = wx.ID_OK
2842        Id = 0
2843        self.EnablePlot = False
2844        if self.PatternTree.GetChildrenCount(self.root,False):
2845            if self.dataFrame:
2846                self.dataFrame.Clear() 
2847            dlg = wx.MessageDialog(
2848                self,
2849                'Do you want to overwrite the current project? '
2850                'Any unsaved changes will be lost. Press OK to continue.',
2851                'Overwrite?',  wx.OK | wx.CANCEL)
2852            try:
2853                result = dlg.ShowModal()
2854                if result == wx.ID_OK:
2855                    self.PatternTree.DeleteChildren(self.root)
2856                    self.GSASprojectfile = ''
2857                    if self.HKL: self.HKL = []
2858                    if self.G2plotNB.plotList:
2859                        self.G2plotNB.clear()
2860            finally:
2861                dlg.Destroy()
2862        if result != wx.ID_OK: return
2863
2864        if not filename:
2865            if self.dataDisplay: self.dataDisplay.Destroy()
2866            dlg = wx.FileDialog(self, 'Choose GSAS-II project file', '.', '', 
2867                'GSAS-II project file (*.gpx)|*.gpx',wx.OPEN|wx.CHANGE_DIR)
2868            try:
2869                if dlg.ShowModal() != wx.ID_OK: return
2870                self.GSASprojectfile = dlg.GetPath()
2871                self.GSASprojectfile = G2IO.FileDlgFixExt(dlg,self.GSASprojectfile)
2872                self.dirname = dlg.GetDirectory()
2873            finally:
2874                dlg.Destroy()
2875        else:
2876            self.GSASprojectfile = os.path.splitext(filename)[0]+'.gpx'
2877            self.dirname = os.path.split(filename)[0]
2878
2879        G2IO.ProjFileOpen(self)
2880        self.PatternTree.SetItemText(self.root,'Loaded Data: '+self.GSASprojectfile)
2881        self.PatternTree.Expand(self.root)
2882        self.HKL = []
2883        item, cookie = self.PatternTree.GetFirstChild(self.root)
2884        while item and not Id:
2885            name = self.PatternTree.GetItemText(item)
2886            if name[:4] in ['PWDR','HKLF','IMG ','PDF ','SASD',]:
2887                Id = item
2888            elif name == 'Controls':
2889                data = self.PatternTree.GetItemPyData(item)
2890                if data:
2891                    for item in self.Refine: item.Enable(True)
2892                    self.EnableSeqRefineMenu()
2893            item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
2894        if Id:
2895            self.EnablePlot = True
2896            self.PatternTree.SelectItem(Id)
2897        self.CheckNotebook()
2898        os.chdir(self.dirname)           # to get Mac/Linux to change directory!
2899
2900    def OnFileClose(self, event):
2901        '''Clears the data tree in response to the
2902        File/New Project menu button. User is given option to save
2903        the project.
2904        '''
2905        if self.dataFrame:
2906            self.dataFrame.Clear()
2907            self.dataFrame.SetLabel('GSAS-II data display') 
2908        dlg = wx.MessageDialog(self, 'Save current project?', ' ', wx.YES | wx.NO | wx.CANCEL)
2909        try:
2910            result = dlg.ShowModal()
2911            if result == wx.ID_OK:
2912                self.OnFileSaveMenu(event)
2913            if result != wx.ID_CANCEL:
2914                self.GSASprojectfile = ''
2915                self.PatternTree.SetItemText(self.root,'Loaded Data: ')
2916                self.PatternTree.DeleteChildren(self.root)
2917                if self.HKL: self.HKL = []
2918                if self.G2plotNB.plotList:
2919                    self.G2plotNB.clear()
2920        finally:
2921            dlg.Destroy()
2922
2923    def OnFileSave(self, event):
2924        '''Save the current project in response to the
2925        File/Save Project menu button
2926        '''
2927       
2928        if self.GSASprojectfile: 
2929            self.PatternTree.SetItemText(self.root,'Loaded Data: '+self.GSASprojectfile)
2930            G2IO.ProjFileSave(self)
2931        else:
2932            self.OnFileSaveas(event)
2933
2934    def OnFileSaveas(self, event):
2935        '''Save the current project in response to the
2936        File/Save as menu button
2937        '''
2938        dlg = wx.FileDialog(self, 'Choose GSAS-II project file name', '.', '', 
2939            'GSAS-II project file (*.gpx)|*.gpx',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
2940        try:
2941            if dlg.ShowModal() == wx.ID_OK:
2942                self.GSASprojectfile = dlg.GetPath()
2943                self.GSASprojectfile = G2IO.FileDlgFixExt(dlg,self.GSASprojectfile)
2944                self.PatternTree.SetItemText(self.root,'Saving project as'+self.GSASprojectfile)
2945                self.SetTitle("GSAS-II data tree: "+os.path.split(self.GSASprojectfile)[1])
2946                G2IO.ProjFileSave(self)
2947                os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
2948        finally:
2949            dlg.Destroy()
2950
2951    def ExitMain(self, event):
2952        '''Called if the main window is closed'''
2953        if self.undofile:
2954            os.remove(self.undofile)
2955        sys.exit()
2956       
2957    def OnFileExit(self, event):
2958        '''Called in response to the File/Quit menu button'''
2959        if self.dataFrame:
2960            self.dataFrame.Clear() 
2961            self.dataFrame.Destroy()
2962        self.Close()
2963       
2964    # def OnExportPatterns(self,event):
2965    #     names = ['All']
2966    #     exports = []
2967    #     item, cookie = self.PatternTree.GetFirstChild(self.root)
2968    #     while item:
2969    #         name = self.PatternTree.GetItemText(item)
2970    #         if 'PWDR' in name:
2971    #             names.append(name)
2972    #         item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
2973    #     if names:
2974    #         dlg = wx.MultiChoiceDialog(self,'Select','Powder patterns to export',names)
2975    #         if dlg.ShowModal() == wx.ID_OK:
2976    #             sel = dlg.GetSelections()
2977    #             if sel[0] == 0:
2978    #                 exports = names[1:]
2979    #             else:
2980    #                 for x in sel:
2981    #                     exports.append(names[x])
2982    #         dlg.Destroy()
2983    #     if exports:
2984    #         dlg = wx.FileDialog(self, 'Choose output powder file name', '.', '',
2985    #             'GSAS fxye file (*.fxye)|*.fxye|xye file (*.xye)|*.xye',
2986    #             wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
2987    #         try:
2988    #             if dlg.ShowModal() == wx.ID_OK:
2989    #                 powderfile = dlg.GetPath()
2990    #                 powderfile = G2IO.FileDlgFixExt(dlg,powderfile)
2991    #                 if 'fxye' in powderfile:
2992    #                     G2IO.powderFxyeSave(self,exports,powderfile)
2993    #                 else:       #just xye
2994    #                     G2IO.powderXyeSave(self,exports,powderfile)
2995    #         finally:
2996    #             dlg.Destroy()
2997       
2998    def OnExportPeakList(self,event):
2999        dlg = wx.FileDialog(self, 'Choose output peak list file name', '.', '', 
3000            '(*.*)|*.*',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
3001        try:
3002            if dlg.ShowModal() == wx.ID_OK:
3003                self.peaklistfile = dlg.GetPath()
3004                self.peaklistfile = G2IO.FileDlgFixExt(dlg,self.peaklistfile)
3005                file = open(self.peaklistfile,'w')               
3006                item, cookie = self.PatternTree.GetFirstChild(self.root)
3007                while item:
3008                    name = self.PatternTree.GetItemText(item)
3009                    if 'PWDR' in name:
3010                        item2, cookie2 = self.PatternTree.GetFirstChild(item)
3011                        while item2:
3012                            name2 = self.PatternTree.GetItemText(item2)
3013                            if name2 == 'Peak List':
3014                                peaks = self.PatternTree.GetItemPyData(item2)['peaks']
3015                                file.write("%s \n" % (name+' Peak List'))
3016                                if len(peaks[0]) == 8:
3017                                    file.write('%10s %12s %10s %10s\n'%('pos','int','sig','gam'))
3018                                else:
3019                                    file.write('%10s %12s %10s %10s %10s %10s\n'%('pos','int','alp','bet','sig','gam'))                                   
3020                                for peak in peaks:
3021                                    if len(peak) == 8:  #CW
3022                                        file.write("%10.5f %12.2f %10.3f %10.3f \n" % \
3023                                            (peak[0],peak[2],peak[4],peak[6]))
3024                                    else:               #TOF - more cols
3025                                        file.write("%10.5f %12.2f %10.3f %10.3f %10.3f %10.3f\n" % \
3026                                            (peak[0],peak[2],peak[4],peak[6],peak[8],peak[10]))
3027                            item2, cookie2 = self.PatternTree.GetNextChild(item, cookie2)                           
3028                    item, cookie = self.PatternTree.GetNextChild(self.root, cookie)                           
3029                file.close()
3030        finally:
3031            dlg.Destroy()
3032       
3033    def OnExportHKL(self,event):
3034        dlg = wx.FileDialog(self, 'Choose output reflection list file name', '.', '', 
3035            '(*.*)|*.*',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
3036        try:
3037            if dlg.ShowModal() == wx.ID_OK:
3038                self.peaklistfile = dlg.GetPath()
3039                self.peaklistfile = G2IO.FileDlgFixExt(dlg,self.peaklistfile)
3040                file = open(self.peaklistfile,'w')               
3041                item, cookie = self.PatternTree.GetFirstChild(self.root)
3042                while item:
3043                    name = self.PatternTree.GetItemText(item)
3044                    if 'PWDR' in name:
3045                        item2, cookie2 = self.PatternTree.GetFirstChild(item)
3046                        while item2:
3047                            name2 = self.PatternTree.GetItemText(item2)
3048                            if name2 == 'Reflection Lists':
3049                                data = self.PatternTree.GetItemPyData(item2)
3050                                phases = data.keys()
3051                                for phase in phases:
3052                                    peaks = data[phase]
3053                                    file.write("%s %s %s \n" % (name,phase,' Reflection List'))
3054                                    if 'T' in peaks.get('Type','PXC'):
3055                                        file.write('%s \n'%('   h   k   l   m    d-space     TOF         wid        F**2'))
3056                                    else:               
3057                                        file.write('%s \n'%('   h   k   l   m    d-space   2-theta       wid        F**2'))
3058                                    for peak in peaks['RefList']:
3059                                        FWHM = G2pwd.getgamFW(peak[7],peak[6])/50.      #to get delta-2-theta in deg.
3060                                        if 'T' in peaks.get('Type','PXC'):
3061                                            file.write(" %3d %3d %3d %3d %10.5f %10.2f %10.5f %10.3f \n" % \
3062                                                (int(peak[0]),int(peak[1]),int(peak[2]),int(peak[3]),peak[4],peak[5],FWHM,peak[8]))
3063                                        else:
3064                                            file.write(" %3d %3d %3d %3d %10.5f %10.5f %10.5f %10.3f \n" % \
3065                                                (int(peak[0]),int(peak[1]),int(peak[2]),int(peak[3]),peak[4],peak[5],FWHM,peak[8]))
3066                            item2, cookie2 = self.PatternTree.GetNextChild(item, cookie2)                           
3067                    item, cookie = self.PatternTree.GetNextChild(self.root, cookie)                           
3068                file.close()
3069        finally:
3070            dlg.Destroy()
3071       
3072    def OnExportPDF(self,event):
3073        #need S(Q) and G(R) to be saved here - probably best from selection?
3074        names = ['All']
3075        exports = []
3076        item, cookie = self.PatternTree.GetFirstChild(self.root)
3077        while item:
3078            name = self.PatternTree.GetItemText(item)
3079            if 'PDF' in name:
3080                names.append(name)
3081            item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3082        if names:
3083            dlg = wx.MultiChoiceDialog(self,'Select','PDF patterns to export',names)
3084            if dlg.ShowModal() == wx.ID_OK:
3085                sel = dlg.GetSelections()
3086                if sel[0] == 0:
3087                    exports = names[1:]
3088                else:
3089                    for x in sel:
3090                        exports.append(names[x])
3091            dlg.Destroy()
3092        if exports:
3093            G2IO.PDFSave(self,exports)
3094       
3095    def OnMakePDFs(self,event):
3096        '''Calculates PDFs
3097        '''
3098        sind = lambda x: math.sin(x*math.pi/180.)
3099        tth2q = lambda t,w:4.0*math.pi*sind(t/2.0)/w
3100        TextList = ['All PWDR']
3101        PDFlist = []
3102        Names = []
3103        if self.PatternTree.GetCount():
3104            id, cookie = self.PatternTree.GetFirstChild(self.root)
3105            while id:
3106                name = self.PatternTree.GetItemText(id)
3107                Names.append(name)
3108                if 'PWDR' in name:
3109                    TextList.append(name)
3110                id, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3111            if len(TextList) == 1:
3112                self.ErrorDialog('Nothing to make PDFs for','There must be at least one "PWDR" pattern')
3113                return
3114            dlg = wx.MultiChoiceDialog(self,'Make PDF controls','Make PDF controls for:',TextList, wx.CHOICEDLG_STYLE)
3115            try:
3116                if dlg.ShowModal() == wx.ID_OK:
3117                    result = dlg.GetSelections()
3118                    for i in result: PDFlist.append(TextList[i])
3119                    if 0 in result:
3120                        PDFlist = [item for item in TextList if item[:4] == 'PWDR']                       
3121                    for item in PDFlist:
3122                        PWDRname = item[4:]
3123                        Id = self.PatternTree.AppendItem(parent=self.root,text='PDF '+PWDRname)
3124                        Data = {
3125                            'Sample':{'Name':item,'Mult':1.0,'Add':0.0},
3126                            'Sample Bkg.':{'Name':'','Mult':-1.0,'Add':0.0},
3127                            'Container':{'Name':'','Mult':-1.0,'Add':0.0},
3128                            'Container Bkg.':{'Name':'','Mult':-1.0,'Add':0.0},'ElList':{},
3129                            'Geometry':'Cylinder','Diam':1.0,'Pack':0.50,'Form Vol':10.0,
3130                            'DetType':'Image plate','ObliqCoeff':0.2,'Ruland':0.025,'QScaleLim':[0,100],
3131                            'Lorch':True,}
3132                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='PDF Controls'),Data)
3133                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='I(Q)'+PWDRname),[])       
3134                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='S(Q)'+PWDRname),[])       
3135                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='F(Q)'+PWDRname),[])       
3136                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='G(R)'+PWDRname),[])       
3137                for item in self.ExportPDF: item.Enable(True)
3138            finally:
3139                dlg.Destroy()
3140               
3141    def GetPWDRdatafromTree(self,PWDRname):
3142        ''' Returns powder data from GSASII tree
3143
3144        :param str PWDRname: a powder histogram name as obtained from
3145          :meth:`GSASIIstruct.GetHistogramNames`
3146
3147        :returns: PWDRdata = powder data dictionary with
3148          Powder data arrays, Limits, Instrument Parameters,
3149          Sample Parameters           
3150        '''
3151        PWDRdata = {}
3152        try:
3153            PWDRdata.update(self.PatternTree.GetItemPyData(PWDRname)[0])            #wtFactor + ?
3154        except ValueError:
3155            PWDRdata['wtFactor'] = 1.0
3156        PWDRdata['Data'] = self.PatternTree.GetItemPyData(PWDRname)[1]          #powder data arrays
3157        PWDRdata['Limits'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Limits'))
3158        PWDRdata['Background'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Background'))
3159        PWDRdata['Instrument Parameters'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Instrument Parameters'))
3160        PWDRdata['Sample Parameters'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Sample Parameters'))
3161        PWDRdata['Reflection Lists'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Reflection Lists'))
3162        if 'ranId' not in PWDRdata:  # patch, add a random Id
3163            PWDRdata['ranId'] = ran.randint(0,sys.maxint)
3164        if 'ranId' not in PWDRdata['Sample Parameters']:  # I hope this becomes obsolete at some point
3165            PWDRdata['Sample Parameters']['ranId'] = PWDRdata['ranId']
3166        return PWDRdata
3167
3168    def GetHKLFdatafromTree(self,HKLFname):
3169        ''' Returns single crystal data from GSASII tree
3170
3171        :param str HKLFname: a single crystal histogram name as obtained
3172          from
3173          :meth:`GSASIIstruct.GetHistogramNames`
3174
3175        :returns: HKLFdata = single crystal data list of reflections
3176
3177        '''
3178        HKLFdata = {}
3179        HKLFdata.update(self.PatternTree.GetItemPyData(HKLFname)[0])            #wtFactor + ?
3180#        try:
3181#            HKLFdata.update(self.PatternTree.GetItemPyData(HKLFname)[0])            #wtFactor + ?
3182#        except ValueError:
3183#            HKLFdata['wtFactor'] = 1.0
3184        HKLFdata['Data'] = self.PatternTree.GetItemPyData(HKLFname)[1]
3185        HKLFdata['Instrument Parameters'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,HKLFname,'Instrument Parameters'))
3186        return HKLFdata
3187       
3188    def GetPhaseData(self):
3189        '''Returns a dict with defined phases.
3190        Note routine :func:`GSASIIstrIO.GetPhaseData` also exists to
3191        get same info from GPX file.
3192        '''
3193        phaseData = {}
3194        if G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
3195            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
3196        else:
3197            print 'no phases found in GetPhaseData'
3198            sub = None
3199        if sub:
3200            item, cookie = self.PatternTree.GetFirstChild(sub)
3201            while item:
3202                phaseName = self.PatternTree.GetItemText(item)
3203                phaseData[phaseName] =  self.PatternTree.GetItemPyData(item)
3204                if 'ranId' not in phaseData[phaseName]:
3205                    phaseData[phaseName]['ranId'] = ran.randint(0,sys.maxint)         
3206                item, cookie = self.PatternTree.GetNextChild(sub, cookie)
3207        return phaseData
3208
3209    def GetPhaseInfofromTree(self):
3210        '''Get the phase names and their rId values,
3211        also the histograms used in each phase.
3212
3213        :returns: (phaseRIdList, usedHistograms) where
3214
3215          * phaseRIdList is a list of random Id values for each phase
3216          * usedHistograms is a dict where the keys are the phase names
3217            and the values for each key are a list of the histogram names
3218            used in each phase.
3219        '''
3220        phaseRIdList = []
3221        usedHistograms = {}
3222        sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
3223        if sub:
3224            item, cookie = self.PatternTree.GetFirstChild(sub)
3225            while item:
3226                phaseName = self.PatternTree.GetItemText(item)
3227                ranId = self.PatternTree.GetItemPyData(item).get('ranId')
3228                if ranId: phaseRIdList.append(ranId)
3229                data = self.PatternTree.GetItemPyData(item)
3230                UseList = data['Histograms']
3231                usedHistograms[phaseName] = UseList.keys()
3232                item, cookie = self.PatternTree.GetNextChild(sub, cookie)
3233        return phaseRIdList,usedHistograms
3234
3235    def GetPhaseNames(self):
3236        '''Returns a list of defined phases.
3237        Note routine :func:`GSASIIstrIO.GetPhaseNames` also exists to
3238        get same info from GPX file.
3239        '''
3240        phaseNames = []
3241        if G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
3242            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
3243        else:
3244            print 'no phases found in GetPhaseNames'
3245            sub = None
3246        if sub:
3247            item, cookie = self.PatternTree.GetFirstChild(sub)
3248            while item:
3249                phase = self.PatternTree.GetItemText(item)
3250                phaseNames.append(phase)
3251                item, cookie = self.PatternTree.GetNextChild(sub, cookie)
3252        return phaseNames
3253   
3254    def GetHistogramNames(self,hType):
3255        """ Returns a list of histogram names found in the GSASII data tree
3256        Note routine :func:`GSASIIstrIO.GetHistogramNames` also exists to
3257        get same info from GPX file.
3258       
3259        :param str hType: list of histogram types
3260        :return: list of histogram names
3261       
3262        """
3263        HistogramNames = []
3264        if self.PatternTree.GetCount():
3265            item, cookie = self.PatternTree.GetFirstChild(self.root)
3266            while item:
3267                name = self.PatternTree.GetItemText(item)
3268                if name[:4] in hType:
3269                    HistogramNames.append(name)       
3270                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)               
3271
3272        return HistogramNames
3273
3274                   
3275    def GetUsedHistogramsAndPhasesfromTree(self):
3276        ''' Returns all histograms that are found in any phase
3277        and any phase that uses a histogram.
3278        This also assigns numbers to used phases and histograms by the
3279        order they appear in the file.
3280        Note routine :func:`GSASIIstrIO.GetUsedHistogramsAndPhasesfromTree` also exists to
3281        get same info from GPX file.
3282
3283        :returns: (Histograms,Phases)
3284
3285            * Histograms = dictionary of histograms as {name:data,...}
3286            * Phases = dictionary of phases that use histograms
3287        '''
3288        Histograms = {}
3289        Phases = {}
3290        phaseNames = self.GetPhaseNames()
3291        phaseData = self.GetPhaseData()
3292        histoList = self.GetHistogramNames(['PWDR','HKLF'])
3293
3294        for phase in phaseData:
3295            Phase = phaseData[phase]
3296            pId = phaseNames.index(phase)
3297            Phase['pId'] = pId
3298            if Phase['Histograms']:
3299                if phase not in Phases:
3300                    Phases[phase] = Phase
3301                for hist in Phase['Histograms']:
3302                    if 'Use' not in Phase['Histograms'][hist]:      #patch: add Use flag as True
3303                        Phase['Histograms'][hist]['Use'] = True         
3304                    if hist not in Histograms and Phase['Histograms'][hist]['Use']:
3305                        item = G2gd.GetPatternTreeItemId(self,self.root,hist)
3306                        if item:
3307                            if 'PWDR' in hist[:4]: 
3308                                Histograms[hist] = self.GetPWDRdatafromTree(item)
3309                            elif 'HKLF' in hist[:4]:
3310                                Histograms[hist] = self.GetHKLFdatafromTree(item)
3311                            hId = histoList.index(hist)
3312                            Histograms[hist]['hId'] = hId
3313                        else: # would happen if a referenced histogram were renamed or deleted
3314                            print('For phase "'+str(phase)+
3315                                  '" unresolved reference to histogram "'+str(hist)+'"')
3316        #G2obj.IndexAllIds(Histograms=Histograms,Phases=Phases)
3317        G2obj.IndexAllIds(Histograms=Histograms,Phases=phaseData)
3318        return Histograms,Phases
3319       
3320    def MakeLSParmDict(self):
3321        '''Load all parameters used for computation from the tree into a
3322        dict of paired values [value, refine flag]. Note that this is
3323        different than the parmDict used in the refinement, which only has
3324        values.
3325
3326        Note that similar things are done in
3327        :meth:`GSASIIIO.ExportBaseclass.loadParmDict` (from the tree) and
3328        :func:`GSASIIstrMain.Refine` and :func:`GSASIIstrMain.SeqRefine` (from
3329        a GPX file).
3330
3331        :returns: (parmDict,varyList) where:
3332
3333         * parmDict is a dict with values and refinement flags
3334           for each parameter and
3335         * varyList is a list of variables (refined parameters).
3336        '''
3337        parmDict = {}
3338        Histograms,Phases = self.GetUsedHistogramsAndPhasesfromTree()
3339        for phase in Phases:
3340            if 'pId' not in Phases[phase]:
3341                self.ErrorDialog('View parameter error','You must run least squares at least once')
3342                raise Exception,'No pId for phase '+str(phase)
3343        rigidbodyDict = self.PatternTree.GetItemPyData(   
3344            G2gd.GetPatternTreeItemId(self,self.root,'Rigid bodies'))
3345        rbVary,rbDict = G2stIO.GetRigidBodyModels(rigidbodyDict,Print=False)
3346        rbIds = rigidbodyDict.get('RBIds',{'Vector':[],'Residue':[]})
3347        Natoms,atomIndx,phaseVary,phaseDict,pawleyLookup,FFtable,BLtable = G2stIO.GetPhaseData(Phases,RestraintDict=None,rbIds=rbIds,Print=False)       
3348        hapVary,hapDict,controlDict = G2stIO.GetHistogramPhaseData(Phases,Histograms,Print=False)
3349        histVary,histDict,controlDict = G2stIO.GetHistogramData(Histograms,Print=False)
3350        varyList = rbVary+phaseVary+hapVary+histVary
3351        parmDict.update(rbDict)
3352        parmDict.update(phaseDict)
3353        parmDict.update(hapDict)
3354        parmDict.update(histDict)
3355        for parm in parmDict:
3356            if parm.split(':')[-1] in ['Azimuth','Gonio. radius','Lam1','Lam2',
3357                'Omega','Chi','Phi','nDebye','nPeaks']:
3358                parmDict[parm] = [parmDict[parm],'-']
3359            elif parm.split(':')[-2] in ['Ax','Ay','Az','SHmodel','SHord']:
3360                parmDict[parm] = [parmDict[parm],'-']
3361            elif parm in varyList:
3362                parmDict[parm] = [parmDict[parm],'T']
3363            else:
3364                parmDict[parm] = [parmDict[parm],'F']
3365        # for i in parmDict: print i,'\t',parmDict[i]
3366        # fl = open('parmDict.dat','wb')
3367        # import cPickle
3368        # cPickle.dump(parmDict,fl,1)
3369        # fl.close()
3370        return parmDict,varyList
3371
3372    def ShowLSParms(self,event):
3373        '''Displays a window showing all parameters in the refinement.
3374        Called from the Calculate/View LS Parms menu.
3375        '''
3376        parmDict,varyList = self.MakeLSParmDict()
3377        parmValDict = {}
3378        for i in parmDict:
3379            parmValDict[i] = parmDict[i][0]
3380           
3381        reqVaryList = tuple(varyList) # save requested variables
3382        try:
3383            # process constraints
3384            sub = G2gd.GetPatternTreeItemId(self,self.root,'Constraints') 
3385            Constraints = self.PatternTree.GetItemPyData(sub)
3386            constList = []
3387            for item in Constraints:
3388                if item.startswith('_'): continue
3389                constList += Constraints[item]
3390            G2mv.InitVars()
3391            constrDict,fixedList,ignored = G2stIO.ProcessConstraints(constList)
3392            groups,parmlist = G2mv.GroupConstraints(constrDict)
3393            G2mv.GenerateConstraints(groups,parmlist,varyList,constrDict,fixedList,parmValDict)
3394            G2mv.Map2Dict(parmValDict,varyList)
3395        except:
3396            pass
3397        dlg = G2gd.ShowLSParms(self,'Least Squares Parameters',parmValDict,varyList,reqVaryList)
3398        dlg.ShowModal()
3399        dlg.Destroy()
3400       
3401    def OnRefine(self,event):
3402        '''Perform a refinement.
3403        Called from the Calculate/Refine menu.
3404        '''       
3405        Id = G2gd.GetPatternTreeItemId(self,self.root,'Sequential results')
3406        if Id:
3407            dlg = wx.MessageDialog(
3408                self,
3409                'Your last refinement was sequential. Continue with "Refine", removing previous sequential results?',
3410                'Remove sequential results?',wx.OK|wx.CANCEL)
3411            if dlg.ShowModal() == wx.ID_OK:
3412                self.PatternTree.Delete(Id)
3413                dlg.Destroy()
3414            else:
3415                dlg.Destroy()
3416                return
3417
3418        self.OnFileSave(event)
3419        # check that constraints are OK here
3420        errmsg, warnmsg = G2stIO.CheckConstraints(self.GSASprojectfile)
3421        if errmsg:
3422            print('Error in constraints:\n'+errmsg+
3423                  '\nRefinement not possible')
3424            self.ErrorDialog('Constraint Error',
3425                             'Error in constraints:\n'+errmsg+
3426                             '\nRefinement not possible')
3427            return
3428        if warnmsg:
3429            print('Conflict between refinment flag settings and constraints:\n'+
3430                  warnmsg+'\nRefinement not possible')
3431            self.ErrorDialog('Refinement Flag Error',
3432                             'Conflict between refinment flag settings and constraints:\n'+
3433                             warnmsg+
3434                             '\nRefinement not possible')
3435            return
3436        #works - but it'd be better if it could restore plots
3437        dlg = wx.ProgressDialog('Residual','All data Rw =',101.0, 
3438            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_CAN_ABORT,
3439            parent=self)
3440        Size = dlg.GetSize()
3441        if 50 < Size[0] < 500: # sanity check on size, since this fails w/Win & wx3.0
3442            dlg.SetSize((int(Size[0]*1.2),Size[1])) # increase size a bit along x
3443        dlg.CenterOnParent()
3444        Rw = 100.00
3445        try:
3446            Rw = G2stMn.Refine(self.GSASprojectfile,dlg)
3447        finally:
3448            dlg.Update(101.) # forces the Auto_Hide; needed after move w/Win & wx3.0
3449            dlg.Destroy()
3450            wx.Yield()
3451        oldId =  self.PatternTree.GetSelection()        #retain current selection
3452        oldName = self.PatternTree.GetItemText(oldId)
3453        parentId = self.PatternTree.GetItemParent(oldId)
3454        parentName = ''
3455        if parentId:
3456            parentName = self.PatternTree.GetItemText(parentId)     #find the current data tree name
3457        dlg2 = wx.MessageDialog(self,'Load new result?','Refinement results, Rw =%.3f'%(Rw),wx.OK|wx.CANCEL)
3458        try:
3459            if dlg2.ShowModal() == wx.ID_OK:
3460                Id = 0
3461                self.PatternTree.DeleteChildren(self.root)
3462                if self.HKL: self.HKL = []
3463                if self.G2plotNB.plotList:
3464                    self.G2plotNB.clear()
3465                G2IO.ProjFileOpen(self)
3466                item, cookie = self.PatternTree.GetFirstChild(self.root)
3467                while item and not Id:
3468                    name = self.PatternTree.GetItemText(item)
3469                    if name[:4] in ['PWDR','HKLF']:
3470                        Id = item
3471                    item, cookie = self.PatternTree.GetNextChild(self.root, cookie)               
3472                if Id:
3473                    self.PatternTree.SelectItem(Id)
3474                if parentName:
3475                    parentId = G2gd.GetPatternTreeItemId(self, self.root, parentName)
3476                    if parentId:
3477                        itemId = G2gd.GetPatternTreeItemId(self, parentId, oldName)
3478                    else:
3479                        itemId = G2gd.GetPatternTreeItemId(self, self.root, oldName)
3480                    self.PatternTree.SelectItem(itemId)
3481        finally:
3482            dlg2.Destroy()
3483
3484    def OnSeqRefine(self,event):
3485        '''Perform a sequential refinement.
3486        Called from the Calculate/Sequential refine menu.
3487        '''       
3488        Id = G2gd.GetPatternTreeItemId(self,self.root,'Sequential results')
3489        if not Id:
3490            Id = self.PatternTree.AppendItem(self.root,text='Sequential results')
3491            self.PatternTree.SetItemPyData(Id,{})           
3492        Controls = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,self.root, 'Controls'))
3493        Controls['ShowCell'] = True
3494        self.OnFileSave(event)
3495        # check that constraints are OK here
3496        errmsg, warnmsg = G2stIO.CheckConstraints(self.GSASprojectfile)
3497        if errmsg:
3498            print('Error in constraints:\n'+errmsg+
3499                  '\nRefinement not possible')
3500            self.ErrorDialog('Constraint Error',
3501                             'Error in constraints:\n'+errmsg+
3502                             '\nRefinement not possible')
3503            return
3504        if warnmsg:
3505            print('Conflict between refinment flag settings and constraints:\n'+
3506                  warnmsg+'\nRefinement not possible')
3507            self.ErrorDialog('Refinement Flag Error',
3508                             'Conflict between refinment flag settings and constraints:\n'+
3509                             warnmsg+'\nRefinement not possible')
3510            return
3511        dlg = wx.ProgressDialog('Residual for histogram 0','Powder profile Rwp =',101.0, 
3512            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_CAN_ABORT,
3513            parent=self)           
3514        Size = dlg.GetSize()
3515        if 50 < Size[0] < 500: # sanity check on size, since this fails w/Win & wx3.0
3516            dlg.SetSize((int(Size[0]*1.2),Size[1])) # increase size a bit along x
3517        dlg.CenterOnParent()
3518        try:
3519            G2stMn.SeqRefine(self.GSASprojectfile,dlg)
3520        finally:
3521            dlg.Update(101.) # forces the Auto_Hide; needed after move w/Win & wx3.0
3522            dlg.Destroy()
3523            wx.Yield()
3524        dlg = wx.MessageDialog(self,'Load new result?','Refinement results',wx.OK|wx.CANCEL)
3525        try:
3526            if dlg.ShowModal() == wx.ID_OK:
3527                Id = 0
3528                self.PatternTree.DeleteChildren(self.root)
3529                if self.HKL: self.HKL = []
3530                if self.G2plotNB.plotList:
3531                    self.G2plotNB.clear()
3532                G2IO.ProjFileOpen(self)
3533                Id = G2gd.GetPatternTreeItemId(self,self.root,'Sequential results')
3534                self.PatternTree.SelectItem(Id)
3535
3536        finally:
3537            dlg.Destroy()
3538       
3539    def ErrorDialog(self,title,message,parent=None, wtype=wx.OK):
3540        'Display an error message'
3541        result = None
3542        if parent is None:
3543            dlg = wx.MessageDialog(self, message, title,  wtype)
3544        else:
3545            dlg = wx.MessageDialog(parent, message, title,  wtype)
3546            dlg.CenterOnParent() # not working on Mac
3547        try:
3548            result = dlg.ShowModal()
3549        finally:
3550            dlg.Destroy()
3551        return result
3552
3553class GSASIImain(wx.App):
3554    '''Defines a wxApp for GSAS-II
3555
3556    Creates a wx frame (self.main) which contains the display of the
3557    data tree.
3558    '''
3559    def OnInit(self):
3560        '''Called automatically when the app is created.'''
3561        if '2.7' not in sys.version[:5]:
3562            dlg = wx.MessageDialog(None, 
3563                'GSAS-II requires Python 2.7.x\n Yours is '+sys.version[:5],
3564                'Python version error',  wx.OK)
3565            try:
3566                result = dlg.ShowModal()
3567            finally:
3568                dlg.Destroy()
3569            sys.exit()
3570        self.main = GSASII(None)
3571        self.main.Show()
3572        self.SetTopWindow(self.main)
3573        # DEBUG: jump to sequential results
3574        #Id = G2gd.GetPatternTreeItemId(self.main,self.main.root,'Sequential results')
3575        #self.main.PatternTree.SelectItem(Id)
3576        # end DEBUG
3577        return True
3578    # def MacOpenFile(self, filename):
3579    #     '''Called on Mac every time a file is dropped on the app when it is running,
3580    #     treat this like a File/Open project menu action.
3581    #     Should be ignored on other platforms
3582    #     '''
3583    #     # PATCH: Canopy 1.4 script main seems dropped on app; ignore .py files
3584    #     print 'MacOpen',filename
3585    #     if os.path.splitext(filename)[1] == '.py': return
3586    #     # end PATCH
3587    #     self.main.OnFileOpen(None,filename)
3588    # removed because this gets triggered when a file is on the command line in canopy 1.4 -- not likely used anyway
3589   
3590def main():
3591    '''Start up the GSAS-II application'''
3592    #application = GSASIImain() # don't redirect output, someday we
3593    # may want to do this if we can
3594    application = GSASIImain(0)
3595    if wxInspector:
3596        import wx.lib.inspection as wxeye
3597        wxeye.InspectionTool().Show()
3598
3599    #application.main.OnRefine(None)
3600    application.MainLoop()
3601   
3602if __name__ == '__main__':
3603    # print versions
3604    print "Python module versions loaded:"
3605    print "python:     ",sys.version[:5]
3606    print "wxpython:   ",wx.__version__
3607    print "matplotlib: ",mpl.__version__
3608    print "numpy:      ",np.__version__
3609    print "scipy:      ",sp.__version__
3610    print "OpenGL:     ",ogl.__version__
3611    try:
3612        from PIL import Image
3613        try:
3614            from PIL import PILLOW_VERSION
3615            version = PILLOW_VERSION
3616        except:
3617            version = Image.VERSION
3618        print "pillow:     ",version
3619    except ImportError:
3620        try:
3621            import Image
3622            print "Image (PIL):",Image.VERSION
3623        except ImportError:
3624            print "Image module not present; Note that PIL (Python Imaging Library) or pillow is needed for some image operations"
3625    try:
3626        import mkl
3627        print "Max threads ",mkl.get_max_threads()
3628    except:
3629        pass
3630    import platform
3631    print "Platform info:",sys.platform,platform.architecture()[0],platform.machine()
3632    #print "wxPython description",wx.PlatformInfo
3633    print "This is GSAS-II version:     ",__version__,' revision '+str(GSASIIpath.GetVersionNumber())
3634    GSASIIpath.InvokeDebugOpts()
3635    main() # start the GUI
Note: See TracBrowser for help on using the repository browser.