source: trunk/G2importphase_CIF.py @ 547

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

redo constraints input & editing; change file overdef in G2struct

File size: 9.5 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            strictExtension=False,
22            formatName = 'CIF',
23            longFormatName = 'Crystallographic Information File import'
24            )
25    def ContentsValidator(self, filepointer):
26        filepointer.seek(0) # rewind the file pointer
27        for i,line in enumerate(filepointer):
28            if i >= 1000: break
29            ''' Encountered only blank lines or comments in first 1000
30            lines. This is unlikely, but assume it is CIF since we are
31            even less likely to find a file with nothing but hashes and
32            blank lines'''
33            line = line.strip()
34            if len(line) == 0:
35                continue # ignore blank lines
36            elif line.startswith('#'):
37                continue # ignore comments
38            elif line.startswith('data_'):
39                return True
40            else:
41                return False # found something else
42        return True
43    def Reader(self,filename,filepointer, ParentFrame=None):
44        returnstat = False
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                selblk = None # no block to choose
87            elif len(str_blklist) == 1: # only one choice
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:
123                returnstat = False # no block selected or available
124            else:
125                blknm = str_blklist[selblk]
126                blk = cf[str_blklist[selblk]]
127                SpGrp = blk.get("_symmetry_space_group_name_H-M")
128                if SpGrp:
129                     E,SGData = G2spc.SpcGroup(SpGrp)
130                if E:
131                    self.warnings += ' ERROR in space group symbol '+SpGrp
132                    self.warnings += ' N.B.: make sure spaces separate axial fields in symbol' 
133                    self.warnings += G2spc.SGErrors(E)
134                else:
135                    self.Phase['General']['SGData'] = SGData
136                # cell parameters
137                cell = []
138                for lbl in (
139                    '_cell_length_a','_cell_length_b','_cell_length_c',
140                    '_cell_angle_alpha','_cell_angle_beta','_cell_angle_gamma',
141                    ):
142                    cell.append(cif.get_number_with_esd(blk[lbl])[0])
143                Volume = G2lat.calc_V(G2lat.cell2A(cell))
144                self.Phase['General']['Cell'] = [False,]+cell+[Volume,]
145                # read in atoms
146                atomloop = blk.GetLoop('_atom_site_label')
147                atomkeys = [i.lower() for i in atomloop.keys()]
148                if blk.get('_atom_site_aniso_label'):
149                    anisoloop = blk.GetLoop('_atom_site_aniso_label')
150                    anisokeys = [i.lower() for i in anisoloop.keys()]
151                else:
152                    anisoloop = None
153                    anisokeys = []
154                self.Phase['Atoms'] = []
155                G2AtomDict = {  '_atom_site_type_symbol' : 1,
156                                '_atom_site_label' : 0,
157                                '_atom_site_fract_x' : 3,
158                                '_atom_site_fract_y' : 4,
159                                '_atom_site_fract_z' : 5,
160                                '_atom_site_occupancy' : 6,
161                                '_atom_site_aniso_u_11' : 11,
162                                '_atom_site_aniso_u_22' : 12,
163                                '_atom_site_aniso_u_33' : 13,
164                                '_atom_site_aniso_u_12' : 14,
165                                '_atom_site_aniso_u_13' : 15,
166                                '_atom_site_aniso_u_23' : 16, }
167                for aitem in atomloop:
168                    atomlist = ['','','',0,0,0,1.0,'',0,'I',0.01,0,0,0,0,0,0]
169                    atomlist.append(ran.randint(0,sys.maxint)) # add a unique label
170                    for val,key in zip(aitem,atomkeys):
171                        col = G2AtomDict.get(key)
172                        if col >= 3:
173                            atomlist[col] = cif.get_number_with_esd(val)[0]
174                        elif col is not None:
175                            atomlist[col] = val
176                        elif key in ('_atom_site_thermal_displace_type',
177                                   '_atom_site_adp_type'):   #Iso or Aniso?
178                            if val.lower() == 'uani':
179                                atomlist[9] = 'A'
180                        elif key == '_atom_site_u_iso_or_equiv':
181                            atomlist[10] =cif.get_number_with_esd(val)[0]
182                    ulbl = '_atom_site_aniso_label'
183                    if  atomlist[9] == 'A' and atomlist[0] in blk.get(ulbl):
184                        for val,key in zip(anisoloop.GetKeyedPacket(ulbl,atomlist[0]),
185                                           anisokeys):
186                            col = G2AtomDict.get(key)
187                            if col:
188                                atomlist[col] = cif.get_number_with_esd(val)[0]
189                    atomlist[7],atomlist[8] = G2spc.SytSym(atomlist[3:6],SGData)
190                    self.Phase['Atoms'].append(atomlist)
191                for lbl in phasenamefields: # get a name for the phase
192                    name = blk.get(lbl)
193                    if name is None:
194                        continue
195                    name = name.strip()
196                    if name == '?' or name == '.':
197                        continue
198                    else:
199                        break
200                else: # no name found, use block name for lack of a better choice
201                    name = blknm
202                self.Phase['General']['Name'] = name.strip()[:20]
203                returnstat = True
204        except Exception as detail:
205            print 'CIF error:',detail # for testing
206            print sys.exc_info()[0] # for testing
207            import traceback
208            print traceback.format_exc()
209            returnstat = False
210        finally:
211            self.DoneBusy()
212        return returnstat
Note: See TracBrowser for help on using the repository browser.