source: trunk/imports/G2phase_CIF.py @ 1123

Last change on this file since 1123 was 1123, checked in by toby, 9 years ago

add import and export routines to sphinx

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