source: trunk/autoint.py @ 2048

Last change on this file since 2048 was 2048, checked in by toby, 7 years ago

move list of PWDR tree items to delete so they are saved

  • Property svn:eol-style set to native
File size: 18.9 KB
Line 
1import os
2import wx
3import copy
4import glob
5import re
6import GSASIIpath
7import GSASIIIO as G2IO
8import GSASIIctrls as G2G
9import GSASIIgrid as G2gd
10import GSASIIimgGUI as G2imG
11'''
12Define a class to be used for Andrey's AutoIntegration process
13'''
14
15class AutoIntFrame(wx.Frame):
16    '''Creates a wx.Frame window for the Image AutoIntegration.
17    The intent is that this will be used as a non-modal dialog window.
18   
19    Implements a Start button that morphs into a pause and resume button.
20    This button starts a processing loop that is repeated every
21    :meth:`PollTime` seconds.
22
23    :param wx.Frame G2frame: main GSAS-II frame
24    :param float PollTime: frequency in seconds to repeat calling the
25      processing loop. (Default is 3.0 seconds.)
26    '''
27    def OnTimerLoop(self,event):
28        '''A method that is called every :meth:`PollTime` seconds that is
29        used to check for new files and process them. This is called only
30        after the "Start" button is pressed (when its label reads "Pause").
31        '''
32        G2frame = self.G2frame
33        try:
34            self.currImageList = sorted(
35                glob.glob(os.path.join(self.imagedir,self.params['filter'])))
36        except IndexError:
37            self.currImageList = []
38            return
39
40        # index of image tree items by file name:
41        imageDict = {G2frame.PatternTree.GetItemPyData(
42            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,img))[1]:
43            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,img)
44                     for img in G2gd.GetPatternTreeDataNames(G2frame,['IMG '])}
45        createdImageIdList = []
46        # loop over files that are found, reading in new ones
47        for newImage in self.currImageList:
48            if newImage in self.G2frame.IntegratedList: continue # already integrated
49            # has this image already been loaded?
50            if newImage not in imageDict:
51                Comments,Data,Npix,Image = G2IO.GetImageData(G2frame,newImage)
52                if not Npix:
53                    print('problem reading '+newImage)
54                    continue
55                G2IO.LoadImage2Tree(newImage,G2frame,Comments,Data,Npix,Image)
56            else:
57                G2frame.Image = imageDict[newImage]
58            # update controls from master
59            controlsDict = G2frame.PatternTree.GetItemPyData(
60                G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
61            controlsDict.update(self.ImageControls)
62            # update masks from master
63            ImageMasks = G2frame.PatternTree.GetItemPyData(
64                G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
65            createdImageIdList.append(G2frame.Image) # save IMG Id
66            self.G2frame.IntegratedList.append(newImage) # save name of image so we don't process it again
67            #print('debug: read '+newImage)
68
69        # now integrate the images we have read
70        for newImagId in createdImageIdList:
71            G2frame.Image = newImagId
72            G2frame.PickId = G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls')
73            #  integrate in this entry
74            size,imagefile = G2frame.PatternTree.GetItemPyData(G2frame.Image)
75            masks = G2frame.PatternTree.GetItemPyData(
76                G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
77            data = G2frame.PatternTree.GetItemPyData(G2frame.PickId)
78            G2frame.ImageZ = G2IO.GetImageData(G2frame,imagefile,True)
79            self.oldImagefile = '' # mark image as changed; reread as needed
80            # simulate a Image Controls press, since that is where the
81            # integration is hidden
82            G2imG.UpdateImageControls(G2frame,data,masks,IntegrateOnly=True)
83            # split name and control number
84            s = re.split(r'(\d+)\Z',os.path.split(os.path.splitext(imagefile)[0])[1])
85            namepre = s[0]
86            if len(s) > 1:
87                namenum = s[1]
88            else:
89                namenum = ''
90            # write out the images in the selected formats and save the names,
91            # reset will delete them
92            for Id in G2frame.IntgOutList:
93                treename = G2frame.PatternTree.GetItemText(Id)
94                self.G2frame.AutointPWDRnames.append(treename)
95                Sdata = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Sample Parameters'))
96                # determine the name for the current file
97                fileroot = namepre
98                if len(G2frame.IntgOutList) > 1:
99                    fileroot += "_AZM"
100                    if 'Azimuth' in Sdata:
101                        fileroot += str(int(10*Sdata['Azimuth']))
102                    fileroot += "_" 
103                fileroot += namenum
104                # loop over selected formats
105                for dfmt in self.fmtlist:
106                    if not self.params[dfmt[1:]]: continue
107                    if self.params['SeparateDir']:
108                        subdir = dfmt[1:]
109                    else:
110                        subdir = ''
111                    fil = os.path.join(self.params['outdir'],subdir,fileroot)
112                    print('writing file '+fil+dfmt)
113                    G2IO.ExportPowder(G2frame,treename,fil,dfmt)
114       
115        if GSASIIpath.GetConfigValue('debug'):
116            import datetime
117            print ("Timer tick at {:%d %b %Y %H:%M:%S}\n".format(datetime.datetime.now()))
118
119    def StartLoop(self):
120        '''Save current Image params for use in future integrations
121        also label the window so users understand whatis being used
122        '''
123        print '\nStarting new autointegration\n'
124        # show current IMG base
125        self.ControlBaseLbl.SetLabel(self.G2frame.PatternTree.GetItemText(self.G2frame.Image))
126        if self.params['Mode'] == 'file':
127            'get file info'
128            GSASIIpath.IPyBreak()
129        else:
130            # load copy of Image Controls from current image and clean up
131            # items that should not be copied
132            self.ImageControls = copy.deepcopy(
133                self.G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(
134                    self.G2frame,self.G2frame.Image, 'Image Controls')))
135            self.ImageControls['showLines'] = True
136            self.ImageControls['ring'] = []
137            self.ImageControls['rings'] = []
138            self.ImageControls['ellipses'] = []
139            self.ImageControls['setDefault'] = False
140            del self.ImageControls['range']
141            del self.ImageControls['size']
142            del self.ImageControls['GonioAngles']
143            # load copy of Image Masks, keep thresholds
144            self.ImageMasks = copy.deepcopy(
145                self.G2frame.PatternTree.GetItemPyData(
146                    G2gd.GetPatternTreeItemId(self.G2frame,self.G2frame.Image, 'Masks')))
147            self.Thresholds = self.ImageMasks['Thresholds'][:]
148        # make sure all output directories exist
149        if self.params['SeparateDir']:
150            for dfmt in self.fmtlist:
151                if not self.params[dfmt[1:]]: continue
152                dir = os.path.join(self.params['outdir'],dfmt[1:])
153                if not os.path.exists(dir): os.makedirs(dir)
154        else:
155            if not os.path.exists(self.params['outdir']):
156                os.makedirs(self.params['outdir'])
157        if self.Reset: # after Reset has been pressed, delete all PWDR items
158            # created after last Start was pressed
159            G2frame = self.G2frame
160            idlist = []
161            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
162            while item:
163                itemName = G2frame.PatternTree.GetItemText(item)
164                if itemName in self.G2frame.AutointPWDRnames:
165                    idlist.append(item)
166                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
167            for item in idlist:
168                G2frame.PatternTree.Delete(item)
169        self.Reset = False
170        self.G2frame.AutointPWDRnames = [] # list of created PWDR tree item names
171
172    def __init__(self,G2frame,PollTime=60.0):
173        def OnStart(event):
174            '''Called when the start button is pressed. Changes button label
175            to Pause. When Pause is pressed the label changes to Resume.
176            When either Start or Resume is pressed, the processing loop
177            is started. When Pause is pressed, the loop is stopped.
178            '''
179            #print self.params # for debug
180
181            # check inputs before starting
182            err = ''
183            #if not any([self.params[fmt] for fmt in self.fmtlist]):
184            #    err += '\nPlease select at least one output format\n'
185            if (self.params['Mode'] == 'file' and not
186                    os.path.exists(self.params['IMGfile'])):
187                err += '\nThe image controls file could not be found\n'
188            if (self.params['Mode'] == 'file' and
189                not self.params['IgnoreMask']
190                ) and not os.path.exists(self.params['MaskFile']): 
191                err += '\nThe mask file could not be found\n'
192            if err:
193                G2G.G2MessageBox(self,err)
194                return
195            # change button label
196            if btnstart.GetLabel() != 'Pause':
197                btnstart.SetLabel('Pause')
198                if self.timer.IsRunning(): self.timer.Stop()
199                self.StartLoop()
200                self.OnTimerLoop(None) # run once immediately and again after delay
201                self.timer.Start(int(1000*PollTime),oneShot=False)
202                self.Status.SetStatusText('Press Pause to delay integration or Reset to prepare to reintegrate all images')
203            else:
204                btnstart.SetLabel('Resume')
205                if self.timer.IsRunning(): self.timer.Stop()
206                print('\nPausing autointegration\n')
207                self.Status.SetStatusText('Press Resume to continue integration or Reset to prepare to reintegrate all images')
208
209        def OnReset(event):
210            '''Called when Reset button is pressed. This stops the
211            processing loop and resets the list of integrated files so
212            all images can be reintegrated.
213            '''
214            btnstart.SetLabel('Restart')
215            self.Status.SetStatusText('Press Restart to reload and re-integrate images matching filter')
216            if self.timer.IsRunning(): self.timer.Stop()
217            self.Reset = True
218            self.G2frame.IntegratedList = []
219           
220        def OnQuit(event):
221            '''Stop the processing loop and close the Frame
222            '''
223            if self.timer.IsRunning(): self.timer.Stop() # make sure we stop first
224            wx.CallAfter(self.Destroy)
225           
226        def OnBrowse(event):
227            '''Responds when the Browse button is pressed to load a file.
228            The routine determines which button was pressed and gets the
229            appropriate file type and loads it into the appropriate place
230            in the dict.
231            '''
232            if btn3 == event.GetEventObject():
233                dlg = wx.DirDialog(
234                    self, 'Select directory for output files',
235                    self.params['outdir'],wx.DD_DEFAULT_STYLE)
236                dlg.CenterOnParent()
237                try:
238                    if dlg.ShowModal() == wx.ID_OK:
239                        self.params['outdir'] = dlg.GetPath()
240                        fInp3.SetValue(self.params['outdir'])
241                finally:
242                    dlg.Destroy()
243                return
244            if btn1 == event.GetEventObject():
245                ext = '.imctrl'
246                title = 'Image control'
247            else:
248                ext = '.immask'
249                title = 'Image masks'               
250            dlg = wx.FileDialog(
251                self, 'Select name for '+title+' file to read',
252                '.', '',
253                title+'file (*'+ext+')|*'+ext,
254                wx.OPEN|wx.CHANGE_DIR)
255            dlg.CenterOnParent()
256            try:
257                if dlg.ShowModal() == wx.ID_OK:
258                    filename = dlg.GetPath()
259                    # make sure extension is correct
260                    #filename = os.path.splitext(filename)[0]+ext
261                    if btn1 == event.GetEventObject():
262                        fInp1.SetValue(filename)
263                    else:
264                        fInp2.SetValue(filename)
265                else:
266                    filename = None
267            finally:
268                dlg.Destroy()
269               
270        def OnRadioSelect(event):
271            '''Respond to a radiobutton selection and enable or
272            disable widgets accordingly. Also gets called when the
273            "Don't Use" flag for Mask use is called.
274            '''
275            lbl1.Disable()
276            fInp1.Disable()
277            btn1.Disable()
278            lbl2.Disable()
279            fInp2.Disable()
280            ign2.Disable()
281            btn2.Disable()
282            if r2.GetValue():
283                self.params['Mode'] = 'file'
284                fInp1.Enable()
285                btn1.Enable()
286                lbl1.Enable()
287                ign2.Enable()
288                if not self.params['IgnoreMask']:
289                    fInp2.Enable()
290                    btn2.Enable()
291                    lbl2.Enable()
292            else:
293                self.params['Mode'] = 'active'
294        ##################################################
295        # beginning of __init__ processing
296        ##################################################
297        self.G2frame = G2frame
298        self.params = {}
299        self.Reset = False
300        self.params['IMGfile'] = ''
301        self.params['MaskFile'] = ''
302        self.params['IgnoreMask'] = True
303        self.fmtlist = G2IO.ExportPowderList(G2frame)
304        self.timer = wx.Timer()
305        self.timer.Bind(wx.EVT_TIMER,self.OnTimerLoop)
306
307        controlsId = G2frame.PatternTree.GetSelection()
308        size,imagefile = G2frame.PatternTree.GetItemPyData(G2frame.Image)
309        self.imagedir,fileroot = os.path.split(imagefile)
310        self.params['filter'] = '*'+os.path.splitext(fileroot)[1]
311        self.params['outdir'] = os.path.abspath(self.imagedir)
312        wx.Frame.__init__(self, G2frame,title='Automatic Integration')
313        self.Status = self.CreateStatusBar()
314        self.Status.SetStatusText('Press Start to load and integrate images matching filter')
315        mnpnl = wx.Panel(self)
316        mnsizer = wx.BoxSizer(wx.VERTICAL)
317        sizer = wx.BoxSizer(wx.HORIZONTAL)
318        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Integration based on: '))
319        self.ControlBaseLbl = wx.StaticText(mnpnl, wx.ID_ANY,'?')
320        self.ControlBaseLbl.SetLabel(G2frame.PatternTree.GetItemText(G2frame.Image))
321        sizer.Add(self.ControlBaseLbl)
322        mnsizer.Add(sizer,0,wx.ALIGN_LEFT,1)
323        # file filter stuff
324        sizer = wx.BoxSizer(wx.HORIZONTAL)
325        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Image filter'))
326        flterInp = G2G.ValidatedTxtCtrl(mnpnl,self.params,'filter')
327        sizer.Add(flterInp)
328        mnsizer.Add(sizer,0,wx.ALIGN_RIGHT,1)
329        # box for integration controls & masks input
330        lbl = wx.StaticBox(mnpnl, wx.ID_ANY, "Integration Controls/Masks source")
331        lblsizr = wx.StaticBoxSizer(lbl, wx.VERTICAL)
332        r1 = wx.RadioButton(mnpnl, wx.ID_ANY, "Use Active Image",
333                            style = wx.RB_GROUP)
334        r1.Bind(wx.EVT_RADIOBUTTON, OnRadioSelect)
335        lblsizr.Add(r1)
336        r1.SetValue(True)
337        r2 = wx.RadioButton(mnpnl, wx.ID_ANY, "Use from file(s)")
338        lblsizr.Add(r2)
339        r2.Bind(wx.EVT_RADIOBUTTON, OnRadioSelect)
340        r2.Disable()         # deactivate this until implemented
341        # Image controls file
342        sizer = wx.BoxSizer(wx.HORIZONTAL)
343        sizer.Add((20,-1))
344        lbl1 = wx.StaticText(mnpnl, wx.ID_ANY,'IMG control file: ')
345        sizer.Add(lbl1)
346        fInp1 = G2G.ValidatedTxtCtrl(mnpnl,self.params,'IMGfile',
347                                       notBlank=False,size=(300,-1))
348        sizer.Add(fInp1)
349        btn1 = wx.Button(mnpnl,  wx.ID_ANY, "Browse")
350        btn1.Bind(wx.EVT_BUTTON, OnBrowse)
351        sizer.Add(btn1)
352        lblsizr.Add(sizer)
353        # Masks input file
354        sizer = wx.BoxSizer(wx.HORIZONTAL)
355        sizer.Add((20,-1))
356        lbl2 = wx.StaticText(mnpnl, wx.ID_ANY,'Mask file: ')
357        sizer.Add(lbl2)
358        fInp2 = G2G.ValidatedTxtCtrl(mnpnl,self.params,'MaskFile',
359                                       notBlank=False,size=(300,-1))
360        sizer.Add(fInp2)
361        ign2 = G2G.G2CheckBox(mnpnl,"Don't use",self.params,'IgnoreMask',
362                              OnChange=OnRadioSelect)
363        sizer.Add(ign2)
364        btn2 = wx.Button(mnpnl,  wx.ID_ANY, "Browse")
365        btn2.Bind(wx.EVT_BUTTON, OnBrowse)
366        sizer.Add(btn2)
367        lblsizr.Add(sizer)
368        mnsizer.Add(lblsizr)
369
370        # box for output selections
371        lbl = wx.StaticBox(mnpnl, wx.ID_ANY, "Output settings")
372        lblsizr = wx.StaticBoxSizer(lbl, wx.VERTICAL)
373        sizer = wx.BoxSizer(wx.HORIZONTAL)
374        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Write to: '))
375        fInp3 = G2G.ValidatedTxtCtrl(mnpnl,self.params,'outdir',
376                                       notBlank=False,size=(300,-1))
377        sizer.Add(fInp3)
378        btn3 = wx.Button(mnpnl,  wx.ID_ANY, "Browse")
379        btn3.Bind(wx.EVT_BUTTON, OnBrowse)
380        sizer.Add(btn3)
381        lblsizr.Add(sizer)
382        #lblsizr.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Select format(s): '))
383        sizer = wx.BoxSizer(wx.HORIZONTAL)
384        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Select format(s): '))
385        for dfmt in self.fmtlist:
386            fmt = dfmt[1:]
387            self.params[fmt] = False
388            btn = G2G.G2CheckBox(mnpnl,dfmt,self.params,fmt)
389            sizer.Add(btn)
390        lblsizr.Add(sizer)
391        sizer = wx.BoxSizer(wx.HORIZONTAL)
392        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Separate dir for each format: '))
393        self.params['SeparateDir'] = False
394        sizer.Add(G2G.G2CheckBox(mnpnl,'',self.params,'SeparateDir'))
395        lblsizr.Add(sizer)
396        mnsizer.Add(lblsizr,0,wx.ALIGN_CENTER,1)
397
398        # buttons on bottom
399        mnsizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'AutoIntegration controls'),0,wx.TOP,5)
400        sizer = wx.BoxSizer(wx.HORIZONTAL)
401        sizer.Add((20,-1))
402        btnstart = wx.Button(mnpnl,  wx.ID_ANY, "Start")
403        btnstart.Bind(wx.EVT_BUTTON, OnStart)
404        sizer.Add(btnstart)
405        btnstop = wx.Button(mnpnl,  wx.ID_ANY, "Reset")
406        btnstop.Bind(wx.EVT_BUTTON, OnReset)
407        sizer.Add(btnstop)
408        sizer.Add((20,-1),wx.EXPAND,1)
409        btnquit = wx.Button(mnpnl,  wx.ID_ANY, "Close")
410        btnquit.Bind(wx.EVT_BUTTON, OnQuit)
411        sizer.Add(btnquit)
412        sizer.Add((20,-1))
413        mnsizer.Add(sizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP,5)
414       
415        # finish up window
416        mnpnl.SetSizer(mnsizer)
417        OnRadioSelect(None) # disable widgets
418        mnsizer.Fit(self)
419        self.CenterOnParent()
420        self.Show() 
421
422if __name__ == '__main__':
423    app = wx.PySimpleApp()
424    G2frame = wx.Frame(None) # create a top-level frame as a stand-in for the GSAS-II data tree
425    G2frame.Show() 
426    frm = AutoIntFrame(G2frame) # test the one above
427    app.MainLoop()
428 
Note: See TracBrowser for help on using the repository browser.