source: trunk/GSASII.py @ 1601

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

remove some more (3+2) & (3+3) supersymmetry stuff
begin implementation of 4D Fourier maps & their display
implement super lattice for cif reflection import
fix space groups imported from cif

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