source: trunk/GSASIIfiles.py @ 3000

Last change on this file since 3000 was 3000, checked in by toby, 4 years ago

make the two frame version the trunk as we hit version 3000

  • Property svn:eol-style set to native
File size: 15.0 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'''
23
24import os
25import sys
26import glob
27import imp
28import inspect
29import traceback
30import platform
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 GSASII.py:1012, 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        bank = sorted(banklist[1])
254        rd.powderentry[2] = bank
255    while il < len(instLines):
256        S = instLines[il]
257        if S[0] == '#':
258            if Found:
259                break
260            if 'Bank' in S:
261                if bank == int(S.split(':')[0].split()[1]):
262                    il += 1
263                    S = instLines[il]
264                else:
265                    il += 1
266                    S = instLines[il]
267                    while il < len(instLines) and '#Bank' not in S:
268                        il += 1
269                        if il == len(instLines):
270                            raise ValueError("Bank {} not found in instprm file".format(bank))
271                        S = instLines[il]
272                    continue
273            else:
274                il += 1
275                S = instLines[il]
276        Found = True
277        if '"""' in S:
278            delim = '"""'
279        elif "'''" in S:
280            delim = "'''"
281        else:
282            S = S.replace(' ', '')
283            SS = S.strip().split(';')
284            for s in SS:
285                item, val = s.split(':', 1)
286                newItems.append(item)
287                try:
288                    newVals.append(float(val))
289                except ValueError:
290                    newVals.append(val)
291            il += 1
292            continue
293        # read multiline values, delimited by ''' or """
294        item, val = S.strip().split(':', 1)
295        val = val.replace(delim, '').rstrip()
296        val += '\n'
297        while True:
298            il += 1
299            if il >= len(instLines):
300                break
301            S = instLines[il]
302            if delim in S:
303                val += S.replace(delim, '').rstrip()
304                val += '\n'
305                break
306            else:
307                val += S.rstrip()
308                val += '\n'
309        newItems.append(item)
310        newVals.append(val)
311        il += 1
312    return [makeInstDict(newItems, newVals, len(newVals)*[False]), {}]
313
314def LoadImportRoutines(prefix, errprefix=None, traceback=False):
315    '''Routine to locate GSASII importers matching a prefix string
316    '''
317    if errprefix is None:
318        errprefix = prefix
319
320    readerlist = []
321    pathlist = sys.path[:]
322    if '.' not in pathlist:
323        pathlist.append('.')
324
325    potential_files = []
326    for path in pathlist:
327        for filename in glob.iglob(os.path.join(path, 'G2'+prefix+'*.py')):
328            potential_files.append(filename)
329
330    potential_files = sorted(list(set(potential_files)))
331    for filename in potential_files:
332        path, rootname = os.path.split(filename)
333        pkg = os.path.splitext(rootname)[0]
334
335        try:
336            fp = None
337            fp, fppath, desc = imp.find_module(pkg, [path])
338            pkg = imp.load_module(pkg, fp, fppath, desc)
339            for name, value in inspect.getmembers(pkg):
340                if name.startswith('_'):
341                    continue
342                if inspect.isclass(value):
343                    for method in 'Reader', 'ExtensionValidator', 'ContentsValidator':
344                        if not hasattr(value, method):
345                            break
346                        if not callable(getattr(value, method)):
347                            break
348                    else:
349                        reader = value()
350                        if reader.UseReader:
351                            readerlist.append(reader)
352        except AttributeError:
353            print 'Import_' + errprefix + ': Attribute Error ' + filename
354            if traceback:
355                traceback.print_exc(file=sys.stdout)
356        except Exception as exc:
357            print '\nImport_' + errprefix + ': Error importing file ' + filename
358            print u'Error message: {}\n'.format(exc)
359            if traceback:
360                traceback.print_exc(file=sys.stdout)
361        finally:
362            if fp:
363                fp.close()
364
365    return readerlist
366
367def LoadExportRoutines():
368    '''Placeholder that will someday retrieve the exporters
369    '''
370    pass
Note: See TracBrowser for help on using the repository browser.