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 |
---|
9 | import sys |
---|
10 | import random as ran |
---|
11 | import GSASIIIO as G2IO |
---|
12 | import GSASIIspc as G2spc |
---|
13 | import GSASIIlattice as G2lat |
---|
14 | import CifFile as cif # PyCifRW from James Hester |
---|
15 | import urllib |
---|
16 | |
---|
17 | class 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 |
---|