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