1 | # -*- coding: utf-8 -*- |
---|
2 | ########### SVN repository information ################### |
---|
3 | # $Date: 2015-08-12 18:30:41 +0000 (Wed, 12 Aug 2015) $ |
---|
4 | # $Author: vondreele $ |
---|
5 | # $Revision: 1956 $ |
---|
6 | # $URL: trunk/imports/G2sfact_CIF.py $ |
---|
7 | # $Id: G2sfact_CIF.py 1956 2015-08-12 18:30:41Z vondreele $ |
---|
8 | ########### SVN repository information ################### |
---|
9 | ''' |
---|
10 | *Module G2sfact_CIF: CIF import* |
---|
11 | ----------------------------------- |
---|
12 | Read structure factors from a CIF reflection table. |
---|
13 | |
---|
14 | ''' |
---|
15 | # routines to read in structure factors from a CIF |
---|
16 | # |
---|
17 | import sys |
---|
18 | import numpy as np |
---|
19 | import os.path |
---|
20 | import GSASIIIO as G2IO |
---|
21 | import GSASIIpath |
---|
22 | GSASIIpath.SetVersionNumber("$Revision: 1956 $") |
---|
23 | import CifFile as cif # PyCifRW from James Hester |
---|
24 | |
---|
25 | class CIFhklReader(G2IO.ImportStructFactor): |
---|
26 | 'Routines to import Phase information from a CIF file' |
---|
27 | def __init__(self): |
---|
28 | super(self.__class__,self).__init__( # fancy way to self-reference |
---|
29 | extensionlist = ('.CIF','.cif','.FCF','.fcf','.HKL','.hkl'), |
---|
30 | strictExtension = False, |
---|
31 | formatName = 'CIF', |
---|
32 | longFormatName = 'CIF format structure factor file (.cif or .hkl)' |
---|
33 | ) |
---|
34 | # Validate the contents |
---|
35 | def ContentsValidator(self, filepointer): |
---|
36 | 'Use standard CIF validator' |
---|
37 | return self.CIFValidator(filepointer) |
---|
38 | |
---|
39 | def Reader(self, filename, filepointer, ParentFrame=None, **kwarg): |
---|
40 | '''Read single crystal data from a CIF. |
---|
41 | If multiple datasets are requested, use self.repeat and buffer caching. |
---|
42 | ''' |
---|
43 | hklitems = [('_refln_index_h','_refln_index_k','_refln_index_l','_refln_index_m_1'), |
---|
44 | ('_refln.index_h','_refln.index_k','_refln.index_l','_refln.index_m_1')] |
---|
45 | cellitems = [ |
---|
46 | ('_cell_length_a','_cell_length_b','_cell_length_c', |
---|
47 | '_cell_angle_alpha','_cell_angle_beta','_cell_angle_gamma',), |
---|
48 | ('_cell.length_a','_cell.length_b','_cell.length_c', |
---|
49 | '_cell.angle_alpha','_cell.angle_beta','_cell.angle_gamma',),] |
---|
50 | |
---|
51 | Fdatanames = ('_refln_f_meas','_refln.f_meas','_refln.f_meas_au', |
---|
52 | ) |
---|
53 | |
---|
54 | F2datanames = ('_refln_f_squared_meas','_refln.f_squared_meas', |
---|
55 | '_refln_intensity_meas','_refln.intensity_meas', |
---|
56 | ) |
---|
57 | |
---|
58 | Idatanames = ('_refln_intensity_meas','_refln.intensity_meas', |
---|
59 | ) # not used yet |
---|
60 | |
---|
61 | Isignames = ('_refln_intensity_meas_sigma','_refln.intensity_meas_sigma', |
---|
62 | ) # not used yet |
---|
63 | |
---|
64 | Fcalcnames = ('_refln_f_calc','_refln.f_calc','_refln.f_calc_au', |
---|
65 | ) |
---|
66 | |
---|
67 | F2calcnames = ('_refln_f_squared_calc','_refln.f_squared_calc', |
---|
68 | ) |
---|
69 | |
---|
70 | Fsignames = ('_refln_f_meas_sigma','_refln.f_meas_sigma','_refln.f_meas_sigma_au', |
---|
71 | '_refln_f_sigma', |
---|
72 | ) |
---|
73 | |
---|
74 | F2signames = ('_refln_f_squared_meas_sigma','_refln.f_squared_meas_sigma', |
---|
75 | '_refln_f_squared_sigma', |
---|
76 | '_refln_intensity_meas_sigma','_refln.intensity_meas_sigma', |
---|
77 | '_refln.intensity_sigma',) |
---|
78 | |
---|
79 | phasenames = ('_refln_phase_calc','_refln.phase_calc', |
---|
80 | ) |
---|
81 | |
---|
82 | |
---|
83 | SGdataname = ('_symmetry_space_group_name_H-M', '_symmetry.space_group_name_H-M') |
---|
84 | |
---|
85 | phasenamefields = ( |
---|
86 | '_chemical_name_common', |
---|
87 | '_pd_phase_name', |
---|
88 | '_chemical_formula_sum' |
---|
89 | ) |
---|
90 | rdbuffer = kwarg.get('buffer') |
---|
91 | cf = None |
---|
92 | try: |
---|
93 | if self.repeat and rdbuffer is not None: |
---|
94 | cf = rdbuffer.get('lastcif') |
---|
95 | print 'Reusing previously parsed CIF' |
---|
96 | if cf is None: |
---|
97 | self.ShowBusy() # this can take a while |
---|
98 | try: |
---|
99 | cf = G2IO.ReadCIF(filename) |
---|
100 | except Exception as detail: |
---|
101 | self.errors = "Parse or reading of file failed in pyCifRW; check syntax of file in enCIFer or CheckCIF" |
---|
102 | return False |
---|
103 | finally: |
---|
104 | self.DoneBusy() |
---|
105 | # scan blocks for reflections |
---|
106 | self.errors = 'Error during scan of blocks for datasets' |
---|
107 | blklist = [] |
---|
108 | for blk in cf.keys(): # scan for reflections, F or F2 values and cell lengths. |
---|
109 | # Ignore blocks that do not have structure factors and a cell |
---|
110 | blkkeys = [k.lower() for k in cf[blk].keys()] |
---|
111 | gotFo = False |
---|
112 | gotFo2 = False |
---|
113 | im = 0 |
---|
114 | for i in range(2): |
---|
115 | if hklitems[i][3] in blkkeys: #Super lattice reflections h,k,l,m |
---|
116 | im = 1 |
---|
117 | if hklitems[i][0] in blkkeys and hklitems[i][1] in blkkeys and hklitems[i][2] in blkkeys: |
---|
118 | dnIndex = i |
---|
119 | break |
---|
120 | else: |
---|
121 | break # no reflections |
---|
122 | for dn in Fdatanames: |
---|
123 | if dn in blkkeys: |
---|
124 | blklist.append(blk) |
---|
125 | gotFo = True |
---|
126 | break |
---|
127 | if gotFo: break |
---|
128 | for dn in F2datanames: |
---|
129 | if dn in blkkeys: |
---|
130 | blklist.append(blk) |
---|
131 | break |
---|
132 | else: |
---|
133 | break |
---|
134 | if not blklist: |
---|
135 | selblk = None # no block to choose |
---|
136 | elif len(blklist) == 1: # only one choice |
---|
137 | selblk = 0 |
---|
138 | else: # choose from options |
---|
139 | choice = [] |
---|
140 | for blknm in blklist: |
---|
141 | choice.append('') |
---|
142 | # accumulate some info about this phase |
---|
143 | choice[-1] += blknm + ': ' |
---|
144 | for i in phasenamefields: # get a name for the phase |
---|
145 | name = cf[blknm].get(i) |
---|
146 | if name is None or name == '?' or name == '.': |
---|
147 | continue |
---|
148 | else: |
---|
149 | choice[-1] += name.strip()[:20] + ', ' |
---|
150 | break |
---|
151 | s = '' |
---|
152 | fmt = "%.2f," |
---|
153 | for i,key in enumerate(cellitems[dnIndex]): |
---|
154 | if i == 3: fmt = "%.f," |
---|
155 | if i == 5: fmt = "%.f" |
---|
156 | val = cf[blknm].get(key) |
---|
157 | if val is None: break |
---|
158 | s += fmt % cif.get_number_with_esd(val)[0] |
---|
159 | if s: choice[-1] += ', cell: ' + s |
---|
160 | for dn in SGdataname: |
---|
161 | sg = cf[blknm].get(dn) |
---|
162 | if sg: |
---|
163 | choice[-1] += ', (' + sg.strip() + ')' |
---|
164 | break |
---|
165 | choice.append('Import all of the above') |
---|
166 | if self.repeat: # we were called to repeat the read |
---|
167 | selblk = self.repeatcount |
---|
168 | self.repeatcount += 1 |
---|
169 | if self.repeatcount >= len(blklist): self.repeat = False |
---|
170 | else: |
---|
171 | selblk = self.BlockSelector( |
---|
172 | choice, |
---|
173 | ParentFrame=ParentFrame, |
---|
174 | title='Select a dataset from one the CIF data_ blocks below', |
---|
175 | size=(600,100), |
---|
176 | header='Dataset Selector') |
---|
177 | self.errors = 'Error during reading of selected block' |
---|
178 | if selblk is None: |
---|
179 | return False # no block selected or available |
---|
180 | if selblk >= len(blklist): # all blocks selected |
---|
181 | selblk = 0 |
---|
182 | self.repeat = True |
---|
183 | if rdbuffer is not None: |
---|
184 | rdbuffer['lastcif'] = cf # save the parsed cif for the next loop |
---|
185 | self.repeatcount = 1 |
---|
186 | blknm = blklist[selblk] |
---|
187 | blk = cf[blklist[selblk]] |
---|
188 | self.objname = os.path.basename(filename)+':'+str(blknm) |
---|
189 | self.errors = 'Error during reading of reflections' |
---|
190 | # read in reflections |
---|
191 | try: |
---|
192 | refloop = blk.GetLoop(hklitems[0][0]) |
---|
193 | dnIndex = 0 |
---|
194 | except KeyError: |
---|
195 | try: |
---|
196 | refloop = blk.GetLoop(hklitems[1][0]) |
---|
197 | dnIndex = 1 |
---|
198 | except KeyError: |
---|
199 | self.errors += "\nUnexpected: '_refln[-.]index_h not found!" |
---|
200 | return False |
---|
201 | itemkeys = {} |
---|
202 | # prepare an index to the CIF reflection loop |
---|
203 | for i,key in enumerate(refloop.keys()): |
---|
204 | itemkeys[key.lower()] = i |
---|
205 | |
---|
206 | # scan for data names: |
---|
207 | F2dn = None |
---|
208 | Fdn = None |
---|
209 | F2cdn = None |
---|
210 | Fcdn = None |
---|
211 | F2sdn = None |
---|
212 | Fsdn = None |
---|
213 | Phdn = None |
---|
214 | FcalcPresent = False |
---|
215 | for dn in F2datanames: |
---|
216 | if dn in itemkeys: |
---|
217 | F2dn = dn |
---|
218 | for dm in F2calcnames: |
---|
219 | if dm in itemkeys: |
---|
220 | F2cdn = dm |
---|
221 | FcalcPresent = True |
---|
222 | break |
---|
223 | for dm in F2signames: |
---|
224 | if dm in itemkeys: |
---|
225 | F2sdn = dm |
---|
226 | break |
---|
227 | break |
---|
228 | else: |
---|
229 | for dn in Fdatanames: |
---|
230 | if dn in itemkeys: |
---|
231 | Fdn = dn |
---|
232 | for dm in Fcalcnames: |
---|
233 | if dm in itemkeys: |
---|
234 | Fcdn = dm |
---|
235 | FcalcPresent = True |
---|
236 | break |
---|
237 | for dm in Fsignames: |
---|
238 | if dm in itemkeys: |
---|
239 | Fsdn = dm |
---|
240 | break |
---|
241 | break |
---|
242 | else: |
---|
243 | msg = "\nno F or F2 loop value found in file\n" |
---|
244 | msg += "A CIF reflection file needs to have at least one of\n" |
---|
245 | for dn in F2datanames+Fdatanames: |
---|
246 | msg += dn + ', ' |
---|
247 | self.errors += msg |
---|
248 | return False |
---|
249 | for dn in phasenames: |
---|
250 | if dn in itemkeys: |
---|
251 | Phdn = dn |
---|
252 | break |
---|
253 | |
---|
254 | # loop over all reflections |
---|
255 | for item in refloop: |
---|
256 | F2c = 0.0 |
---|
257 | sigF2 = 0.0 |
---|
258 | HKL = [] |
---|
259 | try: |
---|
260 | for i in hklitems[dnIndex][:3+im]: # '_refln[._]index_[hkl]' |
---|
261 | num = itemkeys.get(i) |
---|
262 | try: |
---|
263 | HKL.append(int(item[num])) |
---|
264 | except: |
---|
265 | HKL.append('.') |
---|
266 | #h,k,l,m,dsp,Fo2,sig,Fc2,Fot2,Fct2,phase,Ext |
---|
267 | if im: |
---|
268 | ref = HKL+[1,0,0,0,1, 0,0,0,0,0, 0,0] |
---|
269 | else: |
---|
270 | ref = HKL+[1,0,0,1,0, 0,0,0,0,0, 0] |
---|
271 | if F2dn: |
---|
272 | F2 = item[itemkeys[F2dn]] |
---|
273 | if '(' in F2: |
---|
274 | F2, sigF2 = cif.get_number_with_esd(F2) |
---|
275 | F2 = float(F2) |
---|
276 | sigF2 = float(sigF2) |
---|
277 | elif F2sdn: |
---|
278 | F2 = float(F2) |
---|
279 | sigF2 = float(item[itemkeys[F2sdn]]) |
---|
280 | else: |
---|
281 | F2 = float(F2) |
---|
282 | try: |
---|
283 | if F2cdn: |
---|
284 | F2c = float(item[itemkeys[F2cdn]]) |
---|
285 | except: |
---|
286 | pass |
---|
287 | else: |
---|
288 | F = item[itemkeys[Fdn]] |
---|
289 | if '(' in F: |
---|
290 | F, sig = cif.get_number_with_esd(F) |
---|
291 | elif Fsdn: |
---|
292 | F = float(F) |
---|
293 | sig = float(item[itemkeys[Fsdn]]) |
---|
294 | else: |
---|
295 | F = float(F) |
---|
296 | sig = 0.0 |
---|
297 | F2 = F**2 |
---|
298 | sigF2 = 2.0*F*sig |
---|
299 | try: |
---|
300 | if Fcdn: |
---|
301 | Fc = float(item[itemkeys[Fcdn]]) |
---|
302 | F2c = Fc*Fc |
---|
303 | except: |
---|
304 | pass |
---|
305 | |
---|
306 | ref[8+im] = F2 |
---|
307 | ref[5+im] = F2 |
---|
308 | ref[6+im] = sigF2 |
---|
309 | ref[9+im] = F2c |
---|
310 | ref[7+im] = F2c |
---|
311 | try: |
---|
312 | if Phdn: |
---|
313 | ref[10+im] = float(item[itemkeys[Phdn]]) |
---|
314 | except: |
---|
315 | pass |
---|
316 | except: |
---|
317 | continue # skip over incompletely parsed reflections |
---|
318 | self.RefDict['RefList'].append(ref) |
---|
319 | # self.RefDict['FF'].append({}) |
---|
320 | self.RefDict['RefList'] = np.array(self.RefDict['RefList']) |
---|
321 | self.errors = 'Error during reading of dataset parameters' |
---|
322 | if blk.get('_diffrn_radiation_probe'): |
---|
323 | if blk['_diffrn_radiation_probe'] == 'neutron': |
---|
324 | Type = 'SNC' |
---|
325 | elif blk.get('_diffrn_radiation.probe'): |
---|
326 | if blk['_diffrn_radiation.probe'] == 'neutron': |
---|
327 | Type = 'SNC' |
---|
328 | else: |
---|
329 | Type = 'SXC' |
---|
330 | self.RefDict['Type'] = Type |
---|
331 | self.RefDict['Super'] = im |
---|
332 | if blk.get('_diffrn_radiation_wavelength'): |
---|
333 | wave = float(blk['_diffrn_radiation_wavelength']) |
---|
334 | elif blk.get('_diffrn_radiation.wavelength'): |
---|
335 | wave = float(blk['_diffrn_radiation.wavelength']) |
---|
336 | else: |
---|
337 | wave = 0.70926 |
---|
338 | self.UpdateParameters(Type=Type,Wave=wave) # histogram type |
---|
339 | return True |
---|
340 | except Exception as detail: |
---|
341 | self.errors += '\n '+str(detail) |
---|
342 | print self.formatName+' read error:'+str(detail) # for testing |
---|
343 | import traceback |
---|
344 | traceback.print_exc(file=sys.stdout) |
---|
345 | return False |
---|