source: trunk/GSASIIfiles.py @ 3136

Last change on this file since 3136 was 3136, checked in by vondreele, 6 years ago

make GSAS-II python 3.6 compliant & preserve python 2.7 use;changes:
do from future import division, print_function for all GSAS-II py sources
all menu items revised to be py 2.7/3.6 compliant
all wx.OPEN --> wx.FD_OPEN in file dialogs
all integer divides (typically for image pixel math) made explicit with ; ambiguous ones made floats as appropriate
all print "stuff" --> print (stuff)
all print >> pFile,'stuff' --> pFile.writeCIFtemplate('stuff')
all read file opens made explicit 'r' or 'rb'
all cPickle imports made for py2.7 or 3.6 as cPickle or _pickle; test for '2' platform.version_tuple[0] for py 2.7
define cPickleload to select load(fp) or load(fp,encoding='latin-1') for loading gpx files; provides cross compatibility between py 2.7/3.6 gpx files
make dict.keys() as explicit list(dict.keys()) as needed (NB: possible source of remaining py3.6 bugs)
make zip(a,b) as explicit list(zip(a,b)) as needed (NB: possible source of remaining py3.6 bugs)
select unichr/chr according test for '2' platform.version_tuple[0] for py 2.7 (G2pwdGUI * G2plot) for special characters
select wg.EVT_GRID_CELL_CHANGE (classic) or wg.EVT_GRID_CELL_CHANGED (phoenix) in grid Bind
maxint --> maxsize; used in random number stuff
raise Exception,"stuff" --> raise Exception("stuff")
wx 'classic' sizer.DeleteWindows?() or 'phoenix' sizer.Clear(True)
wx 'classic' SetToolTipString?(text) or 'phoenix' SetToolTip?(wx.ToolTip?(text)); define SetToolTipString?(self,text) to handle the choice in plots
status.SetFields? --> status.SetStatusText?
'classic' AddSimpleTool? or 'phoenix' self.AddTool? for plot toolbar; Bind different as well
define GetItemPydata? as it doesn't exist in wx 'phoenix'
allow python versions 2.7 & 3.6 to run GSAS-II
Bind override commented out - no logging capability (NB: remove all logging code?)
all import ContentsValidator? open filename & test if valid then close; filepointer removed from Reader
binary importers (mostly images) test for 'byte' type & convert as needed to satisfy py 3.6 str/byte rules

  • Property svn:eol-style set to native
File size: 15.2 KB
Line 
1# -*- coding: utf-8 -*-
2########### SVN repository information ###################
3# $Date: $
4# $Author: $
5# $Revision: $
6# $URL: $
7# $Id: $
8########### SVN repository information ###################
9'''
10*GSASIIfile: data (non-GUI) I/O routines*
11=========================================
12
13Module with miscellaneous routines for input and output from files.
14
15This module should not contain any references to wxPython so that it
16can be imported for scriptable use or potentially on clients where
17wx is not installed.
18
19Future refactoring: This module and GSASIIIO.py needs some work to
20move non-wx routines here. It may will likely make sense to rename the module(s)
21at that point.
22'''
23from __future__ import division, print_function
24import os
25import sys
26import glob
27import imp
28import inspect
29import platform
30import numpy as np
31
32import GSASIIpath
33GSASIIpath.SetVersionNumber("$Revision: 2957 $")
34
35# N.B. This is duplicated in G2IO
36def sfloat(S):
37    'Convert a string to float. An empty field or a unconvertable value is treated as zero'
38    if S.strip():
39        try:
40            return float(S)
41        except ValueError:
42            pass
43    return 0.0
44
45def get_python_versions(packagelist):
46    versions = [['Python', sys.version.split()[0]]]
47    for pack in packagelist:
48        try:
49            versions.append([pack.__name__, pack.__version__])
50        except:
51            pass
52    versions.append(['Platform',
53                     sys.platform + ' ' + platform.architecture()[0] +
54                     ' ' + platform.machine()])
55    return versions
56
57def makeInstDict(names,data,codes):
58    inst = dict(zip(names,zip(data,data,codes)))
59    for item in inst:
60        inst[item] = list(inst[item])
61    return inst
62
63def SetPowderInstParms(Iparm, rd):
64    '''extracts values from instrument parameters in rd.instdict
65    or in array Iparm.
66    Create and return the contents of the instrument parameter tree entry.
67    '''
68    Irads = {0:' ',1:'CrKa',2:'FeKa',3:'CuKa',4:'MoKa',5:'AgKa',6:'TiKa',7:'CoKa'}
69    DataType = Iparm['INS   HTYPE '].strip()[:3]  # take 1st 3 chars
70    # override inst values with values read from data file
71    Bank = rd.powderentry[2]    #should be used in multibank iparm files
72    if rd.instdict.get('type'):
73        DataType = rd.instdict.get('type')
74    data = [DataType,]
75    instname = Iparm.get('INS  1INAME ')
76    irad = int(Iparm.get('INS  1 IRAD ','0'))
77    if instname:
78        rd.Sample['InstrName'] = instname.strip()
79    if 'C' in DataType:
80        wave1 = None
81        wave2 = 0.0
82        if rd.instdict.get('wave'):
83            wl = rd.instdict.get('wave')
84            wave1 = wl[0]
85            if len(wl) > 1: wave2 = wl[1]
86        s = Iparm['INS  1 ICONS']
87        if not wave1:
88            wave1 = sfloat(s[:10])
89            wave2 = sfloat(s[10:20])
90        v = (wave1,wave2,
91             sfloat(s[20:30])/100.,sfloat(s[55:65]),sfloat(s[40:50])) #get lam1, lam2, zero, pola & ratio
92        if not v[1]:
93            names = ['Type','Lam','Zero','Polariz.','U','V','W','X','Y','SH/L','Azimuth']
94            v = (v[0],v[2],v[4])
95            codes = [0,0,0,0]
96            rd.Sample.update({'Type':'Debye-Scherrer','Absorption':[0.,False],'DisplaceX':[0.,False],'DisplaceY':[0.,False]})
97        else:
98            names = ['Type','Lam1','Lam2','Zero','I(L2)/I(L1)','Polariz.','U','V','W','X','Y','SH/L','Azimuth']
99            codes = [0,0,0,0,0,0]
100            rd.Sample.update({'Type':'Bragg-Brentano','Shift':[0.,False],'Transparency':[0.,False],
101                'SurfRoughA':[0.,False],'SurfRoughB':[0.,False]})
102        data.extend(v)
103        if 'INS  1PRCF  ' in Iparm:
104            v1 = Iparm['INS  1PRCF  '].split()
105            v = Iparm['INS  1PRCF 1'].split()
106            data.extend([float(v[0]),float(v[1]),float(v[2])])                  #get GU, GV & GW - always here
107            azm = float(Iparm.get('INS  1DETAZM','0.0'))
108            v = Iparm['INS  1PRCF 2'].split()
109            if v1[0] == 3:
110                data.extend([float(v[0]),float(v[1]),float(v[2])+float(v[3],azm)])  #get LX, LY, S+H/L & azimuth
111            else:
112                data.extend([0.0,0.0,0.002,azm])                                      #OK defaults if fxn #3 not 1st in iprm file
113        else:
114            v1 = Iparm['INS  1PRCF1 '].split()
115            v = Iparm['INS  1PRCF11'].split()
116            data.extend([float(v[0]),float(v[1]),float(v[2])])                  #get GU, GV & GW - always here
117            azm = float(Iparm.get('INS  1DETAZM','0.0'))
118            v = Iparm['INS  1PRCF12'].split()
119            if v1[0] == 3:
120                data.extend([float(v[0]),float(v[1]),float(v[2])+float(v[3],azm)])  #get LX, LY, S+H/L & azimuth
121            else:
122                data.extend([0.0,0.0,0.002,azm])                                      #OK defaults if fxn #3 not 1st in iprm file
123        codes.extend([0,0,0,0,0,0,0])
124        Iparm1 = makeInstDict(names,data,codes)
125        Iparm1['Source'] = [Irads[irad],Irads[irad]]
126        Iparm1['Bank'] = [Bank,Bank,0]
127        return [Iparm1,{}]
128    elif 'T' in DataType:
129        names = ['Type','fltPath','2-theta','difC','difA', 'difB','Zero','alpha','beta-0','beta-1',
130            'beta-q','sig-0','sig-1','sig-2','sig-q', 'X','Y','Azimuth',]
131        codes = [0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,]
132        azm = 0.
133        if 'INS  1DETAZM' in Iparm:
134            azm = float(Iparm['INS  1DETAZM'])
135        rd.Sample['Azimuth'] = azm
136        fltPath0 = 20.                      #arbitrary
137        if 'INS   FPATH1' in Iparm:
138            s = Iparm['INS   FPATH1'].split()
139            fltPath0 = sfloat(s[0])
140        if 'INS  1BNKPAR' not in Iparm:     #bank missing from Iparm file
141            return []
142        s = Iparm['INS  1BNKPAR'].split()
143        fltPath1 = sfloat(s[0])
144        data.extend([fltPath0+fltPath1,])               #Flight path source-sample-detector
145        data.extend([sfloat(s[1]),])               #2-theta for bank
146        s = Iparm['INS  1 ICONS'].split()
147        data.extend([sfloat(s[0]),sfloat(s[1]),0.0,sfloat(s[2])])    #difC,difA,difB,Zero
148        if 'INS  1PRCF  ' in Iparm:
149            s = Iparm['INS  1PRCF  '].split()
150            pfType = int(s[0])
151            s = Iparm['INS  1PRCF 1'].split()
152            if abs(pfType) == 1:
153                data.extend([sfloat(s[1]),sfloat(s[2]),sfloat(s[3])]) #alpha, beta-0, beta-1
154                s = Iparm['INS  1PRCF 2'].split()
155                data.extend([0.0,0.0,sfloat(s[1]),sfloat(s[2]),0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y
156            elif abs(pfType) in [3,4,5]:
157                data.extend([sfloat(s[0]),sfloat(s[1]),sfloat(s[2])]) #alpha, beta-0, beta-1
158                if abs(pfType) == 4:
159                    data.extend([0.0,0.0,sfloat(s[3]),0.0,0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y
160                else:
161                    s = Iparm['INS  1PRCF 2'].split()
162                    data.extend([0.0,0.0,sfloat(s[0]),sfloat(s[1]),0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y
163            elif abs(pfType) == 2:
164                data.extend([sfloat(s[1]),0.0,1./sfloat(s[3])]) #alpha, beta-0, beta-1
165                data.extend([0.0,0.0,sfloat(s[1]),0.0,0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y
166        else:
167            s = Iparm['INS  1PRCF1 '].split()
168            pfType = int(s[0])
169            s = Iparm['INS  1PRCF11'].split()
170            if abs(pfType) == 1:
171                data.extend([sfloat(s[1]),sfloat(s[2]),sfloat(s[3])]) #alpha, beta-0, beta-1
172                s = Iparm['INS  1PRCF12'].split()
173                data.extend([0.0,0.0,sfloat(s[1]),sfloat(s[2]),0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y
174            elif abs(pfType) in [3,4,5]:
175                data.extend([sfloat(s[0]),sfloat(s[1]),sfloat(s[2])]) #alpha, beta-0, beta-1
176                if abs(pfType) == 4:
177                    data.extend([0.0,0.0,sfloat(s[3]),0.0,0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y
178                else:
179                    s = Iparm['INS  1PRCF12'].split()
180                    data.extend([0.0,0.0,sfloat(s[0]),sfloat(s[1]),0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y
181        Inst1 = makeInstDict(names,data,codes)
182        Inst1['Bank'] = [Bank,Bank,0]
183        Inst2 = {}
184        if pfType < 0:
185            Ipab = 'INS  1PAB'+str(-pfType)
186            Npab = int(Iparm[Ipab+'  '].strip())
187            Inst2['Pdabc'] = []
188            for i in range(Npab):
189                k = Ipab+str(i+1).rjust(2)
190                s = Iparm[k].split()
191                Inst2['Pdabc'].append([float(t) for t in s])
192            Inst2['Pdabc'] = np.array(Inst2['Pdabc'])
193            Inst2['Pdabc'].T[3] += Inst2['Pdabc'].T[0]*Inst1['difC'][0] #turn 3rd col into TOF
194        if 'INS  1I ITYP' in Iparm:
195            s = Iparm['INS  1I ITYP'].split()
196            Ityp = int(s[0])
197            Tminmax = [float(s[1])*1000.,float(s[2])*1000.]
198            Itypes = ['Exponential','Maxwell/Exponential','','Maxwell/Chebyschev','']
199            if Ityp in [1,2,4]:
200                Inst2['Itype'] = Itypes[Ityp-1]
201                Inst2['Tminmax'] = Tminmax
202                Icoeff = []
203                Iesd = []
204                Icovar = []
205                for i in range(3):
206                    s = Iparm['INS  1ICOFF'+str(i+1)].split()
207                    Icoeff += [float(S) for S in s]
208                    s = Iparm['INS  1IECOF'+str(i+1)].split()
209                    Iesd += [float(S) for S in s]
210                NT = 10
211                for i in range(8):
212                    s = Iparm['INS  1IECOR'+str(i+1)]
213                    if i == 7:
214                        NT = 8
215                    Icovar += [float(s[6*j:6*j+6]) for j in range(NT)]
216                Inst2['Icoeff'] = Icoeff
217                Inst2['Iesd'] = Iesd
218                Inst2['Icovar'] = Icovar
219        return [Inst1,Inst2]
220
221def ReadPowderInstprm(instLines, bank, databanks, rd):
222    '''Read lines from a GSAS-II (new) instrument parameter file
223    similar to G2pwdGUI.OnLoad
224    If instprm file has multiple banks each with header #Bank n: ..., this
225    finds matching bank no. to load - problem with nonmatches?
226   
227    Note that this routine performs a similar role to :meth:`GSASIIdataGUI.GSASII.ReadPowderInstprm`,
228    but that will call a GUI routine for selection when needed. This routine will raise exceptions
229    on errors and will select the first bank when a choice might be appropriate.
230    TODO: refactor to combine the two routines.
231   
232    :param list instLines: strings from GSAS-II parameter file; can be concatenated with ';'
233    :param int  bank: bank number to check when instprm file has '#BANK n:...' strings
234         when bank = n then use parameters; otherwise skip that set. Ignored if BANK n:
235         not present. NB: this kind of instprm file made by a Save all profile command in Instrument Par     ameters
236    :return dict: Inst  instrument parameter dict if OK, or
237             str: Error message if failed
238   
239    (transliterated from GSASIIdataGUI.py:1235 (rev 3008), function of the same name)
240     ''' 
241    if 'GSAS-II' not in instLines[0]:
242        raise ValueError("Not a valid GSAS-II instprm file")
243
244    newItems = []
245    newVals = []
246    Found = False
247    il = 0
248    if bank is None:
249        banklist = set()
250        for S in instLines:
251            if S[0] == '#' and 'Bank' in S:
252                banklist.add(int(S.split(':')[0].split()[1]))
253        # Picks the first bank by default
254        if len(banklist) > 1:
255            bank = sorted(banklist)[0]
256        else:
257            bank = 1
258        rd.powderentry[2] = bank
259    while il < len(instLines):
260        S = instLines[il]
261        if S[0] == '#':
262            if Found:
263                break
264            if 'Bank' in S:
265                if bank == int(S.split(':')[0].split()[1]):
266                    il += 1
267                    S = instLines[il]
268                else:
269                    il += 1
270                    S = instLines[il]
271                    while il < len(instLines) and '#Bank' not in S:
272                        il += 1
273                        if il == len(instLines):
274                            raise ValueError("Bank {} not found in instprm file".format(bank))
275                        S = instLines[il]
276                    continue
277            else:
278                il += 1
279                S = instLines[il]
280        Found = True
281        if '"""' in S:
282            delim = '"""'
283        elif "'''" in S:
284            delim = "'''"
285        else:
286            S = S.replace(' ', '')
287            SS = S.strip().split(';')
288            for s in SS:
289                item, val = s.split(':', 1)
290                newItems.append(item)
291                try:
292                    newVals.append(float(val))
293                except ValueError:
294                    newVals.append(val)
295            il += 1
296            continue
297        # read multiline values, delimited by ''' or """
298        item, val = S.strip().split(':', 1)
299        val = val.replace(delim, '').rstrip()
300        val += '\n'
301        while True:
302            il += 1
303            if il >= len(instLines):
304                break
305            S = instLines[il]
306            if delim in S:
307                val += S.replace(delim, '').rstrip()
308                val += '\n'
309                break
310            else:
311                val += S.rstrip()
312                val += '\n'
313        newItems.append(item)
314        newVals.append(val)
315        il += 1
316    return [makeInstDict(newItems, newVals, len(newVals)*[False]), {}]
317
318def LoadImportRoutines(prefix, errprefix=None, traceback=False):
319    '''Routine to locate GSASII importers matching a prefix string
320    '''
321    if errprefix is None:
322        errprefix = prefix
323
324    readerlist = []
325    pathlist = sys.path[:]
326    if '.' not in pathlist:
327        pathlist.append('.')
328
329    potential_files = []
330    for path in pathlist:
331        for filename in glob.iglob(os.path.join(path, 'G2'+prefix+'*.py')):
332            potential_files.append(filename)
333
334    potential_files = sorted(list(set(potential_files)))
335    for filename in potential_files:
336        path, rootname = os.path.split(filename)
337        pkg = os.path.splitext(rootname)[0]
338
339        try:
340            fp = None
341            fp, fppath, desc = imp.find_module(pkg, [path])
342            pkg = imp.load_module(pkg, fp, fppath, desc)
343            for name, value in inspect.getmembers(pkg):
344                if name.startswith('_'):
345                    continue
346                if inspect.isclass(value):
347                    for method in 'Reader', 'ExtensionValidator', 'ContentsValidator':
348                        if not hasattr(value, method):
349                            break
350                        if not callable(getattr(value, method)):
351                            break
352                    else:
353                        reader = value()
354                        if reader.UseReader:
355                            readerlist.append(reader)
356        except AttributeError:
357            print ('Import_' + errprefix + ': Attribute Error ' + filename)
358            if traceback:
359                traceback.print_exc(file=sys.stdout)
360        except Exception as exc:
361            print ('\nImport_' + errprefix + ': Error importing file ' + filename)
362            print (u'Error message: {}\n'.format(exc))
363            if traceback:
364                traceback.print_exc(file=sys.stdout)
365        finally:
366            if fp:
367                fp.close()
368
369    return readerlist
370
371def LoadExportRoutines():
372    '''Placeholder that will someday retrieve the exporters
373    '''
374    pass
Note: See TracBrowser for help on using the repository browser.