1 | # -*- coding: utf-8 -*- |
---|
2 | #GSASIIseqGUI - Sequential Results Display routines |
---|
3 | ########### SVN repository information ################### |
---|
4 | # $Date: 2022-03-30 02:30:42 +0000 (Wed, 30 Mar 2022) $ |
---|
5 | # $Author: toby $ |
---|
6 | # $Revision: 5255 $ |
---|
7 | # $URL: trunk/GSASIIseqGUI.py $ |
---|
8 | # $Id: GSASIIseqGUI.py 5255 2022-03-30 02:30:42Z toby $ |
---|
9 | ########### SVN repository information ################### |
---|
10 | ''' |
---|
11 | *GSASIIseqGUI: Sequential Results GUI* |
---|
12 | ---------------------------------------- |
---|
13 | |
---|
14 | Module that defines GUI routines and classes for the main GUI Frame (window) |
---|
15 | and the main routines that define the GSAS-II tree panel and much of the |
---|
16 | data editing panel. |
---|
17 | ''' |
---|
18 | from __future__ import division, print_function |
---|
19 | import platform |
---|
20 | import copy |
---|
21 | import re |
---|
22 | import numpy as np |
---|
23 | import numpy.ma as ma |
---|
24 | import scipy.optimize as so |
---|
25 | try: |
---|
26 | import wx |
---|
27 | import wx.grid as wg |
---|
28 | except ImportError: |
---|
29 | pass |
---|
30 | import GSASIIpath |
---|
31 | GSASIIpath.SetVersionNumber("$Revision: 5255 $") |
---|
32 | import GSASIImath as G2mth |
---|
33 | import GSASIIIO as G2IO |
---|
34 | import GSASIIdataGUI as G2gd |
---|
35 | import GSASIIstrIO as G2stIO |
---|
36 | import GSASIIlattice as G2lat |
---|
37 | import GSASIIplot as G2plt |
---|
38 | import GSASIImapvars as G2mv |
---|
39 | import GSASIIobj as G2obj |
---|
40 | import GSASIIexprGUI as G2exG |
---|
41 | import GSASIIctrlGUI as G2G |
---|
42 | |
---|
43 | ##### Display of Sequential Results ########################################## |
---|
44 | def UpdateSeqResults(G2frame,data,prevSize=None): |
---|
45 | """ |
---|
46 | Called when the Sequential Results data tree entry is selected |
---|
47 | to show results from a sequential refinement. |
---|
48 | |
---|
49 | :param wx.Frame G2frame: main GSAS-II data tree windows |
---|
50 | |
---|
51 | :param dict data: a dictionary containing the following items: |
---|
52 | |
---|
53 | * 'histNames' - list of histogram names in order as processed by Sequential Refinement |
---|
54 | * 'varyList' - list of variables - identical over all refinements in sequence |
---|
55 | note that this is the original list of variables, prior to processing |
---|
56 | constraints. |
---|
57 | * 'variableLabels' -- a dict of labels to be applied to each parameter |
---|
58 | (this is created as an empty dict if not present in data). |
---|
59 | * keyed by histName - dictionaries for all data sets processed, which contains: |
---|
60 | |
---|
61 | * 'variables'- result[0] from leastsq call |
---|
62 | * 'varyList' - list of variables passed to leastsq call (not same as above) |
---|
63 | * 'sig' - esds for variables |
---|
64 | * 'covMatrix' - covariance matrix from individual refinement |
---|
65 | * 'title' - histogram name; same as dict item name |
---|
66 | * 'newAtomDict' - new atom parameters after shifts applied |
---|
67 | * 'newCellDict' - refined cell parameters after shifts to A0-A5 from Dij terms applied' |
---|
68 | """ |
---|
69 | def GetSampleParms(): |
---|
70 | '''Make a dictionary of the sample parameters that are not the same over the |
---|
71 | refinement series. Controls here is local |
---|
72 | ''' |
---|
73 | if 'IMG' in histNames[0]: |
---|
74 | sampleParmDict = {'Sample load':[],} |
---|
75 | elif 'PDF' in histNames[0]: |
---|
76 | sampleParmDict = {'Temperature':[]} |
---|
77 | else: |
---|
78 | sampleParmDict = {'Temperature':[],'Pressure':[],'Time':[], |
---|
79 | 'FreePrm1':[],'FreePrm2':[],'FreePrm3':[],'Omega':[], |
---|
80 | 'Chi':[],'Phi':[],'Azimuth':[],} |
---|
81 | Controls = G2frame.GPXtree.GetItemPyData( |
---|
82 | G2gd.GetGPXtreeItemId(G2frame,G2frame.root, 'Controls')) |
---|
83 | sampleParm = {} |
---|
84 | for name in histNames: |
---|
85 | if 'IMG' in name or 'PDF' in name: |
---|
86 | if name not in data: |
---|
87 | continue |
---|
88 | for item in sampleParmDict: |
---|
89 | sampleParmDict[item].append(data[name]['parmDict'].get(item,0)) |
---|
90 | else: |
---|
91 | if 'PDF' in name: |
---|
92 | name = 'PWDR' + name[4:] |
---|
93 | Id = G2gd.GetGPXtreeItemId(G2frame,G2frame.root,name) |
---|
94 | if Id: |
---|
95 | sampleData = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,Id,'Sample Parameters')) |
---|
96 | else: # item missing from tree! stick in NaN's! |
---|
97 | sampleData = {} |
---|
98 | for item in sampleParmDict: |
---|
99 | sampleParmDict[item].append(sampleData.get(item,np.NaN)) |
---|
100 | for item in sampleParmDict: |
---|
101 | if sampleParmDict[item]: |
---|
102 | frstValue = sampleParmDict[item][0] |
---|
103 | if np.any(np.array(sampleParmDict[item])-frstValue): |
---|
104 | if item.startswith('FreePrm'): |
---|
105 | sampleParm[Controls[item]] = sampleParmDict[item] |
---|
106 | else: |
---|
107 | sampleParm[item] = sampleParmDict[item] |
---|
108 | return sampleParm |
---|
109 | |
---|
110 | def GetColumnInfo(col): |
---|
111 | '''returns column label, lists of values and errors (or None) for each column in the table |
---|
112 | for plotting. The column label is reformatted from Unicode to MatPlotLib encoding |
---|
113 | ''' |
---|
114 | colName = G2frame.SeqTable.GetColLabelValue(col) |
---|
115 | plotName = variableLabels.get(colName,colName) |
---|
116 | plotName = plotSpCharFix(plotName) |
---|
117 | return plotName,G2frame.colList[col],G2frame.colSigs[col] |
---|
118 | |
---|
119 | def PlotSelectedColRow(calltyp='',event=None): |
---|
120 | '''Called to plot a selected column or row by clicking |
---|
121 | on a row or column label. N.B. This is called for LB click |
---|
122 | after the event is processed so that the column or row has been |
---|
123 | selected. For RB clicks, the event is processed here |
---|
124 | |
---|
125 | :param str calltyp: ='left'/'right', specifies if this was |
---|
126 | a left- or right-click, where a left click on row |
---|
127 | plots histogram; Right click on row plots V-C matrix; |
---|
128 | Left or right click on column: plots values in column |
---|
129 | :param obj event: from wx.EVT_GRID_LABEL_RIGHT_CLICK |
---|
130 | ''' |
---|
131 | rows = [] |
---|
132 | cols = [] |
---|
133 | if calltyp == 'left': |
---|
134 | cols = G2frame.dataDisplay.GetSelectedCols() |
---|
135 | rows = G2frame.dataDisplay.GetSelectedRows() |
---|
136 | elif calltyp == 'right': |
---|
137 | r,c = event.GetRow(),event.GetCol() |
---|
138 | if r > -1: |
---|
139 | rows = [r,] |
---|
140 | elif c > -1: |
---|
141 | cols = [c,] |
---|
142 | if cols and calltyp == 'left': |
---|
143 | G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis) |
---|
144 | elif cols and calltyp == 'right': |
---|
145 | SetLabelString(cols[0]) #only the 1st one selected! |
---|
146 | elif rows and calltyp == 'left': |
---|
147 | name = histNames[rows[0]] #only does 1st one selected |
---|
148 | if name.startswith('PWDR'): |
---|
149 | pickId = G2frame.PickId |
---|
150 | G2frame.PickId = G2frame.PatternId = G2gd.GetGPXtreeItemId(G2frame, G2frame.root, name) |
---|
151 | G2plt.PlotPatterns(G2frame,newPlot=False,plotType='PWDR') |
---|
152 | G2frame.PickId = pickId |
---|
153 | elif name.startswith('PDF'): |
---|
154 | pickId = G2frame.PickId |
---|
155 | G2frame.PickId = G2frame.PatternId = G2gd.GetGPXtreeItemId(G2frame, G2frame.root, name) |
---|
156 | PFdata = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.PickId,'PDF Controls')) |
---|
157 | G2plt.PlotISFG(G2frame,PFdata,plotType='G(R)') |
---|
158 | G2frame.PickId = pickId |
---|
159 | else: |
---|
160 | return |
---|
161 | elif rows and calltyp == 'right': |
---|
162 | name = histNames[rows[0]] #only does 1st one selected |
---|
163 | if name.startswith('PWDR'): |
---|
164 | if len(data[name].get('covMatrix',[])): |
---|
165 | G2plt.PlotCovariance(G2frame,data[name]) |
---|
166 | elif name.startswith('PDF'): |
---|
167 | print('make structure plot') |
---|
168 | else: |
---|
169 | G2frame.ErrorDialog( |
---|
170 | 'Select row or columns', |
---|
171 | 'Nothing selected in table. Click on column or row label(s) to plot. N.B. Grid selection can be a bit funky.' |
---|
172 | ) |
---|
173 | |
---|
174 | def SetLabelString(col): |
---|
175 | '''Define or edit the label for a column in the table, to be used |
---|
176 | as a tooltip and for plotting |
---|
177 | ''' |
---|
178 | if col < 0 or col > len(colLabels): |
---|
179 | return |
---|
180 | var = colLabels[col] |
---|
181 | lbl = variableLabels.get(var,G2obj.fmtVarDescr(var)) |
---|
182 | head = u'Set a new name for variable {} (column {})'.format(var,col) |
---|
183 | dlg = G2G.SingleStringDialog(G2frame,'Set variable label', |
---|
184 | head,lbl,size=(400,-1)) |
---|
185 | if dlg.Show(): |
---|
186 | variableLabels[var] = dlg.GetValue() |
---|
187 | dlg.Destroy() |
---|
188 | wx.CallAfter(UpdateSeqResults,G2frame,data) # redisplay variables |
---|
189 | else: |
---|
190 | dlg.Destroy() |
---|
191 | |
---|
192 | def PlotLeftSelect(event): |
---|
193 | 'Called by a left MB click on a row or column label. ' |
---|
194 | event.Skip() |
---|
195 | wx.CallAfter(PlotSelectedColRow,'left') |
---|
196 | |
---|
197 | def PlotRightSelect(event): |
---|
198 | 'Called by a right MB click on a row or column label' |
---|
199 | PlotSelectedColRow('right',event) |
---|
200 | |
---|
201 | def OnPlotSelSeq(event): |
---|
202 | 'plot the selected columns or row from menu command' |
---|
203 | cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order |
---|
204 | rows = G2frame.dataDisplay.GetSelectedRows() |
---|
205 | if cols: |
---|
206 | G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis) |
---|
207 | elif rows: |
---|
208 | name = histNames[rows[0]] #only does 1st one selected |
---|
209 | G2plt.PlotCovariance(G2frame,data[name]) |
---|
210 | else: |
---|
211 | G2frame.ErrorDialog('Select columns', |
---|
212 | 'No columns or rows selected in table. Click on row or column labels to select fields for plotting.') |
---|
213 | |
---|
214 | def OnAveSelSeq(event): |
---|
215 | 'average the selected columns from menu command' |
---|
216 | cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order |
---|
217 | useCol = ~np.array(G2frame.SeqTable.GetColValues(1),dtype=bool) |
---|
218 | if cols: |
---|
219 | for col in cols: |
---|
220 | items = GetColumnInfo(col)[1] |
---|
221 | noneMask = np.array([item is None for item in items]) |
---|
222 | info = ma.array(items,mask=useCol+noneMask) |
---|
223 | ave = ma.mean(ma.compressed(info)) |
---|
224 | sig = ma.std(ma.compressed(info)) |
---|
225 | print (u' Average for '+G2frame.SeqTable.GetColLabelValue(col)+u': '+'%.6g'%(ave)+u' +/- '+u'%.6g'%(sig)) |
---|
226 | else: |
---|
227 | G2frame.ErrorDialog('Select columns', |
---|
228 | 'No columns selected in table. Click on column labels to select fields for averaging.') |
---|
229 | |
---|
230 | def OnSelectUse(event): |
---|
231 | dlg = G2G.G2MultiChoiceDialog(G2frame, 'Select rows to use','Select rows',histNames) |
---|
232 | sellist = [i for i,item in enumerate(G2frame.colList[1]) if item] |
---|
233 | dlg.SetSelections(sellist) |
---|
234 | if dlg.ShowModal() == wx.ID_OK: |
---|
235 | sellist = dlg.GetSelections() |
---|
236 | for row in range(G2frame.SeqTable.GetNumberRows()): |
---|
237 | G2frame.SeqTable.SetValue(row,1,False) |
---|
238 | G2frame.colList[1][row] = False |
---|
239 | for row in sellist: |
---|
240 | G2frame.SeqTable.SetValue(row,1,True) |
---|
241 | G2frame.colList[1][row] = True |
---|
242 | G2frame.dataDisplay.ForceRefresh() |
---|
243 | dlg.Destroy() |
---|
244 | |
---|
245 | def OnRenameSelSeq(event): |
---|
246 | cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order |
---|
247 | colNames = [G2frame.SeqTable.GetColLabelValue(c) for c in cols] |
---|
248 | newNames = colNames[:] |
---|
249 | for i,name in enumerate(colNames): |
---|
250 | if name in variableLabels: |
---|
251 | newNames[i] = variableLabels[name] |
---|
252 | if not cols: |
---|
253 | G2frame.ErrorDialog('Select columns', |
---|
254 | 'No columns selected in table. Click on column labels to select fields for rename.') |
---|
255 | return |
---|
256 | dlg = G2G.MultiStringDialog(G2frame.dataDisplay,'Set column names',colNames,newNames) |
---|
257 | if dlg.Show(): |
---|
258 | newNames = dlg.GetValues() |
---|
259 | variableLabels.update(dict(zip(colNames,newNames))) |
---|
260 | data['variableLabels'] = variableLabels |
---|
261 | dlg.Destroy() |
---|
262 | UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables |
---|
263 | G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis) |
---|
264 | |
---|
265 | def OnSaveSelSeqCSV(event): |
---|
266 | 'export the selected columns to a .csv file from menu command' |
---|
267 | OnSaveSelSeq(event,csv=True) |
---|
268 | |
---|
269 | def OnSaveSeqCSV(event): |
---|
270 | 'export all columns to a .csv file from menu command' |
---|
271 | OnSaveSelSeq(event,csv=True,allcols=True) |
---|
272 | |
---|
273 | def OnSaveSelSeq(event,csv=False,allcols=False): |
---|
274 | 'export the selected columns to a .txt or .csv file from menu command' |
---|
275 | def WriteLine(line): |
---|
276 | if '2' in platform.python_version_tuple()[0]: |
---|
277 | SeqFile.write(G2obj.StripUnicode(line)) |
---|
278 | else: |
---|
279 | SeqFile.write(line) |
---|
280 | |
---|
281 | def WriteCSV(): |
---|
282 | def WriteList(headerItems): |
---|
283 | line = '' |
---|
284 | for lbl in headerItems: |
---|
285 | if line: line += ',' |
---|
286 | line += '"'+lbl+'"' |
---|
287 | return line |
---|
288 | head = ['name'] |
---|
289 | for col in cols: |
---|
290 | # Excel does not like unicode |
---|
291 | item = G2obj.StripUnicode(G2frame.SeqTable.GetColLabelValue(col)) |
---|
292 | if col in havesig: |
---|
293 | head += [item,'esd-'+item] |
---|
294 | else: |
---|
295 | head += [item] |
---|
296 | WriteLine(WriteList(head)+'\n') |
---|
297 | for row,name in enumerate(saveNames): |
---|
298 | line = '"'+saveNames[row]+'"' |
---|
299 | for col in cols: |
---|
300 | if saveData[col][row] is None: |
---|
301 | if col in havesig: |
---|
302 | # line += ',0.0,0.0' |
---|
303 | line += ',,' |
---|
304 | else: |
---|
305 | # line += ',0.0' |
---|
306 | line += ',' |
---|
307 | else: |
---|
308 | if col in havesig: |
---|
309 | line += ','+str(saveData[col][row])+','+str(saveSigs[col][row]) |
---|
310 | else: |
---|
311 | line += ','+str(saveData[col][row]) |
---|
312 | WriteLine(line+'\n') |
---|
313 | def WriteSeq(): |
---|
314 | lenName = len(saveNames[0]) |
---|
315 | line = ' %s '%('name'.center(lenName)) |
---|
316 | for col in cols: |
---|
317 | item = G2frame.SeqTable.GetColLabelValue(col) |
---|
318 | if col in havesig: |
---|
319 | line += ' %12s %12s '%(item.center(12),'esd'.center(12)) |
---|
320 | else: |
---|
321 | line += ' %12s '%(item.center(12)) |
---|
322 | WriteLine(line+'\n') |
---|
323 | for row,name in enumerate(saveNames): |
---|
324 | line = " '%s' "%(saveNames[row]) |
---|
325 | for col in cols: |
---|
326 | if col in havesig: |
---|
327 | try: |
---|
328 | line += ' %12.6f %12.6f '%(saveData[col][row],saveSigs[col][row]) |
---|
329 | except TypeError: |
---|
330 | line += ' ' |
---|
331 | else: |
---|
332 | try: |
---|
333 | line += ' %12.6f '%saveData[col][row] |
---|
334 | except TypeError: |
---|
335 | line += ' ' |
---|
336 | WriteLine(line+'\n') |
---|
337 | |
---|
338 | # start of OnSaveSelSeq code |
---|
339 | if allcols: |
---|
340 | cols = range(G2frame.SeqTable.GetNumberCols()) |
---|
341 | else: |
---|
342 | cols = sorted(G2frame.dataDisplay.GetSelectedCols()) # ignore selection order |
---|
343 | nrows = G2frame.SeqTable.GetNumberRows() |
---|
344 | if not cols: |
---|
345 | choices = [G2frame.SeqTable.GetColLabelValue(r) for r in range(G2frame.SeqTable.GetNumberCols())] |
---|
346 | dlg = G2G.G2MultiChoiceDialog(G2frame, 'Select columns to write', |
---|
347 | 'select columns',choices) |
---|
348 | #dlg.SetSelections() |
---|
349 | if dlg.ShowModal() == wx.ID_OK: |
---|
350 | cols = dlg.GetSelections() |
---|
351 | dlg.Destroy() |
---|
352 | else: |
---|
353 | dlg.Destroy() |
---|
354 | return |
---|
355 | #G2frame.ErrorDialog('Select columns', |
---|
356 | # 'No columns selected in table. Click on column labels to select fields for output.') |
---|
357 | #return |
---|
358 | saveNames = [G2frame.SeqTable.GetRowLabelValue(r) for r in range(nrows)] |
---|
359 | saveData = {} |
---|
360 | saveSigs = {} |
---|
361 | havesig = [] |
---|
362 | for col in cols: |
---|
363 | name,vals,sigs = GetColumnInfo(col) |
---|
364 | saveData[col] = vals |
---|
365 | if sigs: |
---|
366 | havesig.append(col) |
---|
367 | saveSigs[col] = sigs |
---|
368 | if csv: |
---|
369 | wild = 'CSV output file (*.csv)|*.csv' |
---|
370 | else: |
---|
371 | wild = 'Text output file (*.txt)|*.txt' |
---|
372 | pth = G2G.GetExportPath(G2frame) |
---|
373 | dlg = wx.FileDialog( |
---|
374 | G2frame, |
---|
375 | 'Choose text output file for your selection', pth, '', |
---|
376 | wild,wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) |
---|
377 | try: |
---|
378 | if dlg.ShowModal() == wx.ID_OK: |
---|
379 | SeqTextFile = dlg.GetPath() |
---|
380 | SeqTextFile = G2IO.FileDlgFixExt(dlg,SeqTextFile) |
---|
381 | SeqFile = open(SeqTextFile,'w') |
---|
382 | if csv: |
---|
383 | WriteCSV() |
---|
384 | else: |
---|
385 | WriteSeq() |
---|
386 | SeqFile.close() |
---|
387 | finally: |
---|
388 | dlg.Destroy() |
---|
389 | |
---|
390 | def striphist(var,insChar=''): |
---|
391 | 'strip a histogram number from a var name' |
---|
392 | sv = var.split(':') |
---|
393 | if len(sv) <= 1: return var |
---|
394 | if sv[1]: |
---|
395 | sv[1] = insChar |
---|
396 | return ':'.join(sv) |
---|
397 | |
---|
398 | def plotSpCharFix(lbl): |
---|
399 | 'Change selected unicode characters to their matplotlib equivalent' |
---|
400 | for u,p in [ |
---|
401 | (u'\u03B1',r'$\alpha$'), |
---|
402 | (u'\u03B2',r'$\beta$'), |
---|
403 | (u'\u03B3',r'$\gamma$'), |
---|
404 | (u'\u0394\u03C7',r'$\Delta\chi$'), |
---|
405 | ]: |
---|
406 | lbl = lbl.replace(u,p) |
---|
407 | return lbl |
---|
408 | |
---|
409 | def SelectXaxis(): |
---|
410 | 'returns a selected column number (or None) as the X-axis selection' |
---|
411 | ncols = G2frame.SeqTable.GetNumberCols() |
---|
412 | colNames = [G2frame.SeqTable.GetColLabelValue(r) for r in range(ncols)] |
---|
413 | dlg = G2G.G2SingleChoiceDialog( |
---|
414 | G2frame.dataDisplay, |
---|
415 | 'Select x-axis parameter for\nplot (Cancel=sequence #)', |
---|
416 | 'Select X-axis', |
---|
417 | colNames) |
---|
418 | try: |
---|
419 | if dlg.ShowModal() == wx.ID_OK: |
---|
420 | col = dlg.GetSelection() |
---|
421 | else: |
---|
422 | col = None |
---|
423 | finally: |
---|
424 | dlg.Destroy() |
---|
425 | return col |
---|
426 | |
---|
427 | def EnablePseudoVarMenus(): |
---|
428 | 'Enables or disables the PseudoVar menu items that require existing defs' |
---|
429 | if data['SeqPseudoVars']: |
---|
430 | val = True |
---|
431 | else: |
---|
432 | val = False |
---|
433 | G2frame.dataWindow.SequentialPvars.Enable(G2G.wxID_DELSEQVAR,val) |
---|
434 | G2frame.dataWindow.SequentialPvars.Enable(G2G.wxID_EDITSEQVAR,val) |
---|
435 | |
---|
436 | def DelPseudoVar(event): |
---|
437 | 'Ask the user to select a pseudo var expression to delete' |
---|
438 | choices = list(data['SeqPseudoVars'].keys()) |
---|
439 | selected = G2G.ItemSelector( |
---|
440 | choices,G2frame, |
---|
441 | multiple=True, |
---|
442 | title='Select expressions to remove', |
---|
443 | header='Delete expression') |
---|
444 | if selected is None: return |
---|
445 | for item in selected: |
---|
446 | del data['SeqPseudoVars'][choices[item]] |
---|
447 | if selected: |
---|
448 | UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables |
---|
449 | |
---|
450 | def EditPseudoVar(event): |
---|
451 | 'Edit an existing pseudo var expression' |
---|
452 | choices = list(data['SeqPseudoVars'].keys()) |
---|
453 | if len(choices) == 1: |
---|
454 | selected = 0 |
---|
455 | else: |
---|
456 | selected = G2G.ItemSelector( |
---|
457 | choices,G2frame, |
---|
458 | multiple=False, |
---|
459 | title='Select an expression to edit', |
---|
460 | header='Edit expression') |
---|
461 | if selected is not None: |
---|
462 | dlg = G2exG.ExpressionDialog( |
---|
463 | G2frame.dataDisplay,PSvarDict, |
---|
464 | data['SeqPseudoVars'][choices[selected]], |
---|
465 | header="Edit the PseudoVar expression", |
---|
466 | VarLabel="PseudoVar #"+str(selected+1), |
---|
467 | fit=False) |
---|
468 | newobj = dlg.Show(True) |
---|
469 | if newobj: |
---|
470 | calcobj = G2obj.ExpressionCalcObj(newobj) |
---|
471 | del data['SeqPseudoVars'][choices[selected]] |
---|
472 | data['SeqPseudoVars'][calcobj.eObj.expression] = newobj |
---|
473 | UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables |
---|
474 | |
---|
475 | def AddNewPseudoVar(event): |
---|
476 | 'Create a new pseudo var expression' |
---|
477 | dlg = G2exG.ExpressionDialog(G2frame.dataDisplay,PSvarDict, |
---|
478 | header='Enter an expression for a PseudoVar here', |
---|
479 | VarLabel = "New PseudoVar",fit=False) |
---|
480 | obj = dlg.Show(True) |
---|
481 | dlg.Destroy() |
---|
482 | if obj: |
---|
483 | calcobj = G2obj.ExpressionCalcObj(obj) |
---|
484 | data['SeqPseudoVars'][calcobj.eObj.expression] = obj |
---|
485 | UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables |
---|
486 | |
---|
487 | def AddNewDistPseudoVar(event): |
---|
488 | obj = None |
---|
489 | dlg = G2exG.BondDialog( |
---|
490 | G2frame.dataDisplay,Phases,PSvarDict, |
---|
491 | VarLabel = "New Bond") |
---|
492 | if dlg.ShowModal() == wx.ID_OK: |
---|
493 | pName,Oatom,Tatom = dlg.GetSelection() |
---|
494 | if Tatom: |
---|
495 | Phase = Phases[pName] |
---|
496 | General = Phase['General'] |
---|
497 | cx,ct = General['AtomPtrs'][:2] |
---|
498 | pId = Phase['pId'] |
---|
499 | SGData = General['SGData'] |
---|
500 | sB = Tatom.find('(')+1 |
---|
501 | symNo = 0 |
---|
502 | if sB: |
---|
503 | sF = Tatom.find(')') |
---|
504 | symNo = int(Tatom[sB:sF]) |
---|
505 | cellNo = [0,0,0] |
---|
506 | cB = Tatom.find('[') |
---|
507 | if cB>0: |
---|
508 | cF = Tatom.find(']')+1 |
---|
509 | cellNo = eval(Tatom[cB:cF]) |
---|
510 | Atoms = Phase['Atoms'] |
---|
511 | aNames = [atom[ct-1] for atom in Atoms] |
---|
512 | oId = aNames.index(Oatom) |
---|
513 | tId = aNames.index(Tatom.split(' +')[0]) |
---|
514 | # create an expression object |
---|
515 | obj = G2obj.ExpressionObj() |
---|
516 | obj.expression = 'Dist(%s,\n%s)'%(Oatom,Tatom.split(' d=')[0].replace(' ','')) |
---|
517 | obj.distance_dict = {'pId':pId,'SGData':SGData,'symNo':symNo,'cellNo':cellNo} |
---|
518 | obj.distance_atoms = [oId,tId] |
---|
519 | else: |
---|
520 | dlg.Destroy() |
---|
521 | return |
---|
522 | dlg.Destroy() |
---|
523 | if obj: |
---|
524 | data['SeqPseudoVars'][obj.expression] = obj |
---|
525 | UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables |
---|
526 | |
---|
527 | def AddNewAnglePseudoVar(event): |
---|
528 | obj = None |
---|
529 | dlg = G2exG.AngleDialog( |
---|
530 | G2frame.dataDisplay,Phases,PSvarDict, |
---|
531 | header='Enter an Angle here', |
---|
532 | VarLabel = "New Angle") |
---|
533 | if dlg.ShowModal() == wx.ID_OK: |
---|
534 | pName,Oatom,Tatoms = dlg.GetSelection() |
---|
535 | if Tatoms: |
---|
536 | obj = G2obj.makeAngleObj(Phases[pName],Oatom,Tatoms) |
---|
537 | else: |
---|
538 | dlg.Destroy() |
---|
539 | return |
---|
540 | dlg.Destroy() |
---|
541 | if obj: |
---|
542 | data['SeqPseudoVars'][obj.expression] = obj |
---|
543 | UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables |
---|
544 | |
---|
545 | def UpdateParmDict(parmDict): |
---|
546 | '''generate the atom positions and the direct & reciprocal cell values, |
---|
547 | because they might be needed to evaluate the pseudovar |
---|
548 | #TODO - effect of ISO modes? |
---|
549 | ''' |
---|
550 | Ddict = dict(zip(['D11','D22','D33','D12','D13','D23'], |
---|
551 | ['A'+str(i) for i in range(6)]) |
---|
552 | ) |
---|
553 | delList = [] |
---|
554 | phaselist = [] |
---|
555 | for item in parmDict: |
---|
556 | if ':' not in item: continue |
---|
557 | key = item.split(':') |
---|
558 | if len(key) < 3: continue |
---|
559 | # remove the dA[xyz] terms, they would only bring confusion |
---|
560 | if key[0] and key[0] not in phaselist: phaselist.append(key[0]) |
---|
561 | if key[2].startswith('dA'): |
---|
562 | delList.append(item) |
---|
563 | # compute and update the corrected reciprocal cell terms using the Dij values |
---|
564 | elif key[2] in Ddict: |
---|
565 | akey = key[0]+'::'+Ddict[key[2]] |
---|
566 | parmDict[akey] += parmDict[item] |
---|
567 | delList.append(item) |
---|
568 | for item in delList: |
---|
569 | del parmDict[item] |
---|
570 | for i in phaselist: |
---|
571 | pId = int(i) |
---|
572 | # apply cell symmetry |
---|
573 | try: |
---|
574 | A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata[pId],parmDict,zeroDict[pId]) |
---|
575 | # convert to direct cell & add the unique terms to the dictionary |
---|
576 | try: |
---|
577 | dcell = G2lat.A2cell(A) |
---|
578 | except: |
---|
579 | print('phase',pId,'Invalid cell tensor',A) |
---|
580 | raise ValueError('Invalid cell tensor in phase '+str(pId)) |
---|
581 | for i,val in enumerate(dcell): |
---|
582 | if i in uniqCellIndx[pId]: |
---|
583 | lbl = str(pId)+'::'+G2lat.cellUlbl[i] |
---|
584 | parmDict[lbl] = val |
---|
585 | lbl = str(pId)+'::'+'Vol' |
---|
586 | parmDict[lbl] = G2lat.calc_V(A) |
---|
587 | except KeyError: |
---|
588 | pass |
---|
589 | return parmDict |
---|
590 | |
---|
591 | def EvalPSvarDeriv(calcobj,parmDict,sampleDict,var,ESD): |
---|
592 | '''Evaluate an expression derivative with respect to a |
---|
593 | GSAS-II variable name. |
---|
594 | |
---|
595 | Note this likely could be faster if the loop over calcobjs were done |
---|
596 | inside after the Dict was created. |
---|
597 | ''' |
---|
598 | if not ESD: |
---|
599 | return 0. |
---|
600 | step = ESD/10 |
---|
601 | Ddict = dict(zip(['D11','D22','D33','D12','D13','D23'], |
---|
602 | ['A'+str(i) for i in range(6)]) |
---|
603 | ) |
---|
604 | results = [] |
---|
605 | phaselist = [] |
---|
606 | VparmDict = sampleDict.copy() |
---|
607 | for incr in step,-step: |
---|
608 | VparmDict.update(parmDict.copy()) |
---|
609 | # as saved, the parmDict has updated 'A[xyz]' values, but 'dA[xyz]' |
---|
610 | # values are not zeroed: fix that! |
---|
611 | VparmDict.update({item:0.0 for item in parmDict if 'dA' in item}) |
---|
612 | VparmDict[var] += incr |
---|
613 | G2mv.Dict2Map(VparmDict) # apply constraints |
---|
614 | # generate the atom positions and the direct & reciprocal cell values now, because they might |
---|
615 | # needed to evaluate the pseudovar |
---|
616 | for item in VparmDict: |
---|
617 | if item in sampleDict: |
---|
618 | continue |
---|
619 | if ':' not in item: continue |
---|
620 | key = item.split(':') |
---|
621 | if len(key) < 3: continue |
---|
622 | # apply any new shifts to atom positions |
---|
623 | if key[2].startswith('dA'): |
---|
624 | VparmDict[''.join(item.split('d'))] += VparmDict[item] |
---|
625 | VparmDict[item] = 0.0 |
---|
626 | # compute and update the corrected reciprocal cell terms using the Dij values |
---|
627 | if key[2] in Ddict: |
---|
628 | if key[0] not in phaselist: phaselist.append(key[0]) |
---|
629 | akey = key[0]+'::'+Ddict[key[2]] |
---|
630 | VparmDict[akey] += VparmDict[item] |
---|
631 | for i in phaselist: |
---|
632 | pId = int(i) |
---|
633 | # apply cell symmetry |
---|
634 | try: |
---|
635 | A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata[pId],VparmDict,zeroDict[pId]) |
---|
636 | # convert to direct cell & add the unique terms to the dictionary |
---|
637 | for i,val in enumerate(G2lat.A2cell(A)): |
---|
638 | if i in uniqCellIndx[pId]: |
---|
639 | lbl = str(pId)+'::'+G2lat.cellUlbl[i] |
---|
640 | VparmDict[lbl] = val |
---|
641 | lbl = str(pId)+'::'+'Vol' |
---|
642 | VparmDict[lbl] = G2lat.calc_V(A) |
---|
643 | except KeyError: |
---|
644 | pass |
---|
645 | # dict should be fully updated, use it & calculate |
---|
646 | calcobj.SetupCalc(VparmDict) |
---|
647 | results.append(calcobj.EvalExpression()) |
---|
648 | if None in results: |
---|
649 | return None |
---|
650 | return (results[0] - results[1]) / (2.*step) |
---|
651 | |
---|
652 | def EnableParFitEqMenus(): |
---|
653 | 'Enables or disables the Parametric Fit menu items that require existing defs' |
---|
654 | if data['SeqParFitEqList']: |
---|
655 | val = True |
---|
656 | else: |
---|
657 | val = False |
---|
658 | G2frame.dataWindow.SequentialPfit.Enable(G2G.wxID_DELPARFIT,val) |
---|
659 | G2frame.dataWindow.SequentialPfit.Enable(G2G.wxID_EDITPARFIT,val) |
---|
660 | G2frame.dataWindow.SequentialPfit.Enable(G2G.wxID_DOPARFIT,val) |
---|
661 | |
---|
662 | def ParEqEval(Values,calcObjList,varyList): |
---|
663 | '''Evaluate the parametric expression(s) |
---|
664 | :param list Values: a list of values for each variable parameter |
---|
665 | :param list calcObjList: a list of :class:`GSASIIobj.ExpressionCalcObj` |
---|
666 | expression objects to evaluate |
---|
667 | :param list varyList: a list of variable names for each value in Values |
---|
668 | ''' |
---|
669 | result = [] |
---|
670 | for calcobj in calcObjList: |
---|
671 | calcobj.UpdateVars(varyList,Values) |
---|
672 | if calcobj.depSig: |
---|
673 | result.append((calcobj.depVal-calcobj.EvalExpression())/calcobj.depSig) |
---|
674 | else: |
---|
675 | result.append(calcobj.depVal-calcobj.EvalExpression()) |
---|
676 | return result |
---|
677 | |
---|
678 | def DoParEqFit(event,eqObj=None): |
---|
679 | 'Parametric fit minimizer' |
---|
680 | varyValueDict = {} # dict of variables and their initial values |
---|
681 | calcObjList = [] # expression objects, ready to go for each data point |
---|
682 | if eqObj is not None: |
---|
683 | eqObjList = [eqObj,] |
---|
684 | else: |
---|
685 | eqObjList = data['SeqParFitEqList'] |
---|
686 | UseFlags = G2frame.SeqTable.GetColValues(1) |
---|
687 | for obj in eqObjList: |
---|
688 | # assemble refined vars for this equation |
---|
689 | varyValueDict.update({var:val for var,val in obj.GetVariedVarVal()}) |
---|
690 | # lookup dependent var position |
---|
691 | depVar = obj.GetDepVar() |
---|
692 | if depVar in colLabels: |
---|
693 | indx = colLabels.index(depVar) |
---|
694 | else: |
---|
695 | raise Exception('Dependent variable '+depVar+' not found') |
---|
696 | # assemble a list of the independent variables |
---|
697 | indepVars = obj.GetIndependentVars() |
---|
698 | # loop over each datapoint |
---|
699 | for j,row in enumerate(zip(*G2frame.colList)): |
---|
700 | if not UseFlags[j]: continue |
---|
701 | # assemble equations to fit |
---|
702 | calcobj = G2obj.ExpressionCalcObj(obj) |
---|
703 | # prepare a dict of needed independent vars for this expression |
---|
704 | indepVarDict = {var:row[i] for i,var in enumerate(colLabels) if var in indepVars} |
---|
705 | calcobj.SetupCalc(indepVarDict) |
---|
706 | # values and sigs for current value of dependent var |
---|
707 | if row[indx] is None: continue |
---|
708 | calcobj.depVal = row[indx] |
---|
709 | if G2frame.colSigs[indx]: |
---|
710 | calcobj.depSig = G2frame.colSigs[indx][j] |
---|
711 | else: |
---|
712 | calcobj.depSig = 1. |
---|
713 | calcObjList.append(calcobj) |
---|
714 | # varied parameters |
---|
715 | varyList = varyValueDict.keys() |
---|
716 | values = varyValues = [varyValueDict[key] for key in varyList] |
---|
717 | if not varyList: |
---|
718 | print ('no variables to refine!') |
---|
719 | return |
---|
720 | try: |
---|
721 | result = so.leastsq(ParEqEval,varyValues,full_output=True, #ftol=Ftol, |
---|
722 | args=(calcObjList,varyList)) |
---|
723 | values = result[0] |
---|
724 | covar = result[1] |
---|
725 | if covar is None: |
---|
726 | raise Exception |
---|
727 | chisq = np.sum(result[2]['fvec']**2) |
---|
728 | GOF = np.sqrt(chisq/(len(calcObjList)-len(varyList))) |
---|
729 | esdDict = {} |
---|
730 | for i,avar in enumerate(varyList): |
---|
731 | esdDict[avar] = np.sqrt(covar[i,i]) |
---|
732 | except: |
---|
733 | print('====> Fit failed') |
---|
734 | return |
---|
735 | print('==== Fit Results ====') |
---|
736 | print (' chisq = %.2f, GOF = %.2f'%(chisq,GOF)) |
---|
737 | for obj in eqObjList: |
---|
738 | obj.UpdateVariedVars(varyList,values) |
---|
739 | ind = ' ' |
---|
740 | print(u' '+obj.GetDepVar()+u' = '+obj.expression) |
---|
741 | for var in obj.assgnVars: |
---|
742 | print(ind+var+u' = '+obj.assgnVars[var]) |
---|
743 | for var in obj.freeVars: |
---|
744 | avar = "::"+obj.freeVars[var][0] |
---|
745 | val = obj.freeVars[var][1] |
---|
746 | if obj.freeVars[var][2]: |
---|
747 | print(ind+var+u' = '+avar + " = " + G2mth.ValEsd(val,esdDict[avar])) |
---|
748 | else: |
---|
749 | print(ind+var+u' = '+avar + u" =" + G2mth.ValEsd(val,0)) |
---|
750 | # create a plot for each parametric variable |
---|
751 | for fitnum,obj in enumerate(eqObjList): |
---|
752 | calcobj = G2obj.ExpressionCalcObj(obj) |
---|
753 | # lookup dependent var position |
---|
754 | indx = colLabels.index(obj.GetDepVar()) |
---|
755 | # assemble a list of the independent variables |
---|
756 | indepVars = obj.GetIndependentVars() |
---|
757 | # loop over each datapoint |
---|
758 | fitvals = [] |
---|
759 | for j,row in enumerate(zip(*G2frame.colList)): |
---|
760 | calcobj.SetupCalc({var:row[i] for i,var in enumerate(colLabels) if var in indepVars}) |
---|
761 | fitvals.append(calcobj.EvalExpression()) |
---|
762 | G2plt.PlotSelectedSequence(G2frame,[indx],GetColumnInfo,SelectXaxis,fitnum,fitvals) |
---|
763 | |
---|
764 | def SingleParEqFit(eqObj): |
---|
765 | DoParEqFit(None,eqObj) |
---|
766 | |
---|
767 | def DelParFitEq(event): |
---|
768 | 'Ask the user to select function to delete' |
---|
769 | txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in data['SeqParFitEqList']] |
---|
770 | selected = G2G.ItemSelector( |
---|
771 | txtlst,G2frame, |
---|
772 | multiple=True, |
---|
773 | title='Select a parametric equation(s) to remove', |
---|
774 | header='Delete equation') |
---|
775 | if selected is None: return |
---|
776 | data['SeqParFitEqList'] = [obj for i,obj in enumerate(data['SeqParFitEqList']) if i not in selected] |
---|
777 | EnableParFitEqMenus() |
---|
778 | if data['SeqParFitEqList']: DoParEqFit(event) |
---|
779 | |
---|
780 | def EditParFitEq(event): |
---|
781 | 'Edit an existing parametric equation' |
---|
782 | txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in data['SeqParFitEqList']] |
---|
783 | if len(txtlst) == 1: |
---|
784 | selected = 0 |
---|
785 | else: |
---|
786 | selected = G2G.ItemSelector( |
---|
787 | txtlst,G2frame, |
---|
788 | multiple=False, |
---|
789 | title='Select a parametric equation to edit', |
---|
790 | header='Edit equation') |
---|
791 | if selected is not None: |
---|
792 | dlg = G2exG.ExpressionDialog(G2frame.dataDisplay,VarDict, |
---|
793 | data['SeqParFitEqList'][selected],depVarDict=VarDict, |
---|
794 | header="Edit the formula for this minimization function", |
---|
795 | ExtraButton=['Fit',SingleParEqFit],wildCard=False) |
---|
796 | newobj = dlg.Show(True) |
---|
797 | if newobj: |
---|
798 | data['SeqParFitEqList'][selected] = newobj |
---|
799 | EnableParFitEqMenus() |
---|
800 | if data['SeqParFitEqList']: DoParEqFit(event) |
---|
801 | |
---|
802 | def AddNewParFitEq(event): |
---|
803 | 'Create a new parametric equation to be fit to sequential results' |
---|
804 | |
---|
805 | # compile the variable names used in previous freevars to avoid accidental name collisions |
---|
806 | usedvarlist = [] |
---|
807 | for obj in data['SeqParFitEqList']: |
---|
808 | for var in obj.freeVars: |
---|
809 | if obj.freeVars[var][0] not in usedvarlist: usedvarlist.append(obj.freeVars[var][0]) |
---|
810 | |
---|
811 | dlg = G2exG.ExpressionDialog(G2frame.dataDisplay,VarDict,depVarDict=VarDict, |
---|
812 | header='Define an equation to minimize in the parametric fit', |
---|
813 | ExtraButton=['Fit',SingleParEqFit],usedVars=usedvarlist,wildCard=False) |
---|
814 | obj = dlg.Show(True) |
---|
815 | dlg.Destroy() |
---|
816 | if obj: |
---|
817 | data['SeqParFitEqList'].append(obj) |
---|
818 | EnableParFitEqMenus() |
---|
819 | if data['SeqParFitEqList']: DoParEqFit(event) |
---|
820 | |
---|
821 | def CopyParFitEq(event): |
---|
822 | 'Copy an existing parametric equation to be fit to sequential results' |
---|
823 | # compile the variable names used in previous freevars to avoid accidental name collisions |
---|
824 | usedvarlist = [] |
---|
825 | for obj in data['SeqParFitEqList']: |
---|
826 | for var in obj.freeVars: |
---|
827 | if obj.freeVars[var][0] not in usedvarlist: usedvarlist.append(obj.freeVars[var][0]) |
---|
828 | txtlst = [obj.GetDepVar()+' = '+obj.expression for obj in data['SeqParFitEqList']] |
---|
829 | if len(txtlst) == 1: |
---|
830 | selected = 0 |
---|
831 | else: |
---|
832 | selected = G2G.ItemSelector( |
---|
833 | txtlst,G2frame, |
---|
834 | multiple=False, |
---|
835 | title='Select a parametric equation to copy', |
---|
836 | header='Copy equation') |
---|
837 | if selected is not None: |
---|
838 | newEqn = copy.deepcopy(data['SeqParFitEqList'][selected]) |
---|
839 | for var in newEqn.freeVars: |
---|
840 | newEqn.freeVars[var][0] = G2obj.MakeUniqueLabel(newEqn.freeVars[var][0],usedvarlist) |
---|
841 | dlg = G2exG.ExpressionDialog( |
---|
842 | G2frame.dataDisplay,VarDict,newEqn,depVarDict=VarDict, |
---|
843 | header="Edit the formula for this minimization function", |
---|
844 | ExtraButton=['Fit',SingleParEqFit],wildCard=False) |
---|
845 | newobj = dlg.Show(True) |
---|
846 | if newobj: |
---|
847 | data['SeqParFitEqList'].append(newobj) |
---|
848 | EnableParFitEqMenus() |
---|
849 | if data['SeqParFitEqList']: DoParEqFit(event) |
---|
850 | |
---|
851 | def GridSetToolTip(row,col): |
---|
852 | '''Routine to show standard uncertainties for each element in table |
---|
853 | as a tooltip |
---|
854 | ''' |
---|
855 | if G2frame.colSigs[col]: |
---|
856 | if G2frame.colSigs[col][row] == -0.1: return 'frozen' |
---|
857 | return u'\u03c3 = '+str(G2frame.colSigs[col][row]) |
---|
858 | return '' |
---|
859 | |
---|
860 | def GridColLblToolTip(col): |
---|
861 | '''Define a tooltip for a column. This will be the user-entered value |
---|
862 | (from data['variableLabels']) or the default name |
---|
863 | ''' |
---|
864 | if col < 0 or col > len(colLabels): |
---|
865 | print ('Illegal column #%d'%col) |
---|
866 | return |
---|
867 | var = colLabels[col] |
---|
868 | return variableLabels.get(var,G2obj.fmtVarDescr(var)) |
---|
869 | |
---|
870 | def DoSequentialExport(event): |
---|
871 | '''Event handler for all Sequential Export menu items |
---|
872 | ''' |
---|
873 | if event.GetId() == G2G.wxID_XPORTSEQFCIF: |
---|
874 | G2IO.ExportSequentialFullCIF(G2frame,data,Controls) |
---|
875 | return |
---|
876 | vals = G2frame.dataWindow.SeqExportLookup.get(event.GetId()) |
---|
877 | if vals is None: |
---|
878 | print('Error: Id not found. This should not happen!') |
---|
879 | return |
---|
880 | G2IO.ExportSequential(G2frame,data,*vals) |
---|
881 | |
---|
882 | def onSelectSeqVars(event): |
---|
883 | '''Select which variables will be shown in table''' |
---|
884 | hides = [saveColLabels[2:].index(item) for item in G2frame.SeqTblHideList if |
---|
885 | item in saveColLabels[2:]] |
---|
886 | dlg = G2G.G2MultiChoiceDialog(G2frame, 'Select columns to hide', |
---|
887 | 'Hide columns',saveColLabels[2:]) |
---|
888 | dlg.SetSelections(hides) |
---|
889 | if dlg.ShowModal() == wx.ID_OK: |
---|
890 | G2frame.SeqTblHideList = [saveColLabels[2:][sel] for sel in dlg.GetSelections()] |
---|
891 | dlg.Destroy() |
---|
892 | UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables |
---|
893 | else: |
---|
894 | dlg.Destroy() |
---|
895 | |
---|
896 | def OnCellChange(event): |
---|
897 | c = event.GetCol() |
---|
898 | if c != 1: return |
---|
899 | r = event.GetRow() |
---|
900 | val = G2frame.SeqTable.GetValue(r,c) |
---|
901 | data['Use'][r] = val |
---|
902 | G2frame.SeqTable.SetValue(r,c, val) |
---|
903 | |
---|
904 | def OnSelectUpdate(event): |
---|
905 | '''Update all phase parameters from a selected column in the Sequential Table. |
---|
906 | If no histogram is selected (or more than one), ask the user to make a selection. |
---|
907 | |
---|
908 | Loosely based on :func:`GSASIIstrIO.SetPhaseData` |
---|
909 | #TODO effect of ISO modes? |
---|
910 | ''' |
---|
911 | rows = G2frame.dataDisplay.GetSelectedRows() |
---|
912 | if len(rows) == 1: |
---|
913 | sel = rows[0] |
---|
914 | else: |
---|
915 | dlg = G2G.G2SingleChoiceDialog(G2frame, 'Select a histogram to\nupdate phase from', |
---|
916 | 'Select row',histNames) |
---|
917 | if dlg.ShowModal() == wx.ID_OK: |
---|
918 | sel = dlg.GetSelection() |
---|
919 | dlg.Destroy() |
---|
920 | else: |
---|
921 | dlg.Destroy() |
---|
922 | return |
---|
923 | parmDict = data[histNames[sel]]['parmDict'] |
---|
924 | Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree() |
---|
925 | for phase in Phases: |
---|
926 | print('Updating {} from Seq. Ref. row {}'.format(phase,histNames[sel])) |
---|
927 | Phase = Phases[phase] |
---|
928 | General = Phase['General'] |
---|
929 | SGData = General['SGData'] |
---|
930 | Atoms = Phase['Atoms'] |
---|
931 | cell = General['Cell'] |
---|
932 | pId = Phase['pId'] |
---|
933 | pfx = str(pId)+'::' |
---|
934 | # there should not be any changes to the cell because those terms are not refined |
---|
935 | A,sigA = G2stIO.cellFill(pfx,SGData,parmDict,{}) |
---|
936 | cell[1:7] = G2lat.A2cell(A) |
---|
937 | cell[7] = G2lat.calc_V(A) |
---|
938 | textureData = General['SH Texture'] |
---|
939 | if textureData['Order']: |
---|
940 | for name in ['omega','chi','phi']: |
---|
941 | aname = pfx+'SH '+name |
---|
942 | textureData['Sample '+name][1] = parmDict[aname] |
---|
943 | for name in textureData['SH Coeff'][1]: |
---|
944 | aname = pfx+name |
---|
945 | textureData['SH Coeff'][1][name] = parmDict[aname] |
---|
946 | ik = 6 #for Pawley stuff below |
---|
947 | if General.get('Modulated',False): |
---|
948 | ik = 7 |
---|
949 | # how are these updated? |
---|
950 | #General['SuperVec'] |
---|
951 | #RBModels = Phase['RBModels'] |
---|
952 | if Phase['General'].get('doPawley'): |
---|
953 | pawleyRef = Phase['Pawley ref'] |
---|
954 | for i,refl in enumerate(pawleyRef): |
---|
955 | key = pfx+'PWLref:'+str(i) |
---|
956 | refl[ik] = parmDict[key] |
---|
957 | # if key in sigDict: #TODO: error here sigDict not defined. What was intended? |
---|
958 | # refl[ik+1] = sigDict[key] |
---|
959 | # else: |
---|
960 | # refl[ik+1] = 0 |
---|
961 | continue |
---|
962 | cx,ct,cs,cia = General['AtomPtrs'] |
---|
963 | for i,at in enumerate(Atoms): |
---|
964 | names = {cx:pfx+'Ax:'+str(i),cx+1:pfx+'Ay:'+str(i),cx+2:pfx+'Az:'+str(i),cx+3:pfx+'Afrac:'+str(i), |
---|
965 | cia+1:pfx+'AUiso:'+str(i),cia+2:pfx+'AU11:'+str(i),cia+3:pfx+'AU22:'+str(i),cia+4:pfx+'AU33:'+str(i), |
---|
966 | cia+5:pfx+'AU12:'+str(i),cia+6:pfx+'AU13:'+str(i),cia+7:pfx+'AU23:'+str(i), |
---|
967 | cx+4:pfx+'AMx:'+str(i),cx+5:pfx+'AMy:'+str(i),cx+6:pfx+'AMz:'+str(i)} |
---|
968 | for ind in range(cx,cx+4): |
---|
969 | at[ind] = parmDict[names[ind]] |
---|
970 | if at[cia] == 'I': |
---|
971 | at[cia+1] = parmDict[names[cia+1]] |
---|
972 | else: |
---|
973 | for ind in range(cia+2,cia+8): |
---|
974 | at[ind] = parmDict[names[ind]] |
---|
975 | if General['Type'] == 'magnetic': |
---|
976 | for ind in range(cx+4,cx+7): |
---|
977 | at[ind] = parmDict[names[ind]] |
---|
978 | ind = General['AtomTypes'].index(at[ct]) |
---|
979 | if General.get('Modulated',False): |
---|
980 | AtomSS = at[-1]['SS1'] |
---|
981 | waveType = AtomSS['waveType'] |
---|
982 | for Stype in ['Sfrac','Spos','Sadp','Smag']: |
---|
983 | Waves = AtomSS[Stype] |
---|
984 | for iw,wave in enumerate(Waves): |
---|
985 | stiw = str(i)+':'+str(iw) |
---|
986 | if Stype == 'Spos': |
---|
987 | if waveType in ['ZigZag','Block',] and not iw: |
---|
988 | names = ['Tmin:'+stiw,'Tmax:'+stiw,'Xmax:'+stiw,'Ymax:'+stiw,'Zmax:'+stiw] |
---|
989 | else: |
---|
990 | names = ['Xsin:'+stiw,'Ysin:'+stiw,'Zsin:'+stiw, |
---|
991 | 'Xcos:'+stiw,'Ycos:'+stiw,'Zcos:'+stiw] |
---|
992 | elif Stype == 'Sadp': |
---|
993 | names = ['U11sin:'+stiw,'U22sin:'+stiw,'U33sin:'+stiw, |
---|
994 | 'U12sin:'+stiw,'U13sin:'+stiw,'U23sin:'+stiw, |
---|
995 | 'U11cos:'+stiw,'U22cos:'+stiw,'U33cos:'+stiw, |
---|
996 | 'U12cos:'+stiw,'U13cos:'+stiw,'U23cos:'+stiw] |
---|
997 | elif Stype == 'Sfrac': |
---|
998 | if 'Crenel' in waveType and not iw: |
---|
999 | names = ['Fzero:'+stiw,'Fwid:'+stiw] |
---|
1000 | else: |
---|
1001 | names = ['Fsin:'+stiw,'Fcos:'+stiw] |
---|
1002 | elif Stype == 'Smag': |
---|
1003 | names = ['MXsin:'+stiw,'MYsin:'+stiw,'MZsin:'+stiw, |
---|
1004 | 'MXcos:'+stiw,'MYcos:'+stiw,'MZcos:'+stiw] |
---|
1005 | for iname,name in enumerate(names): |
---|
1006 | AtomSS[Stype][iw][0][iname] = parmDict[pfx+name] |
---|
1007 | |
---|
1008 | def OnEditSelectPhaseVars(event): |
---|
1009 | '''Select phase parameters in a selected histogram in a sequential |
---|
1010 | fit. This allows the user to set their value(s) |
---|
1011 | ''' |
---|
1012 | rows = G2frame.dataDisplay.GetSelectedRows() |
---|
1013 | if len(rows) >= 1: |
---|
1014 | selRows = rows |
---|
1015 | else: |
---|
1016 | dlg = G2G.G2MultiChoiceDialog(G2frame, 'Select histogram(s) to update\nphase parameters', |
---|
1017 | 'Select row',histNames) |
---|
1018 | if dlg.ShowModal() == wx.ID_OK: |
---|
1019 | selRows = dlg.GetSelections() |
---|
1020 | else: |
---|
1021 | selRows = [] |
---|
1022 | dlg.Destroy() |
---|
1023 | if len(selRows) == 0: return |
---|
1024 | parmDict = data[histNames[selRows[0]]]['parmDict'] |
---|
1025 | # narrow down to items w/o a histogram & having float values |
---|
1026 | phaseKeys = [i for i in parmDict if ':' in i and i.split(':')[1] == ''] |
---|
1027 | phaseKeys = [i for i in phaseKeys if type(parmDict[i]) not in (int,str,bool)] |
---|
1028 | if len(selRows) == 1: |
---|
1029 | lbl = "\nin {} ".format(histNames[selRows[0]]) |
---|
1030 | else: |
---|
1031 | lbl = "\nin {} histograms".format(len(selRows)) |
---|
1032 | dlg = G2G.G2MultiChoiceDialog(G2frame, 'Choose phase parmDict item(s) to set'+lbl, |
---|
1033 | 'Choose items to edit', phaseKeys) |
---|
1034 | if dlg.ShowModal() == wx.ID_OK: |
---|
1035 | select = dlg.GetSelections() |
---|
1036 | dlg.Destroy() |
---|
1037 | else: |
---|
1038 | dlg.Destroy() |
---|
1039 | return |
---|
1040 | if len(select) == 0: return |
---|
1041 | l = [phaseKeys[i] for i in select] |
---|
1042 | d = {i:parmDict[i] for i in l} |
---|
1043 | val = G2G.CallScrolledMultiEditor(G2frame,len(l)*[d],l,l,CopyButton=True) |
---|
1044 | if val: |
---|
1045 | for sel in selRows: |
---|
1046 | parmDict = data[histNames[sel]]['parmDict'] |
---|
1047 | for key in d: # update values shown in table |
---|
1048 | if parmDict[key] == d[key]: continue |
---|
1049 | if key in data[histNames[sel]]['varyList']: |
---|
1050 | i = data[histNames[sel]]['varyList'].index(key) |
---|
1051 | data[histNames[sel]]['variables'][i] = d[key] |
---|
1052 | data[histNames[sel]]['sig'][i] = 0 |
---|
1053 | if key in data[histNames[sel]].get('depParmDict',{}): |
---|
1054 | data[histNames[sel]]['depParmDict'][key] = (d[key],0) |
---|
1055 | parmDict.update(d) # update values used in next fit |
---|
1056 | wx.CallAfter(UpdateSeqResults,G2frame,data) # redisplay variables |
---|
1057 | return |
---|
1058 | |
---|
1059 | #---- UpdateSeqResults: start processing sequential results here ########## |
---|
1060 | # lookup table for unique cell parameters by symmetry |
---|
1061 | |
---|
1062 | if not data: |
---|
1063 | print ('No sequential refinement results') |
---|
1064 | return |
---|
1065 | variableLabels = data.get('variableLabels',{}) |
---|
1066 | data['variableLabels'] = variableLabels |
---|
1067 | Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree() |
---|
1068 | if not len(Histograms) and not len(Phases): #PDF or IMG histogrms not PWDR |
---|
1069 | histNames = [name for name in data['histNames']] |
---|
1070 | Controls = {} |
---|
1071 | else: |
---|
1072 | Controls = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.root,'Controls')) |
---|
1073 | # create a place to store Pseudo Vars & Parametric Fit functions, if not present |
---|
1074 | if 'SeqPseudoVars' not in data: data['SeqPseudoVars'] = {} |
---|
1075 | if 'SeqParFitEqList' not in data: data['SeqParFitEqList'] = [] |
---|
1076 | histNames = [name for name in data['histNames'] if name in data] |
---|
1077 | if G2frame.dataDisplay: |
---|
1078 | G2frame.dataDisplay.Destroy() |
---|
1079 | G2frame.GetStatusBar().SetStatusText("Select column to export; LMB/RMB column to plot data/change label; LMB/RMB on row for PWDR/Covariance plot",1) |
---|
1080 | sampleParms = GetSampleParms() |
---|
1081 | |
---|
1082 | # get unit cell & symmetry for all phases & initial stuff for later use |
---|
1083 | RecpCellTerms = {} |
---|
1084 | SGdata = {} |
---|
1085 | uniqCellIndx = {} |
---|
1086 | initialCell = {} |
---|
1087 | RcellLbls = {} |
---|
1088 | zeroDict = {} |
---|
1089 | for phase in Phases: |
---|
1090 | phasedict = Phases[phase] |
---|
1091 | pId = phasedict['pId'] |
---|
1092 | pfx = str(pId)+'::' # prefix for A values from phase |
---|
1093 | RcellLbls[pId] = [pfx+'A'+str(i) for i in range(6)] |
---|
1094 | RecpCellTerms[pId] = G2lat.cell2A(phasedict['General']['Cell'][1:7]) |
---|
1095 | zeroDict[pId] = dict(zip(RcellLbls[pId],6*[0.,])) |
---|
1096 | SGdata[pId] = phasedict['General']['SGData'] |
---|
1097 | laue = SGdata[pId]['SGLaue'] |
---|
1098 | if laue == '2/m': |
---|
1099 | laue += SGdata[pId]['SGUniq'] |
---|
1100 | for symlist,celllist in G2lat.UniqueCellByLaue: |
---|
1101 | if laue in symlist: |
---|
1102 | uniqCellIndx[pId] = celllist |
---|
1103 | break |
---|
1104 | else: # should not happen |
---|
1105 | uniqCellIndx[pId] = list(range(6)) |
---|
1106 | for i in uniqCellIndx[pId]: |
---|
1107 | initialCell[str(pId)+'::A'+str(i)] = RecpCellTerms[pId][i] |
---|
1108 | |
---|
1109 | G2gd.SetDataMenuBar(G2frame,G2frame.dataWindow.SequentialMenu) |
---|
1110 | G2frame.Bind(wx.EVT_MENU, OnSelectUse, id=G2G.wxID_SELECTUSE) |
---|
1111 | G2frame.Bind(wx.EVT_MENU, OnRenameSelSeq, id=G2G.wxID_RENAMESEQSEL) |
---|
1112 | G2frame.Bind(wx.EVT_MENU, OnSaveSelSeq, id=G2G.wxID_SAVESEQSEL) |
---|
1113 | G2frame.Bind(wx.EVT_MENU, OnSaveSelSeqCSV, id=G2G.wxID_SAVESEQSELCSV) |
---|
1114 | G2frame.Bind(wx.EVT_MENU, OnSaveSeqCSV, id=G2G.wxID_SAVESEQCSV) |
---|
1115 | G2frame.Bind(wx.EVT_MENU, OnPlotSelSeq, id=G2G.wxID_PLOTSEQSEL) |
---|
1116 | G2frame.Bind(wx.EVT_MENU, OnAveSelSeq, id=G2G.wxID_AVESEQSEL) |
---|
1117 | G2frame.Bind(wx.EVT_MENU, OnSelectUpdate, id=G2G.wxID_UPDATESEQSEL) |
---|
1118 | G2frame.Bind(wx.EVT_MENU, OnEditSelectPhaseVars, id=G2G.wxID_EDITSEQSELPHASE) |
---|
1119 | G2frame.Bind(wx.EVT_MENU, onSelectSeqVars, id=G2G.wxID_ORGSEQINC) |
---|
1120 | G2frame.Bind(wx.EVT_MENU, AddNewPseudoVar, id=G2G.wxID_ADDSEQVAR) |
---|
1121 | G2frame.Bind(wx.EVT_MENU, AddNewDistPseudoVar, id=G2G.wxID_ADDSEQDIST) |
---|
1122 | G2frame.Bind(wx.EVT_MENU, AddNewAnglePseudoVar, id=G2G.wxID_ADDSEQANGLE) |
---|
1123 | G2frame.Bind(wx.EVT_MENU, DelPseudoVar, id=G2G.wxID_DELSEQVAR) |
---|
1124 | G2frame.Bind(wx.EVT_MENU, EditPseudoVar, id=G2G.wxID_EDITSEQVAR) |
---|
1125 | G2frame.Bind(wx.EVT_MENU, AddNewParFitEq, id=G2G.wxID_ADDPARFIT) |
---|
1126 | G2frame.Bind(wx.EVT_MENU, CopyParFitEq, id=G2G.wxID_COPYPARFIT) |
---|
1127 | G2frame.Bind(wx.EVT_MENU, DelParFitEq, id=G2G.wxID_DELPARFIT) |
---|
1128 | G2frame.Bind(wx.EVT_MENU, EditParFitEq, id=G2G.wxID_EDITPARFIT) |
---|
1129 | G2frame.Bind(wx.EVT_MENU, DoParEqFit, id=G2G.wxID_DOPARFIT) |
---|
1130 | |
---|
1131 | for id in G2frame.dataWindow.SeqExportLookup: |
---|
1132 | G2frame.Bind(wx.EVT_MENU, DoSequentialExport, id=id) |
---|
1133 | G2frame.Bind(wx.EVT_MENU, OnSaveSeqCSV, id=G2G.wxID_XPORTSEQCSV) |
---|
1134 | G2frame.Bind(wx.EVT_MENU, DoSequentialExport, id=G2G.wxID_XPORTSEQFCIF) |
---|
1135 | |
---|
1136 | EnablePseudoVarMenus() |
---|
1137 | EnableParFitEqMenus() |
---|
1138 | |
---|
1139 | combinedVaryList = [] # list of all varied parameters ; used for column headings |
---|
1140 | atomsVaryList = {} # dict of atom coords varied in any histogram, includes dependent params |
---|
1141 | # key is atom param name, value is esd parm name |
---|
1142 | firstValueDict = {} # first value for each parameter; used to create VarDict for parametric fit pseudo vars GUI |
---|
1143 | foundHistNames = [] # histograms to be used in sequential table |
---|
1144 | maxPWL = 5 # number of Pawley vars to show |
---|
1145 | missing = 0 |
---|
1146 | newCellDict = {} |
---|
1147 | PSvarDict = {} # contains 1st value for each parameter in parmDict |
---|
1148 | # needed for creating & editing pseudovars |
---|
1149 | PSvarDict.update(sampleParms) |
---|
1150 | |
---|
1151 | # scan through histograms to see what are available and to make a |
---|
1152 | # list of all varied parameters; also create a dict that has the |
---|
1153 | for i,name in enumerate(histNames): |
---|
1154 | if name not in data: |
---|
1155 | if missing < 5: |
---|
1156 | print(" Warning: "+name+" not found") |
---|
1157 | elif missing == 5: |
---|
1158 | print (' Warning: more are missing') |
---|
1159 | missing += 1 |
---|
1160 | continue |
---|
1161 | foundHistNames.append(name) |
---|
1162 | for var,val,sig in zip(data[name]['varyList'],data[name]['variables'],data[name]['sig']): |
---|
1163 | svar = striphist(var,'*') # wild-carded |
---|
1164 | if 'PWL' in svar: |
---|
1165 | if int(svar.split(':')[-1]) > maxPWL: |
---|
1166 | continue |
---|
1167 | if svar not in combinedVaryList: |
---|
1168 | # add variables to list as they appear |
---|
1169 | combinedVaryList.append(svar) |
---|
1170 | firstValueDict[svar] = (val,sig) |
---|
1171 | if '::dA' in var: |
---|
1172 | atomsVaryList[var.replace('::dA','::A')] = var |
---|
1173 | atomsVaryList.update({i.replace('::dA','::A'):i for i in data[name]['depParmDict'] if '::dA' in i}) |
---|
1174 | # get all refined cell terms |
---|
1175 | newCellDict.update(data[name].get('newCellDict',{})) # N.B. These Dij vars are missing a histogram # |
---|
1176 | # make sure 1st reference to each parm is in PseudoVar dict |
---|
1177 | tmp = copy.deepcopy(data[name].get('parmDict',{})) |
---|
1178 | tmp = {striphist(var,'*'):tmp[var] for var in tmp} # replace histogram #s with "*" |
---|
1179 | tmp.update(PSvarDict) |
---|
1180 | PSvarDict = tmp |
---|
1181 | |
---|
1182 | if missing: |
---|
1183 | print (' Warning: Total of %d data sets missing from sequential results'%(missing)) |
---|
1184 | |
---|
1185 | # make dict of varied cell parameters equivalents |
---|
1186 | ESDlookup = {} # provides the Dij term for each Ak term (where terms are refined) |
---|
1187 | Dlookup = {} # provides the Ak term for each Dij term (where terms are refined) |
---|
1188 | cellAlist = [] |
---|
1189 | for item in newCellDict: |
---|
1190 | cellAlist.append(newCellDict[item][0]) |
---|
1191 | if item in data.get('varyList',[]): |
---|
1192 | ESDlookup[newCellDict[item][0]] = item |
---|
1193 | Dlookup[item] = newCellDict[item][0] |
---|
1194 | # add coordinate equivalents to lookup table |
---|
1195 | for parm in atomsVaryList: |
---|
1196 | Dlookup[atomsVaryList[parm]] = parm |
---|
1197 | ESDlookup[parm] = atomsVaryList[parm] |
---|
1198 | combinedVaryList.sort() |
---|
1199 | histNames = foundHistNames |
---|
1200 | # prevVaryList = [] |
---|
1201 | posdict = {} # defines position for each entry in table; for inner |
---|
1202 | # dict key is column number & value is parameter name |
---|
1203 | for i,name in enumerate(histNames): |
---|
1204 | # if prevVaryList != data[name]['varyList']: # this refinement has a different refinement list from previous |
---|
1205 | # prevVaryList = data[name]['varyList'] |
---|
1206 | posdict[name] = {} |
---|
1207 | for var in data[name]['varyList']: |
---|
1208 | svar = striphist(var,'*') |
---|
1209 | if 'PWL' in svar: |
---|
1210 | if int(svar.split(':')[-1]) > maxPWL: |
---|
1211 | continue |
---|
1212 | posdict[name][combinedVaryList.index(svar)] = svar |
---|
1213 | ####-- build up the data table by columns ----------------------------------------------- |
---|
1214 | nRows = len(histNames) |
---|
1215 | G2frame.colList = [list(range(nRows))] |
---|
1216 | if len(data.get('Use',[])) != nRows: |
---|
1217 | data['Use'] = nRows*[True] |
---|
1218 | G2frame.colList += [data['Use']] |
---|
1219 | G2frame.colSigs = [None,None,] |
---|
1220 | colLabels = ['No.','Use',] |
---|
1221 | Types = [wg.GRID_VALUE_LONG,wg.GRID_VALUE_BOOL,] |
---|
1222 | # start with Rwp values |
---|
1223 | if 'IMG ' not in histNames[0][:4]: |
---|
1224 | G2frame.colList += [[data[name]['Rvals']['Rwp'] for name in histNames]] |
---|
1225 | G2frame.colSigs += [None] |
---|
1226 | colLabels += ['Rwp'] |
---|
1227 | Types += [wg.GRID_VALUE_FLOAT+':10,3',] |
---|
1228 | # add % change in Chi^2 in last cycle |
---|
1229 | if histNames[0][:4] not in ['SASD','IMG ','REFD'] and Controls.get('ShowCell'): |
---|
1230 | G2frame.colList += [[100.*data[name]['Rvals'].get('DelChi2',-1) for name in histNames]] |
---|
1231 | G2frame.colSigs += [None] |
---|
1232 | colLabels += [u'\u0394\u03C7\u00B2 (%)'] |
---|
1233 | Types += [wg.GRID_VALUE_FLOAT+':10,5',] |
---|
1234 | deltaChiCol = len(colLabels)-1 |
---|
1235 | # frozen variables? |
---|
1236 | if 'parmFrozen' in Controls: |
---|
1237 | f = [len(Controls['parmFrozen'].get(h,[])) for h in histNames] |
---|
1238 | if any(f): |
---|
1239 | G2frame.colList += [f] |
---|
1240 | G2frame.colSigs += [None] |
---|
1241 | colLabels += ['frozen'] |
---|
1242 | Types += [wg.GRID_VALUE_LONG] |
---|
1243 | # add changing sample parameters to table |
---|
1244 | for key in sampleParms: |
---|
1245 | G2frame.colList += [sampleParms[key]] |
---|
1246 | G2frame.colSigs += [None] |
---|
1247 | colLabels += [key] |
---|
1248 | Types += [wg.GRID_VALUE_FLOAT,] |
---|
1249 | sampleDict = {} |
---|
1250 | for i,name in enumerate(histNames): |
---|
1251 | sampleDict[name] = dict(zip(sampleParms.keys(),[sampleParms[key][i] for key in sampleParms.keys()])) |
---|
1252 | # add unique cell parameters |
---|
1253 | if Controls.get('ShowCell',False) and len(newCellDict): |
---|
1254 | phaseLookup = {Phases[phase]['pId']:phase for phase in Phases} |
---|
1255 | for pId in sorted(RecpCellTerms): |
---|
1256 | pfx = str(pId)+'::' # prefix for A values from phase |
---|
1257 | cells = [] |
---|
1258 | cellESDs = [] |
---|
1259 | colLabels += [pfx+G2lat.cellUlbl[i] for i in uniqCellIndx[pId]] |
---|
1260 | colLabels += [pfx+'Vol'] |
---|
1261 | Types += (len(uniqCellIndx[pId]))*[wg.GRID_VALUE_FLOAT+':10,5',] |
---|
1262 | Types += [wg.GRID_VALUE_FLOAT+':10,3',] |
---|
1263 | Albls = [pfx+'A'+str(i) for i in range(6)] |
---|
1264 | for name in histNames: |
---|
1265 | if name not in Histograms: continue |
---|
1266 | hId = Histograms[name]['hId'] |
---|
1267 | phfx = '%d:%d:'%(pId,hId) |
---|
1268 | esdLookUp = {} |
---|
1269 | dLookup = {} |
---|
1270 | for item in data[name]['newCellDict']: |
---|
1271 | if phfx+item.split('::')[1] in data[name]['varyList']: |
---|
1272 | esdLookUp[newCellDict[item][0]] = item |
---|
1273 | dLookup[item] = newCellDict[item][0] |
---|
1274 | covData = {'varyList': [dLookup.get(striphist(v),v) for v in data[name]['varyList']], |
---|
1275 | 'covMatrix': data[name]['covMatrix']} |
---|
1276 | A = RecpCellTerms[pId][:] # make copy of starting A values |
---|
1277 | # update with refined values |
---|
1278 | for i,j in enumerate(('D11','D22','D33','D12','D13','D23')): |
---|
1279 | var = str(pId)+'::A'+str(i) |
---|
1280 | Dvar = str(pId)+':'+str(hId)+':'+j |
---|
1281 | # apply Dij value if non-zero |
---|
1282 | if Dvar in data[name]['parmDict']: |
---|
1283 | if data[name]['parmDict'][Dvar] != 0.0: |
---|
1284 | A[i] += data[name]['parmDict'][Dvar] |
---|
1285 | # override with fit result if is Dij varied |
---|
1286 | if var in cellAlist: |
---|
1287 | try: |
---|
1288 | A[i] = data[name]['newCellDict'][esdLookUp[var]][1] # get refined value |
---|
1289 | except KeyError: |
---|
1290 | pass |
---|
1291 | # apply symmetry |
---|
1292 | cellDict = dict(zip(Albls,A)) |
---|
1293 | try: # convert to direct cell |
---|
1294 | A,zeros = G2stIO.cellFill(pfx,SGdata[pId],cellDict,zeroDict[pId]) |
---|
1295 | c = G2lat.A2cell(A) |
---|
1296 | vol = G2lat.calc_V(A) |
---|
1297 | cE = G2stIO.getCellEsd(pfx,SGdata[pId],A,covData) |
---|
1298 | except: |
---|
1299 | c = 6*[None] |
---|
1300 | cE = 6*[None] |
---|
1301 | vol = None |
---|
1302 | # add only unique values to table |
---|
1303 | if name in Phases[phaseLookup[pId]]['Histograms']: |
---|
1304 | cells += [[c[i] for i in uniqCellIndx[pId]]+[vol]] |
---|
1305 | cellESDs += [[cE[i] for i in uniqCellIndx[pId]]+[cE[-1]]] |
---|
1306 | # add in direct cell terms to PseudoVar dict |
---|
1307 | tmp = dict(zip([pfx+G2lat.cellUlbl[i] for i in uniqCellIndx[pId]]+[pfx+'Vol'], |
---|
1308 | [c[i] for i in uniqCellIndx[pId]]+[vol])) |
---|
1309 | tmp.update(PSvarDict) |
---|
1310 | PSvarDict = tmp |
---|
1311 | else: |
---|
1312 | cells += [[None for i in uniqCellIndx[pId]]+[None]] |
---|
1313 | cellESDs += [[None for i in uniqCellIndx[pId]]+[None]] |
---|
1314 | G2frame.colList += zip(*cells) |
---|
1315 | G2frame.colSigs += zip(*cellESDs) |
---|
1316 | |
---|
1317 | # get ISODISTORT labels |
---|
1318 | ISOlist = [] |
---|
1319 | for phase in Phases: |
---|
1320 | ISOlist += [i.varname() for i in Phases[phase].get('ISODISTORT',{}).get('G2ModeList',[]) |
---|
1321 | if i.varname() not in ISOlist] |
---|
1322 | # set labels for columns of data table |
---|
1323 | ISOcols = {} # ISODISTORT modes |
---|
1324 | for i,lbl in enumerate(combinedVaryList): |
---|
1325 | if 'nv-' in lbl: |
---|
1326 | nlbl = lbl.replace('::nv-','::') |
---|
1327 | if nlbl in ISOlist: |
---|
1328 | lbl = nlbl |
---|
1329 | ISOcols[lbl] = i |
---|
1330 | colLabels.append(lbl) |
---|
1331 | Types += len(combinedVaryList)*[wg.GRID_VALUE_FLOAT,] |
---|
1332 | vals = [] |
---|
1333 | esds = [] |
---|
1334 | varsellist = None # will be a list of variable names in the order they are selected to appear |
---|
1335 | # tabulate values for each hist, leaving None for blank columns |
---|
1336 | for ih,name in enumerate(histNames): |
---|
1337 | varsellist = [posdict[name].get(i) for i in range(len(combinedVaryList))] |
---|
1338 | # translate variable names to how they will be used in the headings |
---|
1339 | vs = [striphist(v,'*') for v in data[name]['varyList']] |
---|
1340 | # determine the index for each column (or None) in the data[]['variables'] and ['sig'] lists |
---|
1341 | sellist = [vs.index(v) if v is not None else None for v in varsellist] |
---|
1342 | #sellist = [i if striphist(v,'*') in varsellist else None for i,v in enumerate(data[name]['varyList'])] |
---|
1343 | if not varsellist: raise Exception() |
---|
1344 | vals.append([data[name]['variables'][s] if s is not None else None for s in sellist]) |
---|
1345 | #replace mode displacement shift with value; esd applies to both |
---|
1346 | for pname in ISOcols: |
---|
1347 | if pname in data[name]['parmDict']: |
---|
1348 | vals[ih][ISOcols[pname]] = data[name]['parmDict'][pname] |
---|
1349 | esds.append([data[name]['sig'][s] if s is not None else None for s in sellist]) |
---|
1350 | G2frame.colList += zip(*vals) |
---|
1351 | G2frame.colSigs += zip(*esds) |
---|
1352 | |
---|
1353 | # add refined atom parameters to table |
---|
1354 | for parm in sorted(atomsVaryList): |
---|
1355 | vals = [] |
---|
1356 | sigs = [] |
---|
1357 | aprm = atomsVaryList[parm] |
---|
1358 | for name in histNames: |
---|
1359 | if aprm in data[name]['varyList']: |
---|
1360 | i = data[name]['parmDict'][parm] |
---|
1361 | j = data[name]['sig'][data[name]['varyList'].index(aprm)] |
---|
1362 | elif aprm in data[name]['depParmDict']: |
---|
1363 | i = data[name]['parmDict'][parm] |
---|
1364 | j = data[name]['depParmDict'][aprm][1] |
---|
1365 | else: |
---|
1366 | i = j = None |
---|
1367 | vals.append(i) |
---|
1368 | sigs.append(j) |
---|
1369 | colLabels.append(parm) |
---|
1370 | Types += [wg.GRID_VALUE_FLOAT+':10,5',] |
---|
1371 | G2frame.colSigs += [sigs] |
---|
1372 | G2frame.colList += [vals] |
---|
1373 | |
---|
1374 | # tabulate dependent parameters from constraints, removing histogram numbers from |
---|
1375 | # parm label, if needed. Add the dependent variables to the table |
---|
1376 | depValDict = {} |
---|
1377 | for name in histNames: |
---|
1378 | for var in data[name].get('depParmDict',{}): |
---|
1379 | if '::dA' in var: continue |
---|
1380 | val,sig = data[name]['depParmDict'][var] |
---|
1381 | svar = striphist(var,'*') |
---|
1382 | if svar not in depValDict: |
---|
1383 | depValDict[svar] = {} |
---|
1384 | depValDict[svar][name] = (val,sig) |
---|
1385 | for svar in sorted(depValDict): |
---|
1386 | vals = [] |
---|
1387 | sigs = [] |
---|
1388 | for name in histNames: |
---|
1389 | if name in depValDict[svar]: |
---|
1390 | i,j = depValDict[svar][name] |
---|
1391 | else: |
---|
1392 | i = j = None |
---|
1393 | vals.append(i) |
---|
1394 | sigs.append(j) |
---|
1395 | colLabels.append(svar) |
---|
1396 | Types += [wg.GRID_VALUE_FLOAT+':10,5',] |
---|
1397 | G2frame.colSigs += [sigs] |
---|
1398 | G2frame.colList += [vals] |
---|
1399 | |
---|
1400 | # evaluate Pseudovars, their ESDs and add them to grid |
---|
1401 | # this should be reworked so that the eval dict is created once and as noted below |
---|
1402 | for expr in data['SeqPseudoVars']: |
---|
1403 | obj = data['SeqPseudoVars'][expr] |
---|
1404 | calcobj = G2obj.ExpressionCalcObj(obj) |
---|
1405 | valList = [] |
---|
1406 | esdList = [] |
---|
1407 | for seqnum,name in enumerate(histNames): |
---|
1408 | sigs = data[name]['sig'] |
---|
1409 | G2mv.InitVars() |
---|
1410 | # parmDict = data[name].get('parmDict') |
---|
1411 | parmDict = data[name]['parmDict'] |
---|
1412 | constraintInfo = data[name].get('constraintInfo',[[],[],{},[],seqnum]) |
---|
1413 | groups,parmlist,constrDict,fixedList,ihst = constraintInfo |
---|
1414 | varyList = data[name]['varyList'] |
---|
1415 | msg = G2mv.EvaluateMultipliers(constrDict,parmDict) |
---|
1416 | if msg: |
---|
1417 | print('Unable to interpret multiplier(s) for',name,':',msg) |
---|
1418 | continue |
---|
1419 | G2mv.GenerateConstraints(varyList,constrDict,fixedList,parmDict, |
---|
1420 | seqHistNum=ihst,raiseException=False) |
---|
1421 | if 'Dist' in expr: |
---|
1422 | derivs = G2mth.CalcDistDeriv(obj.distance_dict,obj.distance_atoms, parmDict) |
---|
1423 | pId = obj.distance_dict['pId'] |
---|
1424 | aId,bId = obj.distance_atoms |
---|
1425 | varyNames = ['%d::dA%s:%d'%(pId,ip,aId) for ip in ['x','y','z']] |
---|
1426 | varyNames += ['%d::dA%s:%d'%(pId,ip,bId) for ip in ['x','y','z']] |
---|
1427 | VCoV = G2mth.getVCov(varyNames,varyList,data[name]['covMatrix']) |
---|
1428 | esdList.append(np.sqrt(np.inner(derivs,np.inner(VCoV,derivs.T)) )) |
---|
1429 | elif 'Angle' in expr: |
---|
1430 | derivs = G2mth.CalcAngleDeriv(obj.angle_dict,obj.angle_atoms, parmDict) |
---|
1431 | pId = obj.angle_dict['pId'] |
---|
1432 | aId,bId = obj.angle_atoms |
---|
1433 | varyNames = ['%d::dA%s:%d'%(pId,ip,aId) for ip in ['x','y','z']] |
---|
1434 | varyNames += ['%d::dA%s:%d'%(pId,ip,bId[0]) for ip in ['x','y','z']] |
---|
1435 | varyNames += ['%d::dA%s:%d'%(pId,ip,bId[1]) for ip in ['x','y','z']] |
---|
1436 | VCoV = G2mth.getVCov(varyNames,varyList,data[name]['covMatrix']) |
---|
1437 | esdList.append(np.sqrt(np.inner(derivs,np.inner(VCoV,derivs.T)) )) |
---|
1438 | else: |
---|
1439 | derivs = np.array( # TODO: this needs to be reworked |
---|
1440 | [EvalPSvarDeriv(calcobj,parmDict.copy(),sampleDict[name],var,ESD) |
---|
1441 | for var,ESD in zip(varyList,sigs)]) |
---|
1442 | # needs work: calls calcobj.SetupCalc each call time |
---|
1443 | # integrate into G2obj.ExpressionCalcObj |
---|
1444 | if None in list(derivs): |
---|
1445 | esdList.append(None) |
---|
1446 | else: |
---|
1447 | esdList.append(np.sqrt( |
---|
1448 | np.inner(derivs,np.inner(data[name]['covMatrix'],derivs.T)) )) |
---|
1449 | psDict = parmDict.copy() |
---|
1450 | psDict.update(sampleDict[name]) |
---|
1451 | try: |
---|
1452 | UpdateParmDict(psDict) |
---|
1453 | except: |
---|
1454 | print('UpdateParmDict error on histogram',name) |
---|
1455 | calcobj.UpdateDict(psDict) |
---|
1456 | valList.append(calcobj.EvalExpression()) |
---|
1457 | # if calcobj.su is not None: esdList[-1] = calcobj.su |
---|
1458 | if not esdList: |
---|
1459 | esdList = None |
---|
1460 | G2frame.colList += [valList] |
---|
1461 | G2frame.colSigs += [esdList] |
---|
1462 | colLabels += [expr] |
---|
1463 | Types += [wg.GRID_VALUE_FLOAT+':10,5'] |
---|
1464 | #---- table build done ------------------------------------------------------------- |
---|
1465 | |
---|
1466 | # clean up the PseudoVars dict by reomving dA[xyz] & Dij |
---|
1467 | remDij = re.compile('[0-9]+:[0-9]*:D[123][123]') |
---|
1468 | remdAxyz = re.compile('[0-9]+::dA[xyz]:[0-9]+') |
---|
1469 | PSvarDict = {i:PSvarDict[i] for i in PSvarDict if not (remDij.match(i) or remdAxyz.match(i))} |
---|
1470 | |
---|
1471 | # remove selected columns from table |
---|
1472 | saveColLabels = colLabels[:] |
---|
1473 | if G2frame.SeqTblHideList is None: #set default hides |
---|
1474 | G2frame.SeqTblHideList = [item for item in saveColLabels if 'Back' in item] |
---|
1475 | G2frame.SeqTblHideList += [item for item in saveColLabels if 'dA' in item] |
---|
1476 | G2frame.SeqTblHideList += [item for item in saveColLabels if ':*:D' in item] |
---|
1477 | #****************************************************************************** |
---|
1478 | # create a set of values for example evaluation of parametric equation fitting |
---|
1479 | VarDict = {} |
---|
1480 | for i,var in enumerate(colLabels): |
---|
1481 | if var in ['Use','Rwp',u'\u0394\u03C7\u00B2 (%)']: continue |
---|
1482 | if G2frame.colList[i][0] is None: |
---|
1483 | val,sig = firstValueDict.get(var,[None,None]) |
---|
1484 | elif G2frame.colSigs[i]: |
---|
1485 | val,sig = G2frame.colList[i][0],G2frame.colSigs[i][0] |
---|
1486 | else: |
---|
1487 | val,sig = G2frame.colList[i][0],None |
---|
1488 | if striphist(var) not in Dlookup: |
---|
1489 | VarDict[var] = val |
---|
1490 | # add recip cell coeff. values |
---|
1491 | VarDict.update({var:val for var,val in newCellDict.values()}) |
---|
1492 | |
---|
1493 | # remove items to be hidden from table |
---|
1494 | for l in reversed(range(len(colLabels))): |
---|
1495 | if colLabels[l] in G2frame.SeqTblHideList: |
---|
1496 | del colLabels[l] |
---|
1497 | del Types[l] |
---|
1498 | del G2frame.colList[l] |
---|
1499 | del G2frame.colSigs[l] |
---|
1500 | if deltaChiCol == l: |
---|
1501 | deltaChiCol = None |
---|
1502 | |
---|
1503 | # make a copy of the column labels substituting alternate labels when defined |
---|
1504 | displayLabels = colLabels[:] |
---|
1505 | for i,l in enumerate(colLabels): |
---|
1506 | if l in variableLabels: |
---|
1507 | displayLabels[i] = variableLabels[l] |
---|
1508 | |
---|
1509 | G2frame.dataWindow.ClearData() |
---|
1510 | G2frame.dataWindow.currentGrids = [] |
---|
1511 | G2frame.dataDisplay = G2G.GSGrid(parent=G2frame.dataWindow) |
---|
1512 | G2frame.dataDisplay.SetScrollRate(10,10) |
---|
1513 | G2frame.dataWindow.GetSizer().Add(G2frame.dataDisplay,1,wx.ALL|wx.EXPAND) |
---|
1514 | if histNames[0].startswith('PWDR'): |
---|
1515 | #rowLabels = [str(i)+': '+l[5:30] for i,l in enumerate(histNames)] |
---|
1516 | rowLabels = [l[5:] for i,l in enumerate(histNames)] |
---|
1517 | else: |
---|
1518 | rowLabels = histNames |
---|
1519 | G2frame.SeqTable = G2G.Table([list(cl) for cl in zip(*G2frame.colList)], # convert from columns to rows |
---|
1520 | colLabels=displayLabels,rowLabels=rowLabels,types=Types) |
---|
1521 | G2frame.dataDisplay.SetTable(G2frame.SeqTable, True) |
---|
1522 | # make all Use editable all others ReadOnly |
---|
1523 | for c in range(len(colLabels)): |
---|
1524 | for r in range(nRows): |
---|
1525 | if c == 1: |
---|
1526 | G2frame.dataDisplay.SetReadOnly(r,c,isReadOnly=False) |
---|
1527 | else: |
---|
1528 | G2frame.dataDisplay.SetReadOnly(r,c,isReadOnly=True) |
---|
1529 | if 'phoenix' in wx.version(): |
---|
1530 | G2frame.dataDisplay.Bind(wg.EVT_GRID_CELL_CHANGED, OnCellChange) |
---|
1531 | else: |
---|
1532 | G2frame.dataDisplay.Bind(wg.EVT_GRID_CELL_CHANGE, OnCellChange) |
---|
1533 | G2frame.dataDisplay.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK, PlotLeftSelect) |
---|
1534 | G2frame.dataDisplay.Bind(wg.EVT_GRID_LABEL_RIGHT_CLICK, PlotRightSelect) |
---|
1535 | G2frame.dataDisplay.SetRowLabelSize(8*len(histNames[0])) #pretty arbitrary 8 |
---|
1536 | G2frame.dataDisplay.SetMargins(0,0) |
---|
1537 | G2frame.dataDisplay.AutoSizeColumns(False) |
---|
1538 | # highlight unconverged shifts |
---|
1539 | if histNames[0][:4] not in ['SASD','IMG ','REFD',] and deltaChiCol is not None: |
---|
1540 | for row,name in enumerate(histNames): |
---|
1541 | deltaChi = G2frame.SeqTable.GetValue(row,deltaChiCol) |
---|
1542 | try: |
---|
1543 | if deltaChi > 10.: |
---|
1544 | G2frame.dataDisplay.SetCellStyle(row,deltaChiCol,color=wx.Colour(255,0,0)) |
---|
1545 | elif deltaChi > 1.0: |
---|
1546 | G2frame.dataDisplay.SetCellStyle(row,deltaChiCol,color=wx.Colour(255,255,0)) |
---|
1547 | except: |
---|
1548 | pass |
---|
1549 | G2frame.dataDisplay.InstallGridToolTip(GridSetToolTip,GridColLblToolTip) |
---|
1550 | #G2frame.dataDisplay.SendSizeEvent() # resize needed on mac |
---|
1551 | #G2frame.dataDisplay.Refresh() # shows colored text on mac |
---|
1552 | G2frame.dataWindow.SetDataSize() |
---|