source: trunk/imports/G2phase_CIF.py @ 1006

Last change on this file since 1006 was 1006, checked in by toby, 10 years ago

fix Bob's bug when multiple HKL files are read; pickup shelx spacegroup in CIF; improve file read error messages

  • Property svn:eol-style set to native
File size: 10.9 KB
Line 
1# -*- coding: utf-8 -*-
2########### SVN repository information ###################
3# $Date: 2012-02-13 11:33:35 -0600 (Mon, 13 Feb 2012) $
4# $Author: vondreele & toby $
5# $Revision: 482 $
6# $URL: https://subversion.xor.aps.anl.gov/pyGSAS/trunk/G2importphase_CIF.py $
7# $Id: G2importphase_CIF.py 482 2012-02-13 17:33:35Z vondreele $
8########### SVN repository information ###################
9# Routines to import Phase information from CIF files
10import sys
11import random as ran
12import GSASIIIO as G2IO
13import GSASIIspc as G2spc
14import GSASIIElem as G2elem
15import GSASIIlattice as G2lat
16import CifFile as cif # PyCifRW from James Hester
17import urllib
18
19class CIFPhaseReader(G2IO.ImportPhase):
20    def __init__(self):
21        super(self.__class__,self).__init__( # fancy way to say ImportPhase.__init__
22            extensionlist=('.CIF','.cif'),
23            strictExtension=False,
24            formatName = 'CIF',
25            longFormatName = 'Crystallographic Information File import'
26            )
27    def ContentsValidator(self, filepointer):
28        for i,line in enumerate(filepointer):
29            if i >= 1000: break
30            ''' Encountered only blank lines or comments in first 1000
31            lines. This is unlikely, but assume it is CIF since we are
32            even less likely to find a file with nothing but hashes and
33            blank lines'''
34            line = line.strip()
35            if len(line) == 0:
36                continue # ignore blank lines
37            elif line.startswith('#'):
38                continue # ignore comments
39            elif line.startswith('data_'):
40                return True
41            else:
42                return False # found something else
43        return True
44    def Reader(self,filename,filepointer, ParentFrame=None, **unused):
45        returnstat = False
46        cellitems = (
47            '_cell_length_a','_cell_length_b','_cell_length_c',
48            '_cell_angle_alpha','_cell_angle_beta','_cell_angle_gamma',)
49        reqitems = (
50             '_atom_site_fract_x',
51             '_atom_site_fract_y',
52             '_atom_site_fract_z',
53            )
54        phasenamefields = (
55            '_chemical_name_common',
56            '_pd_phase_name',
57            '_chemical_formula_sum'
58            )
59        try:
60#### development code (to speed testing)
61#            try:
62#                    fp = open(filename+'cP',"rb")
63#                    print("reading from "+filename+'cP')
64#                    cf = cPickle.load(fp)
65#                    fp.close()
66#            except:
67#                    cf = cif.ReadCif(filename)
68#                    fp = open(filename+'cP',"wb")
69#                    cPickle.dump(cf,fp)
70#                    fp.close()
71####
72#### end development code
73            self.ShowBusy() # this can take a while
74            ciffile = 'file:'+urllib.pathname2url(filename)
75            cf = cif.ReadCif(ciffile)
76            self.DoneBusy()
77            #print cf
78            # scan blocks for structural info
79            str_blklist = []
80            for blk in cf.keys():
81                for r in reqitems+cellitems:
82                    if r not in cf[blk].keys():
83                        break
84                else:
85                    str_blklist.append(blk)
86            if not str_blklist:
87                selblk = None # no block to choose
88            elif len(str_blklist) == 1: # only one choice
89                selblk = 0
90            else:                       # choose from options
91                choice = []
92                for blknm in str_blklist:
93                    choice.append('')
94                    # accumumlate some info about this phase
95                    choice[-1] += blknm + ': '
96                    for i in phasenamefields: # get a name for the phase
97                        name = cf[blknm].get(i)
98                        if name is None or name == '?' or name == '.':
99                            continue
100                        else:
101                            choice[-1] += name.strip()[:20] + ', '
102                            break
103                    na = len(cf[blknm].get("_atom_site_fract_x"))
104                    if na == 1:
105                        choice[-1] += '1 atom'
106                    else:
107                        choice[-1] += ('%d' % nd) + ' atoms'
108                    choice[-1] += ', cell: '
109                    fmt = "%.2f,"
110                    for i,key in enumerate(cellitems):
111                        if i == 3: fmt = "%.f,"
112                        if i == 5: fmt = "%.f"
113                        choice[-1] += fmt % cif.get_number_with_esd(
114                            cf[blknm].get(key))[0]
115                    sg = cf[blknm].get("_symmetry_space_group_name_H-M",'')
116                    if not sg: sg = cf[blknm].get("_space_group_name_H-M_alt",'')
117                    if sg: choice[-1] += ', (' + sg.strip() + ')'
118                selblk = self.PhaseSelector(
119                    choice,
120                    ParentFrame=ParentFrame,
121                    title= 'Select a phase from one the CIF data_ blocks below',
122                    size=(600,100)
123                    )
124            if selblk is None:
125                returnstat = False # no block selected or available
126            else:
127                blknm = str_blklist[selblk]
128                blk = cf[str_blklist[selblk]]
129                E = True
130                SpGrp = blk.get("_symmetry_space_group_name_H-M",'')
131                if not SpGrp:
132                    SpGrp = blk.get("_space_group_name_H-M_alt",'')
133                # try normalizing the space group, to see if we can pick the space group out of a table
134                SpGrpNorm = G2spc.StandardizeSpcName(SpGrp)
135                if SpGrpNorm:
136                    E,SGData = G2spc.SpcGroup(SpGrpNorm)
137                # nope, try the space group "out of the Box"
138                if E and SpGrp:
139                    E,SGData = G2spc.SpcGroup(SpGrp)
140                if E:
141                    if not SpGrp:
142                        self.warnings += 'No space group name was found in the CIF.'
143                        self.warnings += '\nThe space group has been set to "P 1". '
144                        self.warnings += "Change this in phase's General tab."
145                    else:
146                        self.warnings += 'ERROR in space group symbol '+SpGrp
147                        self.warnings += '\nThe space group has been set to "P 1". '
148                        self.warnings += "Change this in phase's General tab."
149                        self.warnings += '\nAre there spaces separating axial fields?\n\nError msg: '
150                        self.warnings += G2spc.SGErrors(E)
151                    SGData = G2IO.SGData # P 1
152                self.Phase['General']['SGData'] = SGData
153                # cell parameters
154                cell = []
155                for lbl in (
156                    '_cell_length_a','_cell_length_b','_cell_length_c',
157                    '_cell_angle_alpha','_cell_angle_beta','_cell_angle_gamma',
158                    ):
159                    cell.append(cif.get_number_with_esd(blk[lbl])[0])
160                Volume = G2lat.calc_V(G2lat.cell2A(cell))
161                self.Phase['General']['Cell'] = [False,]+cell+[Volume,]
162                # read in atoms
163                atomloop = blk.GetLoop('_atom_site_label')
164                atomkeys = [i.lower() for i in atomloop.keys()]
165                if blk.get('_atom_site_aniso_label'):
166                    anisoloop = blk.GetLoop('_atom_site_aniso_label')
167                    anisokeys = [i.lower() for i in anisoloop.keys()]
168                else:
169                    anisoloop = None
170                    anisokeys = []
171                self.Phase['Atoms'] = []
172                G2AtomDict = {  '_atom_site_type_symbol' : 1,
173                                '_atom_site_label' : 0,
174                                '_atom_site_fract_x' : 3,
175                                '_atom_site_fract_y' : 4,
176                                '_atom_site_fract_z' : 5,
177                                '_atom_site_occupancy' : 6,
178                                '_atom_site_aniso_u_11' : 11,
179                                '_atom_site_aniso_u_22' : 12,
180                                '_atom_site_aniso_u_33' : 13,
181                                '_atom_site_aniso_u_12' : 14,
182                                '_atom_site_aniso_u_13' : 15,
183                                '_atom_site_aniso_u_23' : 16, }
184                for aitem in atomloop:
185                    atomlist = ['','','',0,0,0,1.0,'',0,'I',0.01,0,0,0,0,0,0]
186                    atomlist.append(ran.randint(0,sys.maxint)) # add a unique label
187                    for val,key in zip(aitem,atomkeys):
188                        col = G2AtomDict.get(key)
189                        if col >= 3:
190                            atomlist[col] = cif.get_number_with_esd(val)[0]
191                        elif col is not None:
192                            atomlist[col] = val
193                        elif key in ('_atom_site_thermal_displace_type',
194                                   '_atom_site_adp_type'):   #Iso or Aniso?
195                            if val.lower() == 'uani':
196                                atomlist[9] = 'A'
197                        elif key == '_atom_site_u_iso_or_equiv':
198                            atomlist[10] =cif.get_number_with_esd(val)[0]
199                    if not atomlist[1] and atomlist[0]:
200                        for i in range(2,0,-1):
201                            typ = atomlist[0].strip()[:i]
202                            if G2elem.CheckElement(typ):
203                                atomlist[1] = typ
204                            if not atomlist[1]: atomlist[1] = 'Xe'
205                    ulbl = '_atom_site_aniso_label'
206                    if  atomlist[9] == 'A' and atomlist[0] in blk.get(ulbl):
207                        for val,key in zip(anisoloop.GetKeyedPacket(ulbl,atomlist[0]),
208                                           anisokeys):
209                            col = G2AtomDict.get(key)
210                            if col:
211                                atomlist[col] = cif.get_number_with_esd(val)[0]
212                    atomlist[7],atomlist[8] = G2spc.SytSym(atomlist[3:6],SGData)
213                    atomlist[1] = G2elem.FixValence(atomlist[1])
214                    self.Phase['Atoms'].append(atomlist)
215                for lbl in phasenamefields: # get a name for the phase
216                    name = blk.get(lbl)
217                    if name is None:
218                        continue
219                    name = name.strip()
220                    if name == '?' or name == '.':
221                        continue
222                    else:
223                        break
224                else: # no name found, use block name for lack of a better choice
225                    name = blknm
226                self.Phase['General']['Name'] = name.strip()[:20]
227                returnstat = True
228        except Exception as detail:
229            print 'CIF error:',detail # for testing
230            print sys.exc_info()[0] # for testing
231            import traceback
232            print traceback.format_exc()
233            returnstat = False
234        return returnstat
Note: See TracBrowser for help on using the repository browser.