source: trunk/imports/G2phase_CIF.py @ 1069

Last change on this file since 1069 was 1069, checked in by toby, 8 years ago

finally a working CIF exporter (export mechanism needs configuring); work around windows file names in PyCifRW & missing unicode char

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