source: trunk/imports/G2sfact_CIF.py @ 4949

Last change on this file since 4949 was 4410, checked in by toby, 5 years ago

do much more cleanup after phase delete; refactor some importer imports to avoid G2IO

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