source: trunk/G2importphase_CIF.py @ 524

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

fix cif bug; add print traceback on some exceptions

File size: 9.2 KB
Line 
1########### SVN repository information ###################
2# $Date: 2012-02-13 11:33:35 -0600 (Mon, 13 Feb 2012) $
3# $Author: vondreele & toby $
4# $Revision: 482 $
5# $URL: https://subversion.xor.aps.anl.gov/pyGSAS/trunk/G2importphase_CIF.py $
6# $Id: G2importphase_CIF.py 482 2012-02-13 17:33:35Z vondreele $
7########### SVN repository information ###################
8# Routines to import Phase information from CIF files
9import sys
10import random as ran
11import GSASIIIO as G2IO
12import GSASIIspc as G2spc
13import GSASIIlattice as G2lat
14import CifFile as cif # PyCifRW from James Hester
15import urllib
16
17class CIFPhaseReader(G2IO.ImportPhase):
18    def __init__(self):
19        super(self.__class__,self).__init__( # fancy way to say ImportPhase.__init__
20            #extensionlist=('.CIF','.cif'),
21            extensionlist=('.CIF','.cif','.pdb'), # just for test!
22            strictExtension=False,
23            formatName = 'CIF',
24            longFormatName = 'Crystallographic Information File import'
25            )
26    def ContentsValidator(self, filepointer):
27        filepointer.seek(0) # rewind the file pointer
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):
45        cellitems = (
46            '_cell_length_a','_cell_length_b','_cell_length_c',
47            '_cell_angle_alpha','_cell_angle_beta','_cell_angle_gamma',)
48        reqitems = (
49             '_atom_site_type_symbol',
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            #print cf
77            # scan blocks for structural info
78            str_blklist = []
79            for blk in cf.keys():
80                for r in reqitems+cellitems:
81                    if r not in cf[blk].keys():
82                        break
83                else:
84                    str_blklist.append(blk)
85            if not str_blklist:
86                return False            # no blocks with coordinates
87            elif len(str_blklist) == 1: # no choices
88                selblk = 0
89            else:                       # choose from options
90                choice = []
91                for blknm in str_blklist:
92                    choice.append('')
93                    # accumumlate some info about this phase
94                    choice[-1] += blknm + ': '
95                    for i in phasenamefields: # get a name for the phase
96                        name = cf[blknm].get(i).strip()
97                        if name is None or name == '?' or name == '.':
98                            continue
99                        else:
100                            choice[-1] += name.strip()[:20] + ', '
101                            break
102                    na = len(cf[blknm].get("_atom_site_fract_x"))
103                    if na == 1:
104                        choice[-1] += '1 atom'
105                    else:
106                        choice[-1] += ('%d' % nd) + ' atoms'
107                    choice[-1] += ', cell: '
108                    fmt = "%.2f,"
109                    for i,key in enumerate(cellitems):
110                        if i == 3: fmt = "%.f,"
111                        if i == 5: fmt = "%.f"
112                        choice[-1] += fmt % cif.get_number_with_esd(
113                            cf[blknm].get(key))[0]
114                    sg = cf[blknm].get("_symmetry_space_group_name_H-M")
115                    if sg: choice[-1] += ', (' + sg.strip() + ')'
116                selblk = self.PhaseSelector(
117                    choice,
118                    ParentFrame=ParentFrame,
119                    title= 'Select a phase from one the CIF data_ blocks below',
120                    size=(600,100)
121                    )
122                if selblk is None: return False # User pressed cancel
123            blknm = str_blklist[selblk]
124            blk = cf[str_blklist[selblk]]
125            SpGrp = blk.get("_symmetry_space_group_name_H-M")
126            if SpGrp:
127                 E,SGData = G2spc.SpcGroup(SpGrp)
128            if E:
129                self.warnings += ' ERROR in space group symbol '+SpGrp
130                self.warnings += ' N.B.: make sure spaces separate axial fields in symbol' 
131                self.warnings += G2spc.SGErrors(E)
132            else:
133                self.Phase['General']['SGData'] = SGData
134            # cell parameters
135            cell = []
136            for lbl in (
137                '_cell_length_a','_cell_length_b','_cell_length_c',
138                '_cell_angle_alpha','_cell_angle_beta','_cell_angle_gamma',
139                ):
140                cell.append(cif.get_number_with_esd(blk[lbl])[0])
141            Volume = G2lat.calc_V(G2lat.cell2A(cell))
142            self.Phase['General']['Cell'] = [False,]+cell+[Volume,]
143            # read in atoms
144            atomloop = blk.GetLoop('_atom_site_label')
145            atomkeys = [i.lower() for i in atomloop.keys()]
146            if blk.get('_atom_site_aniso_label'):
147                anisoloop = blk.GetLoop('_atom_site_aniso_label')
148                anisokeys = [i.lower() for i in anisoloop.keys()]
149            else:
150                anisoloop = None
151                anisokeys = []
152            self.Phase['Atoms'] = []
153            G2AtomDict = {  '_atom_site_type_symbol' : 1,
154                            '_atom_site_label' : 0,
155                            '_atom_site_fract_x' : 3,
156                            '_atom_site_fract_y' : 4,
157                            '_atom_site_fract_z' : 5,
158                            '_atom_site_occupancy' : 6,
159                            '_atom_site_aniso_u_11' : 11,
160                            '_atom_site_aniso_u_22' : 12,
161                            '_atom_site_aniso_u_33' : 13,
162                            '_atom_site_aniso_u_12' : 14,
163                            '_atom_site_aniso_u_13' : 15,
164                            '_atom_site_aniso_u_23' : 16, }
165            for aitem in atomloop:
166                atomlist = ['','','',0,0,0,1.0,'',0,'I',0.01,0,0,0,0,0,0]
167                atomlist.append(ran.randint(0,sys.maxint)) # add a unique label
168                for val,key in zip(aitem,atomkeys):
169                    col = G2AtomDict.get(key)
170                    if col >= 3:
171                        atomlist[col] = cif.get_number_with_esd(val)[0]
172                    elif col is not None:
173                        atomlist[col] = val
174                    elif key in ('_atom_site_thermal_displace_type',
175                               '_atom_site_adp_type'):   #Iso or Aniso?
176                        if val.lower() == 'uani':
177                            atomlist[9] = 'A'
178                    elif key == '_atom_site_u_iso_or_equiv':
179                        atomlist[10] =cif.get_number_with_esd(val)[0]
180                ulbl = '_atom_site_aniso_label'
181                if  atomlist[9] == 'A' and atomlist[0] in blk.get(ulbl):
182                    for val,key in zip(anisoloop.GetKeyedPacket(ulbl,atomlist[0]),
183                                       anisokeys):
184                        col = G2AtomDict.get(key)
185                        if col:
186                            atomlist[col] = cif.get_number_with_esd(val)[0]
187                atomlist[7],atomlist[8] = G2spc.SytSym(atomlist[3:6],SGData)
188                self.Phase['Atoms'].append(atomlist)
189            for lbl in phasenamefields: # get a name for the phase
190                name = blk.get(lbl)
191                if name is None:
192                    continue
193                name = name.strip()
194                if name == '?' or name == '.':
195                    continue
196                else:
197                    break
198            else: # no name found, use block name for lack of a better choice
199                name = blknm
200            self.Phase['General']['Name'] = name.strip()[:20]
201            return True
202        except Exception as detail:
203            print 'CIF error:',detail # for testing
204            print sys.exc_info()[0] # for testing
205            import traceback
206            print traceback.format_exc()
207            return False
208        finally:
209            self.DoneBusy()
210
Note: See TracBrowser for help on using the repository browser.