source: trunk/exports/G2cif.py @ 956

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

snapshot of CIF dev

  • Property svn:eol-style set to native
File size: 37.4 KB
Line 
1'''Development code to export a GSAS-II project as a CIF
2The heavy lifting is done in method export
3'''
4
5import datetime as dt
6import os.path
7import GSASIIIO as G2IO
8reload(G2IO)
9import GSASIIgrid as G2gd
10import GSASIIstrIO as G2stIO
11#import GSASIImapvars as G2mv
12import GSASIImath as G2mth
13import GSASIIlattice as G2lat
14import GSASIIspc as G2spg
15
16def getCallerDocString(): # for development
17    "Return the calling function's doc string"
18    import inspect as ins
19    for item in ins.stack()[1][0].f_code.co_consts:
20        if type(item) is str:
21            return item
22    else:
23        return '?'
24
25class ExportCIF(G2IO.ExportBaseclass):
26    def __init__(self,G2frame):
27        super(self.__class__,self).__init__( # fancy way to say <parentclass>.__init__
28            G2frame=G2frame,
29            formatName = 'full CIF',
30            longFormatName = 'Export project as complete CIF'
31            )
32        self.author = ''
33
34    def export(self,mode='full'):
35        '''Export a CIF
36
37        :param str mode: "full" (default) to create a complete CIF of project,
38          "simple" for a simple CIF with only coordinates
39        '''
40        def WriteCIFitem(name,value=''):
41            if value:
42                if "\n" in value or len(value)> 70:
43                    if name.strip(): print name
44                    print '; '+value
45                    print '; '
46                elif " " in value:
47                    if len(name)+len(value) > 65:
48                        print name,'\n   ','"' + str(value) + '"'
49                    else:
50                        print name,'  ','"' + str(value) + '"'
51                else:
52                    if len(name)+len(value) > 65:
53                        print name,'\n   ',value
54                    else:
55                        print name,'  ',value
56            else:
57                print name
58
59        def WriteAudit():
60            WriteCIFitem('_audit_creation_method',
61                         'created in GSAS-II')
62            WriteCIFitem('_audit_creation_date',self.CIFdate)
63            if self.author:
64                WriteCIFitem('_audit_author_name',self.author)
65            WriteCIFitem('_audit_update_record',
66                         self.CIFdate+'  Initial software-generated CIF')
67
68        def WriteOverall():
69            '''TODO: Write out overall refinement information
70            '''
71            WriteCIFitem('_pd_proc_info_datetime', self.CIFdate)
72            WriteCIFitem('_pd_calc_method', 'Rietveld Refinement')
73            #WriteCIFitem('_refine_ls_shift/su_max',DAT1)
74            #WriteCIFitem('_refine_ls_shift/su_mean',DAT2)
75            WriteCIFitem('_computing_structure_refinement','GSAS-II')
76            try:
77                vars = str(len(self.OverallParms['Covariance']['varyList']))
78            except:
79                vars = '?'
80            WriteCIFitem('_refine_ls_number_parameters',vars)
81            try:
82                GOF = str(self.OverallParms['Covariance']['Rvals']['GOF'])
83            except:
84                GOF = '?'
85            WriteCIFitem('_refine_ls_goodness_of_fit_all',GOF)
86            #WriteCIFitem('_refine_ls_number_restraints',TEXT(1:7))
87            # other things to consider reporting
88            # _refine_ls_number_reflns
89            # _refine_ls_goodness_of_fit_obs
90            # _refine_ls_R_factor_all
91            # _refine_ls_R_factor_obs
92            # _refine_ls_wR_factor_all
93            # _refine_ls_wR_factor_obs
94            # _refine_ls_restrained_S_all
95            # _refine_ls_restrained_S_obs
96
97            # include an overall profile r-factor, if there is more than one powder histogram
98            if self.npowder > 1:
99                WriteCIFitem('\n# OVERALL POWDER R-FACTOR')
100                try:
101                    R = str(self.OverallParms['Covariance']['Rvals']['Rwp'])
102                except:
103                    R = '?'
104                WriteCIFitem('_pd_proc_ls_prof_wR_factor',R)
105                #WriteCIFitem('_pd_proc_ls_prof_R_factor',TEXT(11:20)) # who cares!
106            WriteCIFitem('_refine_ls_matrix_type','full')
107            #WriteCIFitem('_refine_ls_matrix_type','userblocks')
108
109        def WritePubTemplate():
110            '''TODO: insert the publication template ``template_publ.cif`` or some modified
111            version for this project. Store this in the GPX file?
112            '''
113            print getCallerDocString()
114
115        def WritePhaseTemplate():
116            '''TODO: insert the phase template ``template_phase.cif`` or some modified
117            version for this project
118            '''
119            print getCallerDocString()
120
121        def WritePowderTemplate():
122            '''TODO: insert the phase template ``template_instrument.cif`` or some modified
123            version for this project
124            '''
125            print getCallerDocString()
126
127        def WriteSnglXtalTemplate():
128            '''TODO: insert the single-crystal histogram template
129            for this project
130            '''
131            print getCallerDocString()
132
133        def FormatSH(phasedict):
134            'Format a full spherical harmonics texture description as a string'
135            # SH Texture
136            pfx = str(phasedict['pId'])+'::'
137            s = ""
138            textureData = phasedict['General']['SH Texture']   
139            if textureData.get('Order'):
140                s += "Spherical Harmonics correction. Order = "+str(textureData['Order'])
141                s += " Model: " + str(textureData['Model']) + "\n    Orientation angles: "
142                for name in ['omega','chi','phi']:
143                    aname = pfx+'SH '+name
144                    s += name + " = "
145                    sig = self.sigDict.get(aname,-0.09)
146                    s += G2mth.ValEsd(self.parmDict[aname],sig)
147                    s += "; "
148                s += "\n"
149                s1 = "    Coefficients:  "
150                for name in textureData['SH Coeff'][1]:
151                    aname = pfx+name
152                    if len(s1) > 60:
153                        s += s1 + "\n"
154                        s1 = "    "
155                    s1 += aname + ' = '
156                    sig = self.sigDict.get(aname,-0.0009)
157                    s1 += G2mth.ValEsd(self.parmDict[aname],sig)
158                    s1 += "; "
159                s += s1
160            return s
161
162        def FormatHAPpo(phasedict):
163            'return the March-Dollase/SH correction for every histogram in the current phase'
164            s = ''
165            for histogram in sorted(phasedict['Histograms']):
166                Histogram = self.Histograms.get(histogram)
167                if not Histogram: continue
168                hapData = phasedict['Histograms'][histogram]
169                if hapData['Pref.Ori.'][0] == 'MD':
170                    aname = str(phasedict['pId'])+':'+str(Histogram['hId'])+':MD'
171                    if self.parmDict.get(aname,1.0) != 1.0: continue
172                    sig = self.sigDict.get(aname,-0.009)
173                    if s != "": s += '\n'
174                    s += 'March-Dollase correction'
175                    if self.npowder > 1:
176                        s += ', histogram '+str(Histogram['hId']+1)
177                    s += ' coef. = ' + G2mth.ValEsd(self.parmDict[aname],sig)
178                    s += ' axis = ' + str(hapData['Pref.Ori.'][3])
179                else: # must be SH
180                    if s != "": s += '\n'
181                    s += 'Simple spherical harmonic correction'
182                    if self.npowder > 1:
183                        s += ', histogram '+str(Histogram['hId']+1)
184                    s += ' Order = '+str(hapData['Pref.Ori.'][4])+'\n'
185                    s1 = "    Coefficients:  "
186                    for item in hapData['Pref.Ori.'][5]:
187                        print item
188                        aname = str(phasedict['pId'])+':'+str(Histogram['hId'])+':'+item
189                        print aname
190                        if len(s1) > 60:
191                            s += s1 + "\n"
192                            s1 = "    "
193                        s1 += aname + ' = '
194                        sig = self.sigDict.get(aname,-0.0009)
195                        s1 += G2mth.ValEsd(self.parmDict[aname],sig)
196                        s1 += "; "
197                    s += s1
198            return s
199       
200        def FmtAtomType(sym):
201            'Reformat a GSAS-II atom type symbol to match CIF rules'
202            sym = sym.replace('_','') # underscores are not allowed: no isotope designation?
203            # in CIF oxidation state symbols come after, not before
204            if '+' in sym:
205                sym = sym.replace('+','') + '+'
206            elif '-' in sym:
207                sym = sym.replace('-','') + '-'
208            return sym
209           
210        def PutInCol(val,wid):
211            '''Pad a value to >=wid+1 columns by adding spaces at the end. Always
212            adds at least one space
213            '''
214            val = str(val).replace(' ','')
215            if not val: val = '?'
216            fmt = '{:' + str(wid) + '} '
217            return fmt.format(val)
218
219        def MakeUniqueLabel(lbl,labellist):
220            'Make sure that every atom label is unique'
221            lbl = lbl.strip()
222            if not lbl: # deal with a blank label
223                lbl = 'A_1'
224            if lbl not in labellist:
225                labellist.append(lbl)
226                return lbl
227            i = 1
228            prefix = lbl
229            if '_' in lbl:
230                prefix = lbl[:lbl.rfind('_')]
231                suffix = lbl[lbl.rfind('_')+1:]
232                try:
233                    i = int(suffix)+1
234                except:
235                    pass
236            while prefix+'_'+str(i) in labellist:
237                i += 1
238            else:
239                lbl = prefix+'_'+str(i)
240                labellist.append(lbl)
241
242        def WriteAtomsNuclear(phasenam):
243            phasedict = self.Phases[phasenam] # pointer to current phase info           
244            General = phasedict['General']
245            WriteCIFitem('\n# ATOMIC COORDINATES AND DISPLACEMENT PARAMETERS')
246            Atoms = phasedict['Atoms']
247            WriteCIFitem('loop_ '+
248                         '\n\t_atom_site_label'+
249                         '\n\t_atom_site_type_symbol'+
250                         '\n\t_atom_site_fract_x'+
251                         '\n\t_atom_site_fract_y'+
252                         '\n\t_atom_site_fract_z'+
253                         '\n\t_atom_site_occupancy'+
254                         '\n\t_atom_site_adp_type'+
255                         '\n\t_atom_site_U_iso_or_equiv'+
256                         '\n\t_atom_site_symmetry_multiplicity')
257
258            varnames = {3:'Ax',4:'Ay',5:'Az',6:'Afrac',
259                        10:'AUiso',11:'AU11',12:'AU22',13:'AU33',
260                        14:'AU12',15:'AU13',16:'AU23'}
261            labellist = []
262           
263            pfx = str(phasedict['pId'])+'::'
264            for i,at in enumerate(Atoms):
265                print at
266            for i,at in enumerate(Atoms):
267                s = " "
268                s += PutInCol(MakeUniqueLabel(at[0],labellist),6) # label
269                #s += PutInCol(MakeUniqueLabel('A',labellist),6) # label
270                s += PutInCol(FmtAtomType(at[1]),6) # type
271                if at[9] == 'I':
272                    adp = 'Uiso '
273                else:
274                    adp = 'Uani '
275                    t = 0.0
276                    for j in (11,12,13):
277                        var = pfx+varnames[j]+":"+str(i)
278                        t += self.parmDict.get(var,at[j])
279                for j in (3,4,5,6,10):
280                    if j in (3,4,5):
281                        dig = 11
282                        sigdig = -0.00009
283                    else:
284                        dig = 9
285                        sigdig = -0.009
286                    var = pfx+varnames[j]+":"+str(i)
287                    dvar = pfx+"d"+varnames[j]+":"+str(i)
288                    if dvar not in self.sigDict:
289                        dvar = var
290                    if j == 10 and adp == 'Uani ':
291                        # compute Uequiv crudely
292                        t = 0.0
293                        for k in (11,12,13):
294                            var = pfx+varnames[j]+":"+str(i)
295                            t += self.parmDict.get(var,at[k])
296                        val = t/3.
297                        sig = sigdig
298                    else:
299                        val = self.parmDict.get(var,at[j])
300                        sig = self.sigDict.get(dvar,sigdig)
301                    s += PutInCol(G2mth.ValEsd(val,sig),dig)
302                s += adp
303                print s
304       
305        def WritePhaseInfo(phasenam):
306            # see writepha.for
307            print 'TODO: phase info for',phasenam,'goes here'
308            # THINK: how to select publication flags for distances/angles?
309            phasedict = self.Phases[phasenam] # pointer to current phase info           
310            WriteCIFitem('_pd_phase_name', phasenam)
311            # replace some of these later
312            #General = phasedict['General']
313            #SGData = phasedict['General']['SGData']
314            #cell = General['Cell']
315            pfx = str(phasedict['pId'])+'::'
316            #covData = self.OverallParms['Covariance']
317            A,sigA = G2stIO.cellFill(pfx,phasedict['General']['SGData'],self.parmDict,self.sigDict)
318            cellSig = G2stIO.getCellEsd(pfx,
319                                       phasedict['General']['SGData'],A,
320                                       self.OverallParms['Covariance'])  # returns 7 vals, includes sigVol
321            cellList = G2lat.A2cell(A) + (G2lat.calc_V(A),)
322            defsigL = 3*[-0.00001] + 3*[-0.001] + [-0.01] # significance to use when no sigma
323            names = ['length_a','length_b','length_c',
324                     'angle_alpha','angle_beta ','angle_gamma',
325                     'volume']
326            prevsig = 0
327            for lbl,defsig,val,sig in zip(names,defsigL,cellList,cellSig):
328                if sig:
329                    txt = G2mth.ValEsd(val,sig)
330                    prevsig = -sig # use this as the significance for next value
331                else:
332                    txt = G2mth.ValEsd(val,min(defsig,prevsig),True)
333                WriteCIFitem('_cell_'+lbl,txt)
334                   
335            WriteCIFitem('_symmetry_cell_setting',
336                         phasedict['General']['SGData']['SGSys'])
337
338            spacegroup = phasedict['General']['SGData']['SpGrp'].strip()
339            # regularize capitalization and remove trailing H/R
340            spacegroup = spacegroup[0].upper() + spacegroup[1:].lower().rstrip('rh ')
341            WriteCIFitem('_symmetry_space_group_name_H-M',spacegroup)
342
343            # generate symmetry operations including centering and center of symmetry
344            WriteCIFitem('loop_ _symmetry_equiv_pos_site_id _symmetry_equiv_pos_as_xyz')
345            for i,op in enumerate(G2spg.AllOps(phasedict['General']['SGData']),start=1):
346                WriteCIFitem('   {:3d}  {:}'.format(i,op.lower()))
347
348            # preferred orientation (always reported by phase)
349            SH = FormatSH(phasedict)
350            MD = FormatHAPpo(phasedict)
351            if SH and MD:
352                WriteCIFitem('_pd_proc_ls_pref_orient_corr', SH + '\n' + MD)
353            elif SH or MD:
354                WriteCIFitem('_pd_proc_ls_pref_orient_corr', SH + MD)
355            else:
356                WriteCIFitem('_pd_proc_ls_pref_orient_corr', 'none')
357
358            # loop over histogram(s) used in this phase
359            if oneblock:
360                # report all profile information here (include histogram & phase)
361                # _pd_proc_ls_profile_function
362                pass
363            else:
364                # pointers to histograms used in this phase
365                histlist = []
366                for hist in self.Phases[phasenam]['Histograms']:
367                    if self.Phases[phasenam]['Histograms'][hist]['Use']:
368                        if phasebyhistDict.get(hist):
369                            phasebyhistDict[hist].append(phasenam)
370                        else:
371                            phasebyhistDict[hist] = [phasenam,]
372                        blockid = datablockidDict.get(hist)
373                        if not blockid:
374                            print "Internal error: no block for data. Phase "+str(
375                                phasenam)+" histogram "+str(hist)
376                            histlist = []
377                            break
378                        histlist.append(blockid)
379
380                if len(histlist) == 0:
381                    WriteCIFitem('# Note: phase has no associated data')
382                else:
383                    WriteCIFitem('loop_  _pd_block_diffractogram_id')
384
385                # report sample profile information here (phase only)
386                # _pd_proc_ls_profile_function
387           
388            if phasedict['General']['Type'] == 'nuclear':        #this needs macromolecular variant, etc!
389                WriteAtomsNuclear(phasenam)
390            else:
391                raise Exception,"no export for mm coordinates implemented"
392     
393
394            raise Exception,'Testing'
395
396            WriteCIFitem('loop_' + '\n\t_atom_site_aniso_label' + 
397                         '\n\t_atom_site_aniso_U_11' + '\n\t_atom_site_aniso_U_12' +
398                         '\n\t_atom_site_aniso_U_13' + '\n\t_atom_site_aniso_U_22' +
399                         '\n\t_atom_site_aniso_U_23' + '\n\t_atom_site_aniso_U_33')
400
401            # process the chemical formula: pick a Z value & generate molecular weight
402            # find the maximum possible Z value
403
404            # order the elements in "Hill" order: C, H, D, T & alphabetical or alphabetical
405            if not oneblock: # in single block, this is combined with the scattering factors
406                WriteCIFitem('loop_  _atom_type_symbol _atom_type_number_in_cell')
407
408            WriteCIFitem('# If you change Z, be sure to change all 3 of the following')
409            WriteCIFitem( '_chemical_formula_sum',text)
410            #WRITE(TEXT,'(F15.2)') ATMASS
411            WriteCIFitem( '_chemical_formula_weight',text)
412            #WRITE(TEXT,'(I4)') Z
413            WriteCIFitem( '_cell_formula_units_Z',text)
414
415            #C now loop over interatomic distances for this phase
416            WriteCIFitem('\n# MOLECULAR GEOMETRY')
417            WriteCIFitem('loop_' + 
418                         '\n\t_geom_bond_atom_site_label_1' +
419                         '\n\t_geom_bond_atom_site_label_2' + 
420                         '\n\t_geom_bond_distance' + 
421                         '\n\t_geom_bond_site_symmetry_1' + 
422                         '\n\t_geom_bond_site_symmetry_2' + 
423                         '\n\t_geom_bond_publ_flag')
424
425            #C now loop over interatomic angles for this phase
426            WriteCIFitem('loop_' + 
427                         '\n\t_geom_angle_atom_site_label_1' + 
428                         '\n\t_geom_angle_atom_site_label_2' + 
429                         '\n\t_geom_angle_atom_site_label_3' + 
430                         '\n\t_geom_angle' + 
431                         '\n\t_geom_angle_site_symmetry_1' +
432                         '\n\t_geom_angle_site_symmetry_2' + 
433                         '\n\t_geom_angle_site_symmetry_3' + 
434                         '\n\t_geom_angle_publ_flag')
435
436        def WritePowderData(histlbl):
437            text = '?'
438            histblk = self.Histograms[histlbl]
439            print 'TODO: powder here data for',histblk["Sample Parameters"]['InstrName']
440            # see wrpowdhist.for & wrreflist.for
441           
442            refprx = '_refln.' # mm
443            refprx = '_refln_' # normal
444
445            if not oneblock:
446                if not phasebyhistDict.get(histlbl):
447                    WriteCIFitem('\n# No phases associated with this data set')
448                else:
449                    WriteCIFitem('\n# PHASE TABLE')
450                    WriteCIFitem('loop_' +
451                                 '\n\t_pd_phase_id' + 
452                                 '\n\t_pd_phase_block_id' + 
453                                 '\n\t_pd_phase_mass_%')
454                    for phasenam in phasebyhistDict.get(histlbl):
455                        pass
456
457            WriteCIFitem('\n# SCATTERING FACTOR INFO')
458            WriteCIFitem('_diffrn_radiation_wavelength' ,text)
459            #WriteCIFitem('_diffrn_radiation_type',text)
460            #C always assume Ka1 & Ka2 if two wavelengths are present
461            #WriteCIFitem('loop_' +
462            #             '\n\t_diffrn_radiation_wavelength' +
463            #             '\n\t_diffrn_radiation_wavelength_wt' +
464            #             '\n\t_diffrn_radiation_type' +
465            #             '\n\t_diffrn_radiation_wavelength_id')
466            #WRITE LAM1,1.0,'K\\a~1~',1, LAM2,ratio,'K\\a~2~',2
467
468            WriteCIFitem('_pd_proc_ls_prof_R_factor','?')
469            WriteCIFitem('_pd_proc_ls_prof_wR_factor','?')
470            WriteCIFitem('_pd_proc_ls_prof_wR_expected','?')
471            WriteCIFitem('_refine_ls_R_Fsqd_factor','?')
472           
473            #WriteCIFitem('_pd_meas_2theta_fixed',text)
474            WriteCIFitem('_diffrn_radiation_probe','x-ray')
475            WriteCIFitem('_diffrn_radiation_probe','neutron')
476            WriteCIFitem('_diffrn_radiation_polarisn_ratio','?')
477           
478            WriteCIFitem('loop_  _atom_type_symbol')
479            if oneblock:
480                WriteCIFitem('       _atom_type_number_in_cell')
481            #IF (HTYP(2:2) .eq. 'X' .AND. HTYP(3:3) .ne. 'E') THEN
482            WriteCIFitem('      _atom_type_scat_dispersion_real')
483            WriteCIFitem('      _atom_type_scat_dispersion_imag')
484            for lbl in ('a1','a2','a3', 'a4', 'b1', 'b2', 'b3', 'b4', 'c'):
485                WriteCIFitem('      _atom_type_scat_Cromer_Mann_'+lbl)
486            #ELSEIF (HTYP(2:2) .eq. 'N') THEN
487            WriteCIFitem('      _atom_type_scat_length_neutron')
488            #ENDIF
489            WriteCIFitem('      _atom_type_scat_source')
490
491            #C document the background function used
492            WriteCIFitem('_pd_proc_ls_background_function','?')
493
494            WriteCIFitem('_exptl_absorpt_process_details','?')
495            WriteCIFitem('_exptl_absorpt_correction_T_min','?')
496            WriteCIFitem('_exptl_absorpt_correction_T_max','?')
497            #C extinction
498            #WRITE(IUCIF,'(A)') '# Extinction correction'
499            #CALL WRVAL(IUCIF,'_gsas_exptl_extinct_corr_T_min',TEXT(1:10))
500            #CALL WRVAL(IUCIF,'_gsas_exptl_extinct_corr_T_max',TEXT(11:20))
501
502            if not oneblock:
503                # instrumental profile terms go here
504                WriteCIFitem('_pd_proc_ls_profile_function','?')
505
506            WriteCIFitem('\n# STRUCTURE FACTOR TABLE')           
507            WriteCIFitem('loop_' + 
508                         '\n\t' + refprx + 'index_h' + 
509                         '\n\t' + refprx + 'index_k' + 
510                         '\n\t' + refprx + 'index_l' + 
511                         '\n\t_pd_refln_wavelength_id' +
512                         '\n\t_pd_refln_phase_id' + 
513                         '\n\t' + refprx + 'status' + 
514                         '\n\t' + refprx + 'F_squared_meas' + 
515                         '\n\t' + refprx + 'F_squared_sigma' + 
516                         '\n\t' + refprx + 'F_squared_calc' + 
517                         '\n\t' + refprx + 'phase_calc' + 
518                         '\n\t_pd_refln_d_spacing' + 
519                         '\n\t_gsas_i100_meas')
520
521            WriteCIFitem('_reflns_number_total', text)
522            WriteCIFitem('_reflns_limit_h_min', text)
523            WriteCIFitem('_reflns_limit_h_max', text)
524            WriteCIFitem('_reflns_limit_k_min', text)
525            WriteCIFitem('_reflns_limit_k_max', text)
526            WriteCIFitem('_reflns_limit_l_min', text)
527            WriteCIFitem('_reflns_limit_l_max', text)
528            WriteCIFitem('_reflns_d_resolution_high', text)
529            WriteCIFitem('_reflns_d_resolution_low', text)
530           
531            WriteCIFitem('\n# POWDER DATA TABLE')
532            # is data fixed step?
533            fixedstep = False
534            # are ESDs sqrt(I)
535            countsdata = False
536            zero = 0.01
537            if fixedstep:
538                WriteCIFitem('_pd_meas_2theta_range_min', text)
539                WriteCIFitem('_pd_meas_2theta_range_max', text)
540                WriteCIFitem('_pd_meas_2theta_range_inc', text)
541                # zero correct
542                if zero != 0.0:
543                    WriteCIFitem('_pd_proc_2theta_range_min', text)
544                    WriteCIFitem('_pd_proc_2theta_range_max', text)
545                    WriteCIFitem('_pd_proc_2theta_range_inc', text)
546            WriteCIFitem('loop_' +
547                         '\n\t_pd_proc_d_spacing')
548                         #'_pd_meas_time_of_flight'
549            if not fixedstep:
550                if zero != 0.0:
551                    WriteCIFitem('\t_pd_proc_2theta_corrected')
552                else:
553                    WriteCIFitem('\t_pd_meas_2theta_scan')
554            if countsdata:
555                WriteCIFitem('\t_pd_meas_counts_total')
556            else:
557                WriteCIFitem('\t_pd_meas_intensity_total')
558            WriteCIFitem('\t_pd_proc_ls_weight')
559            WriteCIFitem('\t_pd_proc_intensity_bkg_calc')
560            WriteCIFitem('\t_pd_calc_intensity_total')
561            if zero != 0.0:
562                WriteCIFitem('_pd_proc_number_of_points', text)
563            else:
564                WriteCIFitem('_pd_meas_number_of_points', text)
565                         
566        def WriteSingleXtalData(histlbl):
567            histblk = self.Histograms[histlbl]
568            print 'TODO: single xtal here data for',histblk["Instrument Parameters"][0]['InstrName']
569            # see wrreflist.for
570            refprx = '_refln.' # mm
571            refprx = '_refln_' # normal
572           
573            WriteCIFitem('\n# STRUCTURE FACTOR TABLE')           
574            WriteCIFitem('loop_' + 
575                         '\n\t' + refprx + 'index_h' + 
576                         '\n\t' + refprx + 'index_k' + 
577                         '\n\t' + refprx + 'index_l' + 
578                         '\n\t' + refprx + 'status' + 
579                         '\n\t' + refprx + 'F_squared_meas' + 
580                         '\n\t' + refprx + 'F_squared_sigma' + 
581                         '\n\t' + refprx + 'F_squared_calc' + 
582                         '\n\t' + refprx + 'phase_calc')
583            WriteCIFitem('_reflns_number_total', text)
584            WriteCIFitem('_reflns_number_observed', text)
585            WriteCIFitem('_reflns_limit_h_min', text)
586            WriteCIFitem('_reflns_limit_h_max', text)
587            WriteCIFitem('_reflns_limit_k_min', text)
588            WriteCIFitem('_reflns_limit_k_max', text)
589            WriteCIFitem('_reflns_limit_l_min', text)
590            WriteCIFitem('_reflns_limit_l_max', text)
591            WriteCIFitem('_reflns_d_resolution_high', text)
592            WriteCIFitem('_reflns_d_resolution_low', text)
593
594        #============================================================
595        # the export process starts here
596        # create a dict with refined values and their uncertainties
597        self.loadParmDict()
598        # also load all of the tree into a set of dicts
599        self.loadTree()
600        #self.dumpTree()
601
602        # get restraint info
603        #restraintDict = self.OverallParms.get('Restraints',{})
604        #for i in  self.OverallParms['Constraints']:
605        #    print i
606        #    for j in self.OverallParms['Constraints'][i]:
607        #        print j
608        #return
609
610        self.CIFdate = dt.datetime.strftime(dt.datetime.now(),"%Y-%m-%dT%H:%M")
611        # count phases, powder and single crystal histograms
612        self.nphase = len(self.Phases)
613        self.npowder = 0
614        self.nsingle = 0
615        for hist in self.Histograms:
616            if hist.startswith("PWDR"): 
617                self.npowder += 1
618            elif hist.startswith("HKLF"): 
619                self.nsingle += 1
620        # is there anything to export?
621        if self.nphase + self.npowder + self.nsingle == 0: 
622            self.G2frame.ErrorDialog(
623                'Empty project',
624                'No data or phases to include in CIF')
625            return
626        # is there a file name defined?
627        self.CIFname = os.path.splitext(
628            os.path.split(self.G2frame.GSASprojectfile)[1]
629            )[0]
630        self.CIFname = self.CIFname.replace(' ','')
631        if not self.CIFname:
632            self.G2frame.ErrorDialog(
633                'No GPX name',
634                'Please save the project to provide a name')
635            return
636        # test for quick CIF mode or no data
637        self.quickmode = False
638        phasenam = phasenum = None # include all phases
639        if mode != "full" or self.npowder + self.nsingle == 0:
640            self.quickmode = True
641            oneblock = True
642            if self.nphase == 0:
643                self.G2frame.ErrorDialog(
644                    'No phase present',
645                    'Cannot create a coordinates CIF with no phases')
646                return
647            elif self.nphase > 1: # quick mode: choose one phase
648                choices = sorted(self.Phases.keys())
649                phasenum = G2gd.ItemSelector(choices,self.G2frame)
650                if phasenum is None: return
651                phasenam = choices[phasenum]
652        # will this require a multiblock CIF?
653        elif self.nphase > 1:
654            oneblock = False
655        elif self.npowder + self.nsingle > 1:
656            oneblock = False
657        else: # one phase, one dataset, Full CIF
658            oneblock = True
659
660        # make sure needed infomation is present
661        # get CIF author name -- required for full CIFs
662        try:
663            self.author = self.OverallParms['Controls'].get("Author",'').strip()
664        except KeyError:
665            pass
666        while not (self.author or self.quickmode):
667            dlg = G2gd.SingleStringDialog(self.G2frame,'Get CIF Author','Provide CIF Author name (Last, First)')
668            if not dlg.Show(): return # cancel was pressed
669            self.author = dlg.GetValue()
670            dlg.Destroy()
671        try:
672            self.OverallParms['Controls']["Author"] = self.author # save for future
673        except KeyError:
674            pass
675        self.shortauthorname = self.author.replace(',','').replace(' ','')[:20]
676
677        # check the instrument name for every histogram
678        if not self.quickmode:
679            dictlist = []
680            keylist = []
681            lbllist = []
682            invalid = 0
683            key3 = 'InstrName'
684            for hist in self.Histograms:
685                if hist.startswith("PWDR"): 
686                    key2 = "Sample Parameters"
687                    d = self.Histograms[hist][key2]
688                elif hist.startswith("HKLF"): 
689                    key2 = "Instrument Parameters"
690                    d = self.Histograms[hist][key2][0]
691                   
692                lbllist.append(hist)
693                dictlist.append(d)
694                keylist.append(key3)
695                instrname = d.get(key3)
696                if instrname is None:
697                    d[key3] = ''
698                    invalid += 1
699                elif instrname.strip() == '':
700                    invalid += 1
701            if invalid:
702                msg = ""
703                if invalid > 3: msg = (
704                    "\n\nNote: it may be faster to set the name for\n"
705                    "one histogram for each instrument and use the\n"
706                    "File/Copy option to duplicate the name"
707                    )
708                if not G2gd.CallScrolledMultiEditor(
709                    self.G2frame,dictlist,keylist,
710                    prelbl=range(1,len(dictlist)+1),
711                    postlbl=lbllist,
712                    title='Instrument names',
713                    header="Edit instrument names. Note that a non-blank\nname is required for all histograms"+msg,
714                    ): return
715
716        #======================================================================
717        # Start writing the CIF - single block
718        #======================================================================
719        if oneblock:
720            WriteCIFitem('data_'+self.CIFname)
721            if phasenam is None: # if not already selected, select the first phase (should be one)
722                phasenam = self.Phases.keys()[0]
723            #print 'phasenam',phasenam
724            phaseblk = self.Phases[phasenam] # pointer to current phase info
725            if not self.quickmode:
726                # select data, should only be one set in oneblock, but take whatever comes 1st
727                for hist in self.Histograms:
728                    histblk = self.Histograms[hist]
729                    if hist.startswith("PWDR"): 
730                        instnam = histblk["Sample Parameters"]['InstrName']
731                        break # ignore all but 1st data histogram
732                    elif hist.startswith("HKLF"): 
733                        instnam = histblk["Instrument Parameters"][0]['InstrName']
734                        break # ignore all but 1st data histogram
735                instnam = instnam.replace(' ','')
736                WriteCIFitem('_pd_block_id',
737                             str(self.CIFdate) + "|" + str(self.CIFname) + "|" +
738                             str(self.shortauthorname) + "|" + instnam)
739                WriteAudit()
740                WritePubTemplate()
741                WriteOverall()
742            # report the phase info
743            WritePhaseTemplate()
744            WritePhaseInfo(phasenam)
745            if not self.quickmode:
746                if hist.startswith("PWDR"):
747                    WritePowderTemplate()
748                    WritePowderData(hist)
749                elif hist.startswith("HKLF"):
750                    WriteSnglXtalTemplate()
751                    WriteSingleXtalData(hist)
752        else:
753        #======================================================================
754        # Start writing the CIF - multiblock
755        #======================================================================
756            # publication info
757            WriteCIFitem('\ndata_'+self.CIFname+'_publ')
758            WriteAudit()
759            WriteCIFitem('_pd_block_id',
760                         str(self.CIFdate) + "|" + str(self.CIFname) + "|" +
761                         str(self.shortauthorname) + "|Overall")
762            WritePubTemplate()
763            # overall info
764            WriteCIFitem('data_'+str(self.CIFname)+'_overall')
765            WriteOverall()
766            #============================================================
767            WriteCIFitem('# POINTERS TO PHASE AND HISTOGRAM BLOCKS')
768            datablockidDict = {} # save block names here -- N.B. check for conflicts between phase & hist names (unlikely!)
769            # loop over phase blocks
770            if self.nphase > 1:
771                loopprefix = ''
772                WriteCIFitem('loop_   _pd_phase_block_id')
773            else:
774                loopprefix = '_pd_phase_block_id'
775           
776            for phasenam in sorted(self.Phases.keys()):
777                i = self.Phases[phasenam]['pId']
778                datablockidDict[phasenam] = (str(self.CIFdate) + "|" + str(self.CIFname) + "|" +
779                             'phase_'+ str(i) + '|' + str(self.shortauthorname))
780                WriteCIFitem(loopprefix,datablockidDict[phasenam])
781            # loop over data blocks
782            if self.npowder + self.nsingle > 1:
783                loopprefix = ''
784                WriteCIFitem('loop_   _pd_block_diffractogram_id')
785            else:
786                loopprefix = '_pd_block_diffractogram_id'
787            for hist in self.Histograms:
788                histblk = self.Histograms[hist]
789                if hist.startswith("PWDR"): 
790                    instnam = histblk["Sample Parameters"]['InstrName']
791                elif hist.startswith("HKLF"): 
792                    instnam = histblk["Instrument Parameters"][0]['InstrName']
793                instnam = instnam.replace(' ','')
794                i = histblk['hId']
795                datablockidDict[hist] = (str(self.CIFdate) + "|" + str(self.CIFname) + "|" +
796                                         str(self.shortauthorname) + "|" +
797                                         instnam + "_hist_"+str(i))
798                WriteCIFitem(loopprefix,datablockidDict[hist])
799            #============================================================
800            # loop over phases, exporting them
801            phasebyhistDict = {} # create a cross-reference to phases by histogram
802            for j,phasenam in enumerate(sorted(self.Phases.keys())):
803                i = self.Phases[phasenam]['pId']
804                WriteCIFitem('\ndata_'+self.CIFname+"_phase_"+str(i))
805                print "debug, processing ",phasenam
806                WriteCIFitem('# Information for phase '+str(i))
807                WriteCIFitem('_pd_block_id',datablockidDict[phasenam])
808                # report the phase
809                WritePhaseTemplate()
810                WritePhaseInfo(phasenam)
811
812            #============================================================
813            # loop over histograms, exporting them
814            for hist in self.Histograms:
815                histblk = self.Histograms[hist]
816                i = histblk['hId']
817                if hist.startswith("PWDR"): 
818                    WriteCIFitem('\ndata_'+self.CIFname+"_pwd_"+str(i))
819                    #instnam = histblk["Sample Parameters"]['InstrName']
820                    WriteCIFitem('# Information for histogram '+str(i)+': '+
821                                 hist)
822                    WriteCIFitem('_pd_block_id',datablockidDict[hist])
823                    WritePowderTemplate()
824                    WritePowderData(key1)
825                elif hist.startswith("HKLF"): 
826                    WriteCIFitem('\ndata_'+self.CIFname+"_sx_"+str(i))
827                    #instnam = histblk["Instrument Parameters"][0]['InstrName']
828                    WriteCIFitem('# Information for histogram '+str(i)+': '+
829                                 hist)
830                    WriteCIFitem('_pd_block_id',datablockidDict[hist])
831                    WriteSnglXtalTemplate()
832                    WriteSingleXtalData(key1)
833
834        # TODO: how to report _pd_proc_ls_peak_cutoff?
835        WriteCIFitem('#--' + 15*'eof--' + '#')
836
Note: See TracBrowser for help on using the repository browser.