source: trunk/GSASII.py @ 2043

Last change on this file since 2043 was 2043, checked in by vondreele, 8 years ago

some SS deriv work
trap G2frame.PatternId? = None (or 0) in PLotPatterns
put missing import numpy in G2img_1TIF.py

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