source: trunk/autoint.py @ 2047

Last change on this file since 2047 was 2047, checked in by toby, 8 years ago

revise autoint to implement Reset -- redoes integration; warn on old image read

  • Property svn:eol-style set to native
File size: 19.0 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.CreatedPWDRnames.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.CreatedPWDRnames:
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.CreatedPWDRnames = [] # 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        self.CreatedPWDRnames = [] # list of created PWDR tree item names
313        wx.Frame.__init__(self, G2frame,title='Automatic Integration')
314        self.Status = self.CreateStatusBar()
315        self.Status.SetStatusText('Press Start to load and integrate images matching filter')
316        mnpnl = wx.Panel(self)
317        mnsizer = wx.BoxSizer(wx.VERTICAL)
318        sizer = wx.BoxSizer(wx.HORIZONTAL)
319        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Integration based on: '))
320        self.ControlBaseLbl = wx.StaticText(mnpnl, wx.ID_ANY,'?')
321        self.ControlBaseLbl.SetLabel(G2frame.PatternTree.GetItemText(G2frame.Image))
322        sizer.Add(self.ControlBaseLbl)
323        mnsizer.Add(sizer,0,wx.ALIGN_LEFT,1)
324        # file filter stuff
325        sizer = wx.BoxSizer(wx.HORIZONTAL)
326        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Image filter'))
327        flterInp = G2G.ValidatedTxtCtrl(mnpnl,self.params,'filter')
328        sizer.Add(flterInp)
329        mnsizer.Add(sizer,0,wx.ALIGN_RIGHT,1)
330        # box for integration controls & masks input
331        lbl = wx.StaticBox(mnpnl, wx.ID_ANY, "Integration Controls/Masks source")
332        lblsizr = wx.StaticBoxSizer(lbl, wx.VERTICAL)
333        r1 = wx.RadioButton(mnpnl, wx.ID_ANY, "Use Active Image",
334                            style = wx.RB_GROUP)
335        r1.Bind(wx.EVT_RADIOBUTTON, OnRadioSelect)
336        lblsizr.Add(r1)
337        r1.SetValue(True)
338        r2 = wx.RadioButton(mnpnl, wx.ID_ANY, "Use from file(s)")
339        lblsizr.Add(r2)
340        r2.Bind(wx.EVT_RADIOBUTTON, OnRadioSelect)
341        r2.Disable()         # deactivate this until implemented
342        # Image controls file
343        sizer = wx.BoxSizer(wx.HORIZONTAL)
344        sizer.Add((20,-1))
345        lbl1 = wx.StaticText(mnpnl, wx.ID_ANY,'IMG control file: ')
346        sizer.Add(lbl1)
347        fInp1 = G2G.ValidatedTxtCtrl(mnpnl,self.params,'IMGfile',
348                                       notBlank=False,size=(300,-1))
349        sizer.Add(fInp1)
350        btn1 = wx.Button(mnpnl,  wx.ID_ANY, "Browse")
351        btn1.Bind(wx.EVT_BUTTON, OnBrowse)
352        sizer.Add(btn1)
353        lblsizr.Add(sizer)
354        # Masks input file
355        sizer = wx.BoxSizer(wx.HORIZONTAL)
356        sizer.Add((20,-1))
357        lbl2 = wx.StaticText(mnpnl, wx.ID_ANY,'Mask file: ')
358        sizer.Add(lbl2)
359        fInp2 = G2G.ValidatedTxtCtrl(mnpnl,self.params,'MaskFile',
360                                       notBlank=False,size=(300,-1))
361        sizer.Add(fInp2)
362        ign2 = G2G.G2CheckBox(mnpnl,"Don't use",self.params,'IgnoreMask',
363                              OnChange=OnRadioSelect)
364        sizer.Add(ign2)
365        btn2 = wx.Button(mnpnl,  wx.ID_ANY, "Browse")
366        btn2.Bind(wx.EVT_BUTTON, OnBrowse)
367        sizer.Add(btn2)
368        lblsizr.Add(sizer)
369        mnsizer.Add(lblsizr)
370
371        # box for output selections
372        lbl = wx.StaticBox(mnpnl, wx.ID_ANY, "Output settings")
373        lblsizr = wx.StaticBoxSizer(lbl, wx.VERTICAL)
374        sizer = wx.BoxSizer(wx.HORIZONTAL)
375        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Write to: '))
376        fInp3 = G2G.ValidatedTxtCtrl(mnpnl,self.params,'outdir',
377                                       notBlank=False,size=(300,-1))
378        sizer.Add(fInp3)
379        btn3 = wx.Button(mnpnl,  wx.ID_ANY, "Browse")
380        btn3.Bind(wx.EVT_BUTTON, OnBrowse)
381        sizer.Add(btn3)
382        lblsizr.Add(sizer)
383        #lblsizr.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Select format(s): '))
384        sizer = wx.BoxSizer(wx.HORIZONTAL)
385        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Select format(s): '))
386        for dfmt in self.fmtlist:
387            fmt = dfmt[1:]
388            self.params[fmt] = False
389            btn = G2G.G2CheckBox(mnpnl,dfmt,self.params,fmt)
390            sizer.Add(btn)
391        lblsizr.Add(sizer)
392        sizer = wx.BoxSizer(wx.HORIZONTAL)
393        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Separate dir for each format: '))
394        self.params['SeparateDir'] = False
395        sizer.Add(G2G.G2CheckBox(mnpnl,'',self.params,'SeparateDir'))
396        lblsizr.Add(sizer)
397        mnsizer.Add(lblsizr,0,wx.ALIGN_CENTER,1)
398
399        # buttons on bottom
400        mnsizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'AutoIntegration controls'),0,wx.TOP,5)
401        sizer = wx.BoxSizer(wx.HORIZONTAL)
402        sizer.Add((20,-1))
403        btnstart = wx.Button(mnpnl,  wx.ID_ANY, "Start")
404        btnstart.Bind(wx.EVT_BUTTON, OnStart)
405        sizer.Add(btnstart)
406        btnstop = wx.Button(mnpnl,  wx.ID_ANY, "Reset")
407        btnstop.Bind(wx.EVT_BUTTON, OnReset)
408        sizer.Add(btnstop)
409        sizer.Add((20,-1),wx.EXPAND,1)
410        btnquit = wx.Button(mnpnl,  wx.ID_ANY, "Close")
411        btnquit.Bind(wx.EVT_BUTTON, OnQuit)
412        sizer.Add(btnquit)
413        sizer.Add((20,-1))
414        mnsizer.Add(sizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP,5)
415       
416        # finish up window
417        mnpnl.SetSizer(mnsizer)
418        OnRadioSelect(None) # disable widgets
419        mnsizer.Fit(self)
420        self.CenterOnParent()
421        self.Show() 
422
423if __name__ == '__main__':
424    app = wx.PySimpleApp()
425    G2frame = wx.Frame(None) # create a top-level frame as a stand-in for the GSAS-II data tree
426    G2frame.Show() 
427    frm = AutoIntFrame(G2frame) # test the one above
428    app.MainLoop()
429 
Note: See TracBrowser for help on using the repository browser.