- Timestamp:
- Oct 2, 2013 9:27:17 AM (12 years ago)
- Location:
- trunk
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
TabularUnified trunk/GSASIIIO.py ¶
r1057 r1074 1900 1900 self.numbanks = 1 1901 1901 self.instdict = {} # place items here that will be transferred to the instrument parameters 1902 ###################################################################### 1903 def ReadCIF(URLorFile): 1904 '''Open a CIF, which may be specified as a file name or as a URL using PyCifRW 1905 (from James Hester). 1906 The open routine gets confused with DOS names that begin with a letter and colon 1907 "C:\dir\" so this routine will try to open the passed name as a file and if that 1908 fails, try it as a URL 1909 1910 :param str URLorFile: string containing a URL or a file name. Code will try first 1911 to open it as a file and then as a URL. 1912 1913 :returns: a PyCifRW CIF object. 1914 ''' 1915 import CifFile as cif # PyCifRW from James Hester 1916 1917 # alternate approach: 1918 #import urllib 1919 #ciffile = 'file:'+urllib.pathname2url(filename) 1920 1921 try: 1922 fp = open(URLorFile,'r') 1923 cf = cif.ReadCif(fp) 1924 fp.close() 1925 return cf 1926 except IOError: 1927 return cif.ReadCif(URLorFile) 1902 1928 1903 1929 if __name__ == '__main__': -
TabularUnified trunk/exports/G2cif.py ¶
r1069 r1074 10 10 ########### SVN repository information ################### 11 11 '''Code to export a GSAS-II project as a CIF 12 The heavy lifting is done in method export 12 This builds on the data extraction done in method export in the base class 13 14 TODO: set bond pub flags? 15 TODO: progress bar 16 TODO: cleanup routine import 17 13 18 ''' 14 19 15 # TODO: set bond pub flags?16 20 17 21 import datetime as dt … … 48 52 CIFdic = None 49 53 50 def getCallerDocString(): # for development 51 "Return the calling function's doc string" 52 import inspect as ins 53 for item in ins.stack()[1][0].f_code.co_consts: 54 if type(item) is str: 55 return item 56 else: 57 return '?' 54 class ExportCIF(G2IO.ExportBaseclass): 55 '''Used to create a CIF of an entire project 56 ''' 57 def __init__(self,G2frame): 58 super(self.__class__,self).__init__( # fancy way to say <parentclass>.__init__ 59 G2frame=G2frame, 60 formatName = 'full CIF', 61 extension='.cif', 62 longFormatName = 'Export project as CIF' 63 ) 64 self.author = '' 65 66 def export(self,mode='full'): 67 '''Export a CIF 68 69 :param str mode: "full" (default) to create a complete CIF of project, 70 "simple" for a simple CIF with only coordinates 71 ''' 72 73 # ===== define functions for export method ======================================= 74 def openCIF(filnam): 75 'opens the output file' 76 if DEBUG: 77 self.fp = sys.stdout 78 else: 79 self.fp = open(filnam,'w') 80 81 def closeCIF(): 82 'close the output file' 83 if not DEBUG: 84 self.fp.close() 85 86 def WriteCIFitem(name,value=''): 87 '''Write CIF data items to the file. Formats values as needed. 88 Also used without a value for loops, comments, loop headers, etc. 89 ''' 90 if value: 91 if "\n" in value or len(value)> 70: 92 if name.strip(): self.fp.write(name+'\n') 93 self.fp.write('; '+value+'\n') 94 self.fp.write('; '+'\n') 95 elif " " in value: 96 if len(name)+len(value) > 65: 97 self.fp.write(name + '\n ' + '"' + str(value) + '"'+'\n') 98 else: 99 self.fp.write(name + ' ' + '"' + str(value) + '"'+'\n') 100 else: 101 if len(name)+len(value) > 65: 102 self.fp.write(name+'\n ' + value+'\n') 103 else: 104 self.fp.write(name+' ' + value+'\n') 105 else: 106 self.fp.write(name+'\n') 107 108 def WriteAudit(): 109 'Write the CIF audit values. Perhaps should be in a single element loop.' 110 WriteCIFitem('_audit_creation_method', 111 'created in GSAS-II') 112 WriteCIFitem('_audit_creation_date',self.CIFdate) 113 if self.author: 114 WriteCIFitem('_audit_author_name',self.author) 115 WriteCIFitem('_audit_update_record', 116 self.CIFdate+' Initial software-generated CIF') 117 118 def WriteOverall(): 119 '''Write out overall refinement information. 120 121 More could be done here, but this is a good start. 122 ''' 123 WriteCIFitem('_pd_proc_info_datetime', self.CIFdate) 124 WriteCIFitem('_pd_calc_method', 'Rietveld Refinement') 125 #WriteCIFitem('_refine_ls_shift/su_max',DAT1) 126 #WriteCIFitem('_refine_ls_shift/su_mean',DAT2) 127 #WriteCIFitem('_refine_diff_density_max',rhomax) #these need to be defined for each phase! 128 #WriteCIFitem('_refine_diff_density_min',rhomin) 129 WriteCIFitem('_computing_structure_refinement','GSAS-II (Toby & Von Dreele, J. Appl. Cryst. 46, 544-549, 2013)') 130 try: 131 vars = str(len(self.OverallParms['Covariance']['varyList'])) 132 except: 133 vars = '?' 134 WriteCIFitem('_refine_ls_number_parameters',vars) 135 try: 136 GOF = G2mth.ValEsd(self.OverallParms['Covariance']['Rvals']['GOF'],-0.009) 137 except: 138 GOF = '?' 139 WriteCIFitem('_refine_ls_goodness_of_fit_all',GOF) 140 141 # get restraint info 142 # restraintDict = self.OverallParms.get('Restraints',{}) 143 # for i in self.OverallParms['Constraints']: 144 # print i 145 # for j in self.OverallParms['Constraints'][i]: 146 # print j 147 #WriteCIFitem('_refine_ls_number_restraints',TEXT) 148 # other things to consider reporting 149 # _refine_ls_number_reflns 150 # _refine_ls_goodness_of_fit_obs 151 # _refine_ls_wR_factor_obs 152 # _refine_ls_restrained_S_all 153 # _refine_ls_restrained_S_obs 154 155 # include an overall profile r-factor, if there is more than one powder histogram 156 R = '%.5f'%(self.OverallParms['Covariance']['Rvals']['Rwp']/100.) 157 WriteCIFitem('\n# OVERALL WEIGHTED R-FACTOR') 158 WriteCIFitem('_refine_ls_wR_factor_obs',R) 159 # _refine_ls_R_factor_all 160 # _refine_ls_R_factor_obs 161 WriteCIFitem('_refine_ls_matrix_type','full') 162 #WriteCIFitem('_refine_ls_matrix_type','userblocks') 163 164 def writeCIFtemplate(G2dict,tmplate,defaultname=''): 165 '''Write out the selected or edited CIF template 166 An unedited CIF template file is copied, comments intact; an edited 167 CIF template is written out from PyCifRW which of course strips comments. 168 In all cases the initial data_ header is stripped (there should only be one!) 169 ''' 170 CIFobj = G2dict.get("CIF_template") 171 if defaultname: 172 defaultname = defaultname.encode('ascii','replace').strip().replace(' ','_') 173 defaultname = re.sub(r'[^a-zA-Z0-9_-]','',defaultname) 174 defaultname = tmplate + "_" + defaultname + ".cif" 175 else: 176 defaultname = '' 177 templateDefName = 'template_'+tmplate+'.cif' 178 if not CIFobj: # copying a template 179 for pth in [os.getcwd()]+sys.path: 180 fil = os.path.join(pth,defaultname) 181 if os.path.exists(fil) and defaultname: break 182 else: 183 for pth in sys.path: 184 fil = os.path.join(pth,templateDefName) 185 if os.path.exists(fil): break 186 else: 187 print(CIFobj+' not found in path!') 188 return 189 fp = open(fil,'r') 190 txt = fp.read() 191 fp.close() 192 elif type(CIFobj) is not list and type(CIFobj) is not tuple: 193 if not os.path.exists(CIFobj): 194 print("Error: requested template file has disappeared: "+CIFobj) 195 return 196 fp = open(CIFobj,'r') 197 txt = fp.read() 198 fp.close() 199 else: 200 txt = dict2CIF(CIFobj[0],CIFobj[1]).WriteOut() 201 # remove the PyCifRW header, if present 202 #if txt.find('PyCifRW') > -1 and txt.find('data_') > -1: 203 txt = "# GSAS-II edited template follows "+txt[txt.index("data_")+5:] 204 #txt = txt.replace('data_','#') 205 WriteCIFitem(txt) 206 207 def FormatSH(phasenam): 208 'Format a full spherical harmonics texture description as a string' 209 phasedict = self.Phases[phasenam] # pointer to current phase info 210 pfx = str(phasedict['pId'])+'::' 211 s = "" 212 textureData = phasedict['General']['SH Texture'] 213 if textureData.get('Order'): 214 s += "Spherical Harmonics correction. Order = "+str(textureData['Order']) 215 s += " Model: " + str(textureData['Model']) + "\n Orientation angles: " 216 for name in ['omega','chi','phi']: 217 aname = pfx+'SH '+name 218 s += name + " = " 219 sig = self.sigDict.get(aname,-0.09) 220 s += G2mth.ValEsd(self.parmDict[aname],sig) 221 s += "; " 222 s += "\n" 223 s1 = " Coefficients: " 224 for name in textureData['SH Coeff'][1]: 225 aname = pfx+name 226 if len(s1) > 60: 227 s += s1 + "\n" 228 s1 = " " 229 s1 += aname + ' = ' 230 sig = self.sigDict.get(aname,-0.0009) 231 s1 += G2mth.ValEsd(self.parmDict[aname],sig) 232 s1 += "; " 233 s += s1 234 return s 235 236 def FormatHAPpo(phasenam): 237 '''return the March-Dollase/SH correction for every 238 histogram in the current phase formatted into a 239 character string 240 ''' 241 phasedict = self.Phases[phasenam] # pointer to current phase info 242 s = '' 243 for histogram in sorted(phasedict['Histograms']): 244 if histogram.startswith("HKLF"): continue # powder only 245 Histogram = self.Histograms.get(histogram) 246 if not Histogram: continue 247 hapData = phasedict['Histograms'][histogram] 248 if hapData['Pref.Ori.'][0] == 'MD': 249 aname = str(phasedict['pId'])+':'+str(Histogram['hId'])+':MD' 250 if self.parmDict.get(aname,1.0) != 1.0: continue 251 sig = self.sigDict.get(aname,-0.009) 252 if s != "": s += '\n' 253 s += 'March-Dollase correction' 254 if len(self.powderDict) > 1: 255 s += ', histogram '+str(Histogram['hId']+1) 256 s += ' coef. = ' + G2mth.ValEsd(self.parmDict[aname],sig) 257 s += ' axis = ' + str(hapData['Pref.Ori.'][3]) 258 else: # must be SH 259 if s != "": s += '\n' 260 s += 'Simple spherical harmonic correction' 261 if len(self.powderDict) > 1: 262 s += ', histogram '+str(Histogram['hId']+1) 263 s += ' Order = '+str(hapData['Pref.Ori.'][4])+'\n' 264 s1 = " Coefficients: " 265 for item in hapData['Pref.Ori.'][5]: 266 aname = str(phasedict['pId'])+':'+str(Histogram['hId'])+':'+item 267 if len(s1) > 60: 268 s += s1 + "\n" 269 s1 = " " 270 s1 += aname + ' = ' 271 sig = self.sigDict.get(aname,-0.0009) 272 s1 += G2mth.ValEsd(self.parmDict[aname],sig) 273 s1 += "; " 274 s += s1 275 return s 276 def FormatBackground(bkg,hId): 277 '''Display the Background information as a descriptive text string. 278 279 TODO: this needs to be expanded to show the diffuse peak and 280 Debye term information as well. (Bob) 281 282 :returns: the text description (str) 283 ''' 284 hfx = ':'+str(hId)+':' 285 fxn, bkgdict = bkg 286 terms = fxn[2] 287 txt = 'Background function: "'+fxn[0]+'" function with '+str(terms)+' terms:\n' 288 l = " " 289 for i,v in enumerate(fxn[3:]): 290 name = '%sBack:%d'%(hfx,i) 291 sig = self.sigDict.get(name,-0.009) 292 if len(l) > 60: 293 txt += l + '\n' 294 l = ' ' 295 l += G2mth.ValEsd(v,sig)+', ' 296 txt += l 297 if bkgdict['nDebye']: 298 txt += '\n Background Debye function parameters: A, R, U:' 299 names = ['A:','R:','U:'] 300 for i in range(bkgdict['nDebye']): 301 txt += '\n ' 302 for j in range(3): 303 name = hfx+'Debye'+names[j]+str(i) 304 sig = self.sigDict.get(name,-0.009) 305 txt += G2mth.ValEsd(bkgdict['debyeTerms'][i][2*j],sig)+', ' 306 if bkgdict['nPeaks']: 307 txt += '\n Background peak parameters: pos, int, sig, gam:' 308 names = ['pos:','int:','sig:','gam:'] 309 for i in range(bkgdict['nPeaks']): 310 txt += '\n ' 311 for j in range(4): 312 name = hfx+'BkPk'+names[j]+str(i) 313 sig = self.sigDict.get(name,-0.009) 314 txt += G2mth.ValEsd(bkgdict['peaksList'][i][2*j],sig)+', ' 315 return txt 316 317 def FormatInstProfile(instparmdict,hId): 318 '''Format the instrumental profile parameters with a 319 string description. Will only be called on PWDR histograms 320 ''' 321 s = '' 322 inst = instparmdict[0] 323 hfx = ':'+str(hId)+':' 324 if 'C' in inst['Type'][0]: 325 s = 'Finger-Cox-Jephcoat function parameters U, V, W, X, Y, SH/L:\n' 326 s += ' peak variance(Gauss) = Utan(Th)^2^+Vtan(Th)+W:\n' 327 s += ' peak HW(Lorentz) = X/cos(Th)+Ytan(Th); SH/L = S/L+H/L\n' 328 s += ' U, V, W in (centideg)^2^, X & Y in centideg\n ' 329 for item in ['U','V','W','X','Y','SH/L']: 330 name = hfx+item 331 sig = self.sigDict.get(name,-0.009) 332 s += G2mth.ValEsd(inst[item][1],sig)+', ' 333 elif 'T' in inst['Type'][0]: #to be tested after TOF Rietveld done 334 s = 'Von Dreele-Jorgenson-Windsor function parameters\n'+ \ 335 ' alpha, beta-0, beta-1, beta-q, sig-0, sig-1, sig-q, X, Y:\n ' 336 for item in ['alpha','bet-0','bet-1','bet-q','sig-0','sig-1','sig-q','X','Y']: 337 name = hfx+item 338 sig = self.sigDict.get(name,-0.009) 339 s += G2mth.ValEsd(inst[item][1],sig)+', ' 340 return s 341 342 def FormatPhaseProfile(phasenam): 343 '''Format the phase-related profile parameters (size/strain) 344 with a string description. 345 return an empty string or None if there are no 346 powder histograms for this phase. 347 ''' 348 s = '' 349 phasedict = self.Phases[phasenam] # pointer to current phase info 350 SGData = phasedict['General'] ['SGData'] 351 for histogram in sorted(phasedict['Histograms']): 352 if histogram.startswith("HKLF"): continue # powder only 353 Histogram = self.Histograms.get(histogram) 354 if not Histogram: continue 355 hapData = phasedict['Histograms'][histogram] 356 pId = phasedict['pId'] 357 hId = Histogram['hId'] 358 phfx = '%d:%d:'%(pId,hId) 359 size = hapData['Size'] 360 mustrain = hapData['Mustrain'] 361 hstrain = hapData['HStrain'] 362 s = ' Crystallite size model "%s" for %s (microns)\n '%(size[0],phasenam) 363 names = ['Size;i','Size;mx'] 364 if 'uniax' in size[0]: 365 names = ['Size;i','Size;a','Size;mx'] 366 s += 'anisotropic axis is %s\n '%(str(size[3])) 367 s += 'parameters: equatorial size, axial size, G/L mix\n ' 368 for i,item in enumerate(names): 369 name = phfx+item 370 sig = self.sigDict.get(name,-0.009) 371 s += G2mth.ValEsd(size[1][i],sig)+', ' 372 elif 'ellip' in size[0]: 373 s += 'parameters: S11, S22, S33, S12, S13, S23, G/L mix\n ' 374 for i in range(6): 375 name = phfx+'Size:'+str(i) 376 sig = self.sigDict.get(name,-0.009) 377 s += G2mth.ValEsd(size[4][i],sig)+', ' 378 sig = self.sigDict.get(phfx+'Size;mx',-0.009) 379 s += G2mth.ValEsd(size[1][2],sig)+', ' 380 else: #isotropic 381 s += 'parameters: Size, G/L mix\n ' 382 i = 0 383 for item in names: 384 name = phfx+item 385 sig = self.sigDict.get(name,-0.009) 386 s += G2mth.ValEsd(size[1][i],sig)+', ' 387 i = 2 #skip the aniso value 388 s += '\n Mustrain model "%s" for %s (10^6^)\n '%(mustrain[0],phasenam) 389 names = ['Mustrain;i','Mustrain;mx'] 390 if 'uniax' in mustrain[0]: 391 names = ['Mustrain;i','Mustrain;a','Mustrain;mx'] 392 s += 'anisotropic axis is %s\n '%(str(size[3])) 393 s += 'parameters: equatorial mustrain, axial mustrain, G/L mix\n ' 394 for i,item in enumerate(names): 395 name = phfx+item 396 sig = self.sigDict.get(name,-0.009) 397 s += G2mth.ValEsd(mustrain[1][i],sig)+', ' 398 elif 'general' in mustrain[0]: 399 names = 'parameters: ' 400 for i,name in enumerate(G2spc.MustrainNames(SGData)): 401 names += name+', ' 402 if i == 9: 403 names += '\n ' 404 names += 'G/L mix\n ' 405 s += names 406 txt = '' 407 for i in range(len(mustrain[4])): 408 name = phfx+'Mustrain:'+str(i) 409 sig = self.sigDict.get(name,-0.009) 410 if len(txt) > 60: 411 s += txt+'\n ' 412 txt = '' 413 txt += G2mth.ValEsd(mustrain[4][i],sig)+', ' 414 s += txt 415 sig = self.sigDict.get(phfx+'Mustrain;mx',-0.009) 416 s += G2mth.ValEsd(mustrain[1][2],sig)+', ' 417 418 else: #isotropic 419 s += ' parameters: Mustrain, G/L mix\n ' 420 i = 0 421 for item in names: 422 name = phfx+item 423 sig = self.sigDict.get(name,-0.009) 424 s += G2mth.ValEsd(mustrain[1][i],sig)+', ' 425 i = 2 #skip the aniso value 426 s += '\n Macrostrain for %s\n'%(phasenam) 427 txt = ' parameters: ' 428 names = G2spc.HStrainNames(SGData) 429 for name in names: 430 txt += name+', ' 431 s += txt+'\n ' 432 for i in range(len(names)): 433 name = phfx+name[i] 434 sig = self.sigDict.get(name,-0.009) 435 s += G2mth.ValEsd(hstrain[0][i],sig)+', ' 436 return s 437 438 def FmtAtomType(sym): 439 'Reformat a GSAS-II atom type symbol to match CIF rules' 440 sym = sym.replace('_','') # underscores are not allowed: no isotope designation? 441 # in CIF, oxidation state sign symbols come after, not before 442 if '+' in sym: 443 sym = sym.replace('+','') + '+' 444 elif '-' in sym: 445 sym = sym.replace('-','') + '-' 446 return sym 447 448 def PutInCol(val,wid): 449 '''Pad a value to >=wid+1 columns by adding spaces at the end. Always 450 adds at least one space 451 ''' 452 val = str(val).replace(' ','') 453 if not val: val = '?' 454 fmt = '{:' + str(wid) + '} ' 455 return fmt.format(val) 456 457 def MakeUniqueLabel(lbl,labellist): 458 'Make sure that every atom label is unique' 459 lbl = lbl.strip() 460 if not lbl: # deal with a blank label 461 lbl = 'A_1' 462 if lbl not in labellist: 463 labellist.append(lbl) 464 return lbl 465 i = 1 466 prefix = lbl 467 if '_' in lbl: 468 prefix = lbl[:lbl.rfind('_')] 469 suffix = lbl[lbl.rfind('_')+1:] 470 try: 471 i = int(suffix)+1 472 except: 473 pass 474 while prefix+'_'+str(i) in labellist: 475 i += 1 476 else: 477 lbl = prefix+'_'+str(i) 478 labellist.append(lbl) 479 480 def WriteAtomsNuclear(phasenam): 481 'Write atom positions to CIF' 482 phasedict = self.Phases[phasenam] # pointer to current phase info 483 General = phasedict['General'] 484 cx,ct,cs,cia = General['AtomPtrs'] 485 Atoms = phasedict['Atoms'] 486 cfrac = cx+3 487 fpfx = str(phasedict['pId'])+'::Afrac:' 488 for i,at in enumerate(Atoms): 489 fval = self.parmDict.get(fpfx+str(i),at[cfrac]) 490 if fval != 0.0: 491 break 492 else: 493 WriteCIFitem('\n# PHASE HAS NO ATOMS!') 494 return 495 496 WriteCIFitem('\n# ATOMIC COORDINATES AND DISPLACEMENT PARAMETERS') 497 WriteCIFitem('loop_ '+ 498 '\n\t_atom_site_label'+ 499 '\n\t_atom_site_type_symbol'+ 500 '\n\t_atom_site_fract_x'+ 501 '\n\t_atom_site_fract_y'+ 502 '\n\t_atom_site_fract_z'+ 503 '\n\t_atom_site_occupancy'+ 504 '\n\t_atom_site_adp_type'+ 505 '\n\t_atom_site_U_iso_or_equiv'+ 506 '\n\t_atom_site_symmetry_multiplicity') 507 508 varnames = {cx:'Ax',cx+1:'Ay',cx+2:'Az',cx+3:'Afrac', 509 cia+1:'AUiso',cia+2:'AU11',cia+3:'AU22',cia+4:'AU33', 510 cia+5:'AU12',cia+6:'AU13',cia+7:'AU23'} 511 self.labellist = [] 512 513 pfx = str(phasedict['pId'])+'::' 514 # loop over all atoms 515 naniso = 0 516 for i,at in enumerate(Atoms): 517 s = PutInCol(MakeUniqueLabel(at[ct-1],self.labellist),6) # label 518 fval = self.parmDict.get(fpfx+str(i),at[cfrac]) 519 if fval == 0.0: continue # ignore any atoms that have a occupancy set to 0 (exact) 520 s += PutInCol(FmtAtomType(at[ct]),4) # type 521 if at[cia] == 'I': 522 adp = 'Uiso ' 523 else: 524 adp = 'Uani ' 525 naniso += 1 526 # compute Uequiv crudely 527 # correct: Defined as "1/3 trace of diagonalized U matrix". 528 # SEE cell2GS & Uij2Ueqv to GSASIIlattice. Former is needed to make the GS matrix used by the latter. 529 t = 0.0 530 for j in (2,3,4): 531 var = pfx+varnames[cia+j]+":"+str(i) 532 t += self.parmDict.get(var,at[cia+j]) 533 for j in (cx,cx+1,cx+2,cx+3,cia,cia+1): 534 if j in (cx,cx+1,cx+2): 535 dig = 11 536 sigdig = -0.00009 537 else: 538 dig = 10 539 sigdig = -0.009 540 if j == cia: 541 s += adp 542 else: 543 var = pfx+varnames[j]+":"+str(i) 544 dvar = pfx+"d"+varnames[j]+":"+str(i) 545 if dvar not in self.sigDict: 546 dvar = var 547 if j == cia+1 and adp == 'Uani ': 548 val = t/3. 549 sig = sigdig 550 else: 551 #print var,(var in self.parmDict),(var in self.sigDict) 552 val = self.parmDict.get(var,at[j]) 553 sig = self.sigDict.get(dvar,sigdig) 554 s += PutInCol(G2mth.ValEsd(val,sig),dig) 555 s += PutInCol(at[cs+1],3) 556 WriteCIFitem(s) 557 if naniso == 0: return 558 # now loop over aniso atoms 559 WriteCIFitem('\nloop_' + '\n\t_atom_site_aniso_label' + 560 '\n\t_atom_site_aniso_U_11' + '\n\t_atom_site_aniso_U_12' + 561 '\n\t_atom_site_aniso_U_13' + '\n\t_atom_site_aniso_U_22' + 562 '\n\t_atom_site_aniso_U_23' + '\n\t_atom_site_aniso_U_33') 563 for i,at in enumerate(Atoms): 564 fval = self.parmDict.get(fpfx+str(i),at[cfrac]) 565 if fval == 0.0: continue # ignore any atoms that have a occupancy set to 0 (exact) 566 if at[cia] == 'I': continue 567 s = PutInCol(self.labellist[i],6) # label 568 for j in (2,3,4,5,6,7): 569 sigdig = -0.0009 570 var = pfx+varnames[cia+j]+":"+str(i) 571 val = self.parmDict.get(var,at[cia+j]) 572 sig = self.sigDict.get(var,sigdig) 573 s += PutInCol(G2mth.ValEsd(val,sig),11) 574 WriteCIFitem(s) 575 576 def HillSortElements(elmlist): 577 '''Sort elements in "Hill" order: C, H, others, (where others 578 are alphabetical). 579 580 :params list elmlist: a list of element strings 581 582 :returns: a sorted list of element strings 583 ''' 584 newlist = [] 585 oldlist = elmlist[:] 586 for elm in ('C','H'): 587 if elm in elmlist: 588 newlist.append(elm) 589 oldlist.pop(oldlist.index(elm)) 590 return newlist+sorted(oldlist) 591 592 def WriteComposition(phasenam): 593 '''determine the composition for the unit cell, crudely determine Z and 594 then compute the composition in formula units 595 ''' 596 phasedict = self.Phases[phasenam] # pointer to current phase info 597 General = phasedict['General'] 598 Z = General.get('cellZ',0.0) 599 cx,ct,cs,cia = General['AtomPtrs'] 600 Atoms = phasedict['Atoms'] 601 fpfx = str(phasedict['pId'])+'::Afrac:' 602 cfrac = cx+3 603 cmult = cs+1 604 compDict = {} # combines H,D & T 605 sitemultlist = [] 606 massDict = dict(zip(General['AtomTypes'],General['AtomMass'])) 607 cellmass = 0 608 for i,at in enumerate(Atoms): 609 atype = at[ct].strip() 610 if atype.find('-') != -1: atype = atype.split('-')[0] 611 if atype.find('+') != -1: atype = atype.split('+')[0] 612 atype = atype[0].upper()+atype[1:2].lower() # force case conversion 613 if atype == "D" or atype == "D": atype = "H" 614 fvar = fpfx+str(i) 615 fval = self.parmDict.get(fvar,at[cfrac]) 616 mult = at[cmult] 617 if not massDict.get(at[ct]): 618 print('Error: No mass found for atom type '+at[ct]) 619 print('Will not compute cell contents for phase '+phasenam) 620 return 621 cellmass += massDict[at[ct]]*mult*fval 622 compDict[atype] = compDict.get(atype,0.0) + mult*fval 623 if fval == 1: sitemultlist.append(mult) 624 if len(compDict.keys()) == 0: return # no elements! 625 if Z < 1: # Z has not been computed or set by user 626 Z = 1 627 for i in range(2,min(sitemultlist)+1): 628 for m in sitemultlist: 629 if m % i != 0: 630 break 631 else: 632 Z = i 633 General['cellZ'] = Z # save it 634 635 # when scattering factors are included in the CIF, this needs to be 636 # added to the loop here but only in the one-block case. 637 # For multiblock CIFs, scattering factors go in the histogram 638 # blocks (for all atoms in all appropriate phases) - an example?: 639 #loop_ 640 # _atom_type_symbol 641 # _atom_type_description 642 # _atom_type_scat_dispersion_real 643 # _atom_type_scat_dispersion_imag 644 # _atom_type_scat_source 645 # 'C' 'C' 0.0033 0.0016 646 # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' 647 # 'H' 'H' 0.0000 0.0000 648 # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' 649 # 'P' 'P' 0.1023 0.0942 650 # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' 651 # 'Cl' 'Cl' 0.1484 0.1585 652 # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' 653 # 'Cu' 'Cu' 0.3201 1.2651 654 # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' 655 656 #if oneblock: # add scattering factors for current phase here 657 WriteCIFitem('\nloop_ _atom_type_symbol _atom_type_number_in_cell') 658 formula = '' 659 reload(G2mth) 660 for elem in HillSortElements(compDict.keys()): 661 WriteCIFitem(' ' + PutInCol(elem,4) + 662 G2mth.ValEsd(compDict[elem],-0.009,True)) 663 if formula: formula += " " 664 formula += elem 665 if compDict[elem] == Z: continue 666 formula += G2mth.ValEsd(compDict[elem]/Z,-0.009,True) 667 WriteCIFitem( '\n# Note that Z affects _cell_formula_sum and _weight') 668 WriteCIFitem( '_cell_formula_units_Z',str(Z)) 669 WriteCIFitem( '_chemical_formula_sum',formula) 670 WriteCIFitem( '_chemical_formula_weight', 671 G2mth.ValEsd(cellmass/Z,-0.09,True)) 672 673 def WriteDistances(phasenam,SymOpList,offsetList,symOpList,G2oprList): 674 '''Report bond distances and angles for the CIF 675 676 Note that _geom_*_symmetry_* fields are values of form 677 n_klm where n is the symmetry operation in SymOpList (counted 678 starting with 1) and (k-5, l-5, m-5) are translations to add 679 to (x,y,z). See 680 http://www.iucr.org/__data/iucr/cifdic_html/1/cif_core.dic/Igeom_angle_site_symmetry_.html 681 682 TODO: need a method to select publication flags for distances/angles 683 ''' 684 phasedict = self.Phases[phasenam] # pointer to current phase info 685 Atoms = phasedict['Atoms'] 686 generalData = phasedict['General'] 687 cx,ct,cs,cia = phasedict['General']['AtomPtrs'] 688 cn = ct-1 689 fpfx = str(phasedict['pId'])+'::Afrac:' 690 cfrac = cx+3 691 DisAglData = {} 692 DisAglCtls = {} 693 # create a list of atoms, but skip atoms with zero occupancy 694 xyz = [] 695 fpfx = str(phasedict['pId'])+'::Afrac:' 696 for i,atom in enumerate(Atoms): 697 if self.parmDict.get(fpfx+str(i),atom[cfrac]) == 0.0: continue 698 xyz.append([i,]+atom[cn:cn+2]+atom[cx:cx+3]) 699 if 'DisAglCtls' in generalData: 700 DisAglCtls = generalData['DisAglCtls'] 701 else: # should not happen, since DisAglDialog should be called for all 702 # phases before getting here 703 dlg = G2gd.DisAglDialog(self.G2frame,DisAglCtls,generalData) 704 if dlg.ShowModal() == wx.ID_OK: 705 DisAglCtls = dlg.GetData() 706 generalData['DisAglCtls'] = DisAglCtls 707 else: 708 dlg.Destroy() 709 return 710 dlg.Destroy() 711 DisAglData['OrigAtoms'] = xyz 712 DisAglData['TargAtoms'] = xyz 713 SymOpList,offsetList,symOpList,G2oprList = G2spc.AllOps( 714 generalData['SGData']) 715 716 xpandSGdata = generalData['SGData'].copy() 717 xpandSGdata.update({'SGOps':symOpList, 718 'SGInv':False, 719 'SGLatt':'P', 720 'SGCen':np.array([[0, 0, 0]]),}) 721 DisAglData['SGData'] = xpandSGdata 722 723 DisAglData['Cell'] = generalData['Cell'][1:] #+ volume 724 if 'pId' in phasedict: 725 DisAglData['pId'] = phasedict['pId'] 726 DisAglData['covData'] = self.OverallParms['Covariance'] 727 try: 728 AtomLabels,DistArray,AngArray = G2stMn.RetDistAngle(DisAglCtls,DisAglData) 729 except KeyError: # inside DistAngle for missing atom types in DisAglCtls 730 print('**** ERROR - try again but do "Reset" to fill in missing atom types ****') 731 732 # loop over interatomic distances for this phase 733 WriteCIFitem('\n# MOLECULAR GEOMETRY') 734 WriteCIFitem('loop_' + 735 '\n\t_geom_bond_atom_site_label_1' + 736 '\n\t_geom_bond_atom_site_label_2' + 737 '\n\t_geom_bond_distance' + 738 '\n\t_geom_bond_site_symmetry_1' + 739 '\n\t_geom_bond_site_symmetry_2' + 740 '\n\t_geom_bond_publ_flag') 741 742 for i in sorted(AtomLabels.keys()): 743 Dist = DistArray[i] 744 for D in Dist: 745 line = ' '+PutInCol(AtomLabels[i],6)+PutInCol(AtomLabels[D[0]],6) 746 sig = D[4] 747 if sig == 0: sig = -0.00009 748 line += PutInCol(G2mth.ValEsd(D[3],sig,True),10) 749 line += " 1_555 " 750 line += " {:3d}_".format(D[2]) 751 for d in D[1]: 752 line += "{:1d}".format(d+5) 753 line += " yes" 754 WriteCIFitem(line) 755 756 # loop over interatomic angles for this phase 757 WriteCIFitem('\nloop_' + 758 '\n\t_geom_angle_atom_site_label_1' + 759 '\n\t_geom_angle_atom_site_label_2' + 760 '\n\t_geom_angle_atom_site_label_3' + 761 '\n\t_geom_angle' + 762 '\n\t_geom_angle_site_symmetry_1' + 763 '\n\t_geom_angle_site_symmetry_2' + 764 '\n\t_geom_angle_site_symmetry_3' + 765 '\n\t_geom_angle_publ_flag') 766 767 for i in sorted(AtomLabels.keys()): 768 Dist = DistArray[i] 769 for k,j,tup in AngArray[i]: 770 Dj = Dist[j] 771 Dk = Dist[k] 772 line = ' '+PutInCol(AtomLabels[Dj[0]],6)+PutInCol(AtomLabels[i],6)+PutInCol(AtomLabels[Dk[0]],6) 773 sig = tup[1] 774 if sig == 0: sig = -0.009 775 line += PutInCol(G2mth.ValEsd(tup[0],sig,True),10) 776 line += " {:3d}_".format(Dj[2]) 777 for d in Dj[1]: 778 line += "{:1d}".format(d+5) 779 line += " 1_555 " 780 line += " {:3d}_".format(Dk[2]) 781 for d in Dk[1]: 782 line += "{:1d}".format(d+5) 783 line += " yes" 784 WriteCIFitem(line) 785 786 def WritePhaseInfo(phasenam): 787 'Write out the phase information for the selected phase' 788 WriteCIFitem('\n# phase info for '+str(phasenam) + ' follows') 789 phasedict = self.Phases[phasenam] # pointer to current phase info 790 WriteCIFitem('_pd_phase_name', phasenam) 791 pfx = str(phasedict['pId'])+'::' 792 A,sigA = G2stIO.cellFill(pfx,phasedict['General']['SGData'],self.parmDict,self.sigDict) 793 cellSig = G2stIO.getCellEsd(pfx, 794 phasedict['General']['SGData'],A, 795 self.OverallParms['Covariance']) # returns 7 vals, includes sigVol 796 cellList = G2lat.A2cell(A) + (G2lat.calc_V(A),) 797 defsigL = 3*[-0.00001] + 3*[-0.001] + [-0.01] # significance to use when no sigma 798 names = ['length_a','length_b','length_c', 799 'angle_alpha','angle_beta ','angle_gamma', 800 'volume'] 801 prevsig = 0 802 for lbl,defsig,val,sig in zip(names,defsigL,cellList,cellSig): 803 if sig: 804 txt = G2mth.ValEsd(val,sig) 805 prevsig = -sig # use this as the significance for next value 806 else: 807 txt = G2mth.ValEsd(val,min(defsig,prevsig),True) 808 WriteCIFitem('_cell_'+lbl,txt) 809 810 WriteCIFitem('_symmetry_cell_setting', 811 phasedict['General']['SGData']['SGSys']) 812 813 spacegroup = phasedict['General']['SGData']['SpGrp'].strip() 814 # regularize capitalization and remove trailing H/R 815 spacegroup = spacegroup[0].upper() + spacegroup[1:].lower().rstrip('rh ') 816 WriteCIFitem('_symmetry_space_group_name_H-M',spacegroup) 817 818 # generate symmetry operations including centering and center of symmetry 819 SymOpList,offsetList,symOpList,G2oprList = G2spc.AllOps( 820 phasedict['General']['SGData']) 821 WriteCIFitem('loop_\n _space_group_symop_id\n _space_group_symop_operation_xyz') 822 for i,op in enumerate(SymOpList,start=1): 823 WriteCIFitem(' {:3d} {:}'.format(i,op.lower())) 824 825 # loop over histogram(s) used in this phase 826 if not oneblock and not self.quickmode: 827 # report pointers to the histograms used in this phase 828 histlist = [] 829 for hist in self.Phases[phasenam]['Histograms']: 830 if self.Phases[phasenam]['Histograms'][hist]['Use']: 831 if phasebyhistDict.get(hist): 832 phasebyhistDict[hist].append(phasenam) 833 else: 834 phasebyhistDict[hist] = [phasenam,] 835 blockid = datablockidDict.get(hist) 836 if not blockid: 837 print("Internal error: no block for data. Phase "+str( 838 phasenam)+" histogram "+str(hist)) 839 histlist = [] 840 break 841 histlist.append(blockid) 842 843 if len(histlist) == 0: 844 WriteCIFitem('# Note: phase has no associated data') 845 846 # report atom params 847 if phasedict['General']['Type'] == 'nuclear': #this needs macromolecular variant, etc! 848 WriteAtomsNuclear(phasenam) 849 else: 850 raise Exception,"no export for mm coordinates implemented" 851 # report cell contents 852 WriteComposition(phasenam) 853 if not self.quickmode: # report distances and angles 854 WriteDistances(phasenam,SymOpList,offsetList,symOpList,G2oprList) 855 856 def Yfmt(ndec,val): 857 'Format intensity values' 858 out = ("{:."+str(ndec)+"f}").format(val) 859 out = out.rstrip('0') # strip zeros to right of decimal 860 return out.rstrip('.') # and decimal place when not needed 861 862 def WriteReflStat(refcount,hklmin,hklmax,dmin,dmax,nRefSets=1): 863 'Write reflection statistics' 864 WriteCIFitem('_reflns_number_total', str(refcount)) 865 if hklmin is not None and nRefSets == 1: # hkl range has no meaning with multiple phases 866 WriteCIFitem('_reflns_limit_h_min', str(int(hklmin[0]))) 867 WriteCIFitem('_reflns_limit_h_max', str(int(hklmax[0]))) 868 WriteCIFitem('_reflns_limit_k_min', str(int(hklmin[1]))) 869 WriteCIFitem('_reflns_limit_k_max', str(int(hklmax[1]))) 870 WriteCIFitem('_reflns_limit_l_min', str(int(hklmin[2]))) 871 WriteCIFitem('_reflns_limit_l_max', str(int(hklmax[2]))) 872 if hklmin is not None: 873 WriteCIFitem('_reflns_d_resolution_low ', G2mth.ValEsd(dmax,-0.009)) 874 WriteCIFitem('_reflns_d_resolution_high ', G2mth.ValEsd(dmin,-0.009)) 875 876 def WritePowderData(histlbl): 877 'Write out the selected powder diffraction histogram info' 878 histblk = self.Histograms[histlbl] 879 inst = histblk['Instrument Parameters'][0] 880 hId = histblk['hId'] 881 pfx = ':' + str(hId) + ':' 882 883 if 'Lam1' in inst: 884 ratio = self.parmDict.get('I(L2)/I(L1)',inst['I(L2)/I(L1)'][1]) 885 sratio = self.sigDict.get('I(L2)/I(L1)',-0.0009) 886 lam1 = self.parmDict.get('Lam1',inst['Lam1'][1]) 887 slam1 = self.sigDict.get('Lam1',-0.00009) 888 lam2 = self.parmDict.get('Lam2',inst['Lam2'][1]) 889 slam2 = self.sigDict.get('Lam2',-0.00009) 890 # always assume Ka1 & Ka2 if two wavelengths are present 891 WriteCIFitem('_diffrn_radiation_type','K\\a~1,2~') 892 WriteCIFitem('loop_' + 893 '\n\t_diffrn_radiation_wavelength' + 894 '\n\t_diffrn_radiation_wavelength_wt' + 895 '\n\t_diffrn_radiation_wavelength_id') 896 WriteCIFitem(' ' + PutInCol(G2mth.ValEsd(lam1,slam1),15)+ 897 PutInCol('1.0',15) + 898 PutInCol('1',5)) 899 WriteCIFitem(' ' + PutInCol(G2mth.ValEsd(lam2,slam2),15)+ 900 PutInCol(G2mth.ValEsd(ratio,sratio),15)+ 901 PutInCol('2',5)) 902 else: 903 lam1 = self.parmDict.get('Lam',inst['Lam'][1]) 904 slam1 = self.sigDict.get('Lam',-0.00009) 905 WriteCIFitem('_diffrn_radiation_wavelength',G2mth.ValEsd(lam1,slam1)) 906 907 if not oneblock: 908 if not phasebyhistDict.get(histlbl): 909 WriteCIFitem('\n# No phases associated with this data set') 910 else: 911 WriteCIFitem('\n# PHASE TABLE') 912 WriteCIFitem('loop_' + 913 '\n\t_pd_phase_id' + 914 '\n\t_pd_phase_block_id' + 915 '\n\t_pd_phase_mass_%') 916 wtFrSum = 0. 917 for phasenam in phasebyhistDict.get(histlbl): 918 hapData = self.Phases[phasenam]['Histograms'][histlbl] 919 General = self.Phases[phasenam]['General'] 920 wtFrSum += hapData['Scale'][0]*General['Mass'] 921 922 for phasenam in phasebyhistDict.get(histlbl): 923 hapData = self.Phases[phasenam]['Histograms'][histlbl] 924 General = self.Phases[phasenam]['General'] 925 wtFr = hapData['Scale'][0]*General['Mass']/wtFrSum 926 pfx = str(self.Phases[phasenam]['pId'])+':'+str(hId)+':' 927 if pfx+'Scale' in self.sigDict: 928 sig = self.sigDict[pfx+'Scale']*wtFr/hapData['Scale'][0] 929 else: 930 sig = -0.0001 931 WriteCIFitem( 932 ' '+ 933 str(self.Phases[phasenam]['pId']) + 934 ' '+datablockidDict[phasenam]+ 935 ' '+G2mth.ValEsd(wtFr,sig) 936 ) 937 WriteCIFitem('loop_' + 938 '\n\t_gsas_proc_phase_R_F_factor' + 939 '\n\t_gsas_proc_phase_R_Fsqd_factor' + 940 '\n\t_gsas_proc_phase_id' + 941 '\n\t_gsas_proc_phase_block_id') 942 for phasenam in phasebyhistDict.get(histlbl): 943 pfx = str(self.Phases[phasenam]['pId'])+':'+str(hId)+':' 944 WriteCIFitem( 945 ' '+ 946 ' '+G2mth.ValEsd(histblk[pfx+'Rf']/100.,-.00009) + 947 ' '+G2mth.ValEsd(histblk[pfx+'Rf^2']/100.,-.00009)+ 948 ' '+str(self.Phases[phasenam]['pId'])+ 949 ' '+datablockidDict[phasenam] 950 ) 951 else: 952 # single phase in this histogram 953 pfx = '0:'+str(hId)+':' 954 WriteCIFitem('_refine_ls_R_F_factor ','%.5f'%(histblk[pfx+'Rf']/100.)) 955 WriteCIFitem('_refine_ls_R_Fsqd_factor ','%.5f'%(histblk[pfx+'Rf^2']/100.)) 956 957 WriteCIFitem('_pd_proc_ls_prof_R_factor ','%.5f'%(histblk['R']/100.)) 958 WriteCIFitem('_pd_proc_ls_prof_wR_factor ','%.5f'%(histblk['wR']/100.)) 959 WriteCIFitem('_gsas_proc_ls_prof_R_B_factor ','%.5f'%(histblk['Rb']/100.)) 960 WriteCIFitem('_gsas_proc_ls_prof_wR_B_factor','%.5f'%(histblk['wRb']/100.)) 961 WriteCIFitem('_pd_proc_ls_prof_wR_expected','%.5f'%(histblk['wRmin']/100.)) 962 963 if histblk['Instrument Parameters'][0]['Type'][1][1] == 'X': 964 WriteCIFitem('_diffrn_radiation_probe','x-ray') 965 pola = histblk['Instrument Parameters'][0].get('Polariz.') 966 if pola: 967 pfx = ':' + str(hId) + ':' 968 sig = self.sigDict.get(pfx+'Polariz.',-0.0009) 969 txt = G2mth.ValEsd(pola[1],sig) 970 WriteCIFitem('_diffrn_radiation_polarisn_ratio',txt) 971 elif histblk['Instrument Parameters'][0]['Type'][1][1] == 'N': 972 WriteCIFitem('_diffrn_radiation_probe','neutron') 973 # TOF (note that this may not be defined) 974 #if histblk['Instrument Parameters'][0]['Type'][1][2] == 'T': 975 # WriteCIFitem('_pd_meas_2theta_fixed',text) 976 977 978 # TODO: this will need help from Bob 979 #if not oneblock: 980 #WriteCIFitem('\n# SCATTERING FACTOR INFO') 981 #WriteCIFitem('loop_ _atom_type_symbol') 982 #if histblk['Instrument Parameters'][0]['Type'][1][1] == 'X': 983 # WriteCIFitem(' _atom_type_scat_dispersion_real') 984 # WriteCIFitem(' _atom_type_scat_dispersion_imag') 985 # for lbl in ('a1','a2','a3', 'a4', 'b1', 'b2', 'b3', 'b4', 'c'): 986 # WriteCIFitem(' _atom_type_scat_Cromer_Mann_'+lbl) 987 #elif histblk['Instrument Parameters'][0]['Type'][1][1] == 'N': 988 # WriteCIFitem(' _atom_type_scat_length_neutron') 989 #WriteCIFitem(' _atom_type_scat_source') 990 991 WriteCIFitem('_pd_proc_ls_background_function',FormatBackground(histblk['Background'],histblk['hId'])) 992 993 # TODO: this will need help from Bob 994 #WriteCIFitem('_exptl_absorpt_process_details','?') 995 #WriteCIFitem('_exptl_absorpt_correction_T_min','?') 996 #WriteCIFitem('_exptl_absorpt_correction_T_max','?') 997 #C extinction 998 #WRITE(IUCIF,'(A)') '# Extinction correction' 999 #CALL WRVAL(IUCIF,'_gsas_exptl_extinct_corr_T_min',TEXT(1:10)) 1000 #CALL WRVAL(IUCIF,'_gsas_exptl_extinct_corr_T_max',TEXT(11:20)) 1001 1002 if not oneblock: # instrumental profile terms go here 1003 WriteCIFitem('_pd_proc_ls_profile_function', 1004 FormatInstProfile(histblk["Instrument Parameters"],histblk['hId'])) 1005 1006 #refprx = '_refln.' # mm 1007 refprx = '_refln_' # normal 1008 WriteCIFitem('\n# STRUCTURE FACTOR TABLE') 1009 # compute maximum intensity reflection 1010 Imax = 0 1011 for phasenam in histblk['Reflection Lists']: 1012 scale = self.Phases[phasenam]['Histograms'][histlbl]['Scale'][0] 1013 Icorr = np.array([refl[13] for refl in histblk['Reflection Lists'][phasenam]])[0] 1014 FO2 = np.array([refl[8] for refl in histblk['Reflection Lists'][phasenam]]) 1015 I100 = scale*FO2*Icorr 1016 Imax = max(Imax,max(I100)) 1017 1018 WriteCIFitem('loop_') 1019 if len(histblk['Reflection Lists'].keys()) > 1: 1020 WriteCIFitem('\t_pd_refln_phase_id') 1021 WriteCIFitem('\t' + refprx + 'index_h' + 1022 '\n\t' + refprx + 'index_k' + 1023 '\n\t' + refprx + 'index_l' + 1024 '\n\t' + refprx + 'F_squared_meas' + 1025 '\n\t' + refprx + 'F_squared_calc' + 1026 '\n\t' + refprx + 'phase_calc' + 1027 '\n\t_pd_refln_d_spacing') 1028 if Imax > 0: 1029 WriteCIFitem('\t_gsas_i100_meas') 1030 1031 refcount = 0 1032 hklmin = None 1033 hklmax = None 1034 dmax = None 1035 dmin = None 1036 for phasenam in histblk['Reflection Lists']: 1037 scale = self.Phases[phasenam]['Histograms'][histlbl]['Scale'][0] 1038 phaseid = self.Phases[phasenam]['pId'] 1039 refcount += len(histblk['Reflection Lists'][phasenam]) 1040 for ref in histblk['Reflection Lists'][phasenam]: 1041 if DEBUG: 1042 print('DEBUG: skipping reflection list') 1043 break 1044 if hklmin is None: 1045 hklmin = ref[0:3] 1046 hklmax = ref[0:3] 1047 dmax = dmin = ref[4] 1048 if len(histblk['Reflection Lists'].keys()) > 1: 1049 s = PutInCol(phaseid,2) 1050 else: 1051 s = "" 1052 for i,hkl in enumerate(ref[0:3]): 1053 hklmax[i] = max(hkl,hklmax[i]) 1054 hklmin[i] = min(hkl,hklmin[i]) 1055 s += PutInCol(int(hkl),4) 1056 for I in ref[8:10]: 1057 s += PutInCol(G2mth.ValEsd(I,-0.0009),10) 1058 s += PutInCol(G2mth.ValEsd(ref[10],-0.9),7) 1059 dmax = max(dmax,ref[4]) 1060 dmin = min(dmin,ref[4]) 1061 s += PutInCol(G2mth.ValEsd(ref[4],-0.009),8) 1062 if Imax > 0: 1063 I100 = 100.*scale*ref[8]*ref[13]/Imax 1064 s += PutInCol(G2mth.ValEsd(I100,-0.09),6) 1065 WriteCIFitem(" "+s) 1066 1067 WriteReflStat(refcount,hklmin,hklmax,dmin,dmax,len(histblk['Reflection Lists'])) 1068 WriteCIFitem('\n# POWDER DATA TABLE') 1069 # is data fixed step? If the step varies by <0.01% treat as fixed step 1070 steps = histblk['Data'][0][1:] - histblk['Data'][0][:-1] 1071 if abs(max(steps)-min(steps)) > abs(max(steps))/10000.: 1072 fixedstep = False 1073 else: 1074 fixedstep = True 1075 1076 if fixedstep: # and not TOF 1077 WriteCIFitem('_pd_meas_2theta_range_min', G2mth.ValEsd(histblk['Data'][0][0],-0.00009)) 1078 WriteCIFitem('_pd_meas_2theta_range_max', G2mth.ValEsd(histblk['Data'][0][-1],-0.00009)) 1079 WriteCIFitem('_pd_meas_2theta_range_inc', G2mth.ValEsd(steps.sum()/len(steps),-0.00009)) 1080 # zero correct, if defined 1081 zero = None 1082 zerolst = histblk['Instrument Parameters'][0].get('Zero') 1083 if zerolst: zero = zerolst[1] 1084 zero = self.parmDict.get('Zero',zero) 1085 if zero: 1086 WriteCIFitem('_pd_proc_2theta_range_min', G2mth.ValEsd(histblk['Data'][0][0]-zero,-0.00009)) 1087 WriteCIFitem('_pd_proc_2theta_range_max', G2mth.ValEsd(histblk['Data'][0][-1]-zero,-0.00009)) 1088 WriteCIFitem('_pd_proc_2theta_range_inc', G2mth.ValEsd(steps.sum()/len(steps),-0.00009)) 1089 1090 if zero: 1091 WriteCIFitem('_pd_proc_number_of_points', str(len(histblk['Data'][0]))) 1092 else: 1093 WriteCIFitem('_pd_meas_number_of_points', str(len(histblk['Data'][0]))) 1094 WriteCIFitem('\nloop_') 1095 # WriteCIFitem('\t_pd_proc_d_spacing') # need easy way to get this 1096 if not fixedstep: 1097 if zero: 1098 WriteCIFitem('\t_pd_proc_2theta_corrected') 1099 else: 1100 WriteCIFitem('\t_pd_meas_2theta_scan') 1101 # at least for now, always report weights. 1102 #if countsdata: 1103 # WriteCIFitem('\t_pd_meas_counts_total') 1104 #else: 1105 WriteCIFitem('\t_pd_meas_intensity_total') 1106 WriteCIFitem('\t_pd_calc_intensity_total') 1107 WriteCIFitem('\t_pd_proc_intensity_bkg_calc') 1108 WriteCIFitem('\t_pd_proc_ls_weight') 1109 maxY = max(histblk['Data'][1].max(),histblk['Data'][3].max()) 1110 if maxY < 0: maxY *= -10 # this should never happen, but... 1111 ndec = max(0,10-int(np.log10(maxY))-1) # 10 sig figs should be enough 1112 maxSU = histblk['Data'][2].max() 1113 if maxSU < 0: maxSU *= -1 # this should never happen, but... 1114 ndecSU = max(0,8-int(np.log10(maxSU))-1) # 8 sig figs should be enough 1115 lowlim,highlim = histblk['Limits'][1] 1116 1117 if DEBUG: 1118 print('DEBUG: skipping profile list') 1119 else: 1120 for x,yobs,yw,ycalc,ybkg in zip(histblk['Data'][0], 1121 histblk['Data'][1], 1122 histblk['Data'][2], 1123 histblk['Data'][3], 1124 histblk['Data'][4]): 1125 if lowlim <= x <= highlim: 1126 pass 1127 else: 1128 yw = 0.0 # show the point is not in use 1129 1130 if fixedstep: 1131 s = "" 1132 else: 1133 s = PutInCol(G2mth.ValEsd(x-zero,-0.00009),10) 1134 s += PutInCol(Yfmt(ndec,yobs),12) 1135 s += PutInCol(Yfmt(ndec,ycalc),12) 1136 s += PutInCol(Yfmt(ndec,ybkg),11) 1137 s += PutInCol(Yfmt(ndecSU,yw),9) 1138 WriteCIFitem(" "+s) 1139 1140 def WriteSingleXtalData(histlbl): 1141 'Write out the selected single crystal histogram info' 1142 histblk = self.Histograms[histlbl] 1143 #refprx = '_refln.' # mm 1144 refprx = '_refln_' # normal 1145 1146 WriteCIFitem('\n# STRUCTURE FACTOR TABLE') 1147 WriteCIFitem('loop_' + 1148 '\n\t' + refprx + 'index_h' + 1149 '\n\t' + refprx + 'index_k' + 1150 '\n\t' + refprx + 'index_l' + 1151 '\n\t' + refprx + 'F_squared_meas' + 1152 '\n\t' + refprx + 'F_squared_sigma' + 1153 '\n\t' + refprx + 'F_squared_calc' + 1154 '\n\t' + refprx + 'phase_calc' 1155 ) 1156 1157 hklmin = None 1158 hklmax = None 1159 dmax = None 1160 dmin = None 1161 refcount = len(histblk['Data']) 1162 for ref in histblk['Data']: 1163 s = " " 1164 if hklmin is None: 1165 hklmin = ref[0:3] 1166 hklmax = ref[0:3] 1167 dmax = dmin = ref[4] 1168 for i,hkl in enumerate(ref[0:3]): 1169 hklmax[i] = max(hkl,hklmax[i]) 1170 hklmin[i] = min(hkl,hklmin[i]) 1171 s += PutInCol(int(hkl),4) 1172 import sys 1173 if ref[5] == 0.0: 1174 s += PutInCol(G2mth.ValEsd(ref[8],0),12) 1175 s += PutInCol('.',10) 1176 s += PutInCol(G2mth.ValEsd(ref[9],0),12) 1177 s += PutInCol(G2mth.ValEsd(ref[10],-0.9),7) 1178 else: 1179 sig = ref[6] * ref[8] / ref[5] 1180 s += PutInCol(G2mth.ValEsd(ref[8],-abs(sig/10)),12) 1181 s += PutInCol(G2mth.ValEsd(sig,-abs(sig)/10.),10) 1182 s += PutInCol(G2mth.ValEsd(ref[9],-abs(sig/10)),12) 1183 s += PutInCol(G2mth.ValEsd(ref[10],-0.9),7) 1184 dmax = max(dmax,ref[4]) 1185 dmin = min(dmin,ref[4]) 1186 WriteCIFitem(s) 1187 WriteReflStat(refcount,hklmin,hklmax,dmin,dmax) 1188 hId = histblk['hId'] 1189 pfx = '0:'+str(hId)+':' 1190 WriteCIFitem('_reflns_wR_factor_obs ','%.4f'%(histblk['wR']/100.)) 1191 WriteCIFitem('_reflns_R_F_factor_obs ','%.4f'%(histblk[pfx+'Rf']/100.)) 1192 WriteCIFitem('_reflns_R_Fsqd_factor_obs','%.4f'%(histblk[pfx+'Rf^2']/100.)) 1193 def EditAuthor(event=None): 1194 'dialog to edit the CIF author info' 1195 'Edit the CIF author name' 1196 dlg = G2gd.SingleStringDialog(self.G2frame, 1197 'Get CIF Author', 1198 'Provide CIF Author name (Last, First)', 1199 value=self.author) 1200 if not dlg.Show(): 1201 dlg.Destroy() 1202 return False # cancel was pressed 1203 self.author = dlg.GetValue() 1204 dlg.Destroy() 1205 try: 1206 self.OverallParms['Controls']["Author"] = self.author # save for future 1207 except KeyError: 1208 pass 1209 return True 1210 def EditInstNames(event=None): 1211 'Provide a dialog for editing instrument names' 1212 dictlist = [] 1213 keylist = [] 1214 lbllist = [] 1215 for hist in self.Histograms: 1216 if hist.startswith("PWDR"): 1217 key2 = "Sample Parameters" 1218 d = self.Histograms[hist][key2] 1219 elif hist.startswith("HKLF"): 1220 key2 = "Instrument Parameters" 1221 d = self.Histograms[hist][key2][0] 1222 1223 lbllist.append(hist) 1224 dictlist.append(d) 1225 keylist.append('InstrName') 1226 instrname = d.get('InstrName') 1227 if instrname is None: 1228 d['InstrName'] = '' 1229 return G2gd.CallScrolledMultiEditor( 1230 self.G2frame,dictlist,keylist, 1231 prelbl=range(1,len(dictlist)+1), 1232 postlbl=lbllist, 1233 title='Instrument names', 1234 header="Edit instrument names. Note that a non-blank\nname is required for all histograms", 1235 CopyButton=True) 1236 1237 def EditRanges(event): 1238 '''Edit the bond distance/angle search range; phase is determined from 1239 a pointer placed in the button object (.phasedict) that references the 1240 phase dictionary 1241 ''' 1242 but = event.GetEventObject() 1243 phasedict = but.phasedict 1244 dlg = G2gd.DisAglDialog(self.G2frame,{},phasedict['General']) 1245 if dlg.ShowModal() == wx.ID_OK: 1246 phasedict['General']['DisAglCtls'] = dlg.GetData() 1247 dlg.Destroy() 1248 1249 def EditCIFDefaults(): 1250 '''Fills the CIF Defaults window with controls for editing various CIF export 1251 parameters (mostly related to templates). 1252 ''' 1253 import wx.lib.scrolledpanel as wxscroll 1254 self.cifdefs.DestroyChildren() 1255 self.cifdefs.SetTitle('Edit CIF settings') 1256 vbox = wx.BoxSizer(wx.VERTICAL) 1257 but = wx.Button(self.cifdefs, wx.ID_ANY,'Edit CIF Author') 1258 but.Bind(wx.EVT_BUTTON,EditAuthor) 1259 vbox.Add(but,0,wx.ALIGN_CENTER,3) 1260 but = wx.Button(self.cifdefs, wx.ID_ANY,'Edit Instrument Name(s)') 1261 but.Bind(wx.EVT_BUTTON,EditInstNames) 1262 vbox.Add(but,0,wx.ALIGN_CENTER,3) 1263 cpnl = wxscroll.ScrolledPanel(self.cifdefs,size=(300,300)) 1264 cbox = wx.BoxSizer(wx.VERTICAL) 1265 G2gd.HorizontalLine(cbox,cpnl) 1266 cbox.Add( 1267 CIFtemplateSelect(self.cifdefs, 1268 cpnl,'publ',self.OverallParms['Controls'], 1269 EditCIFDefaults, 1270 "Publication (overall) template", 1271 ), 1272 0,wx.EXPAND|wx.ALIGN_LEFT|wx.ALL) 1273 for phasenam in sorted(self.Phases.keys()): 1274 G2gd.HorizontalLine(cbox,cpnl) 1275 title = 'Phase '+phasenam 1276 phasedict = self.Phases[phasenam] # pointer to current phase info 1277 cbox.Add( 1278 CIFtemplateSelect(self.cifdefs, 1279 cpnl,'phase',phasedict['General'], 1280 EditCIFDefaults, 1281 title, 1282 phasenam), 1283 0,wx.EXPAND|wx.ALIGN_LEFT|wx.ALL) 1284 cpnl.SetSizer(cbox) 1285 but = wx.Button(cpnl, wx.ID_ANY,'Edit distance/angle ranges') 1286 #cbox.Add(but,0,wx.ALIGN_CENTER,3) 1287 cbox.Add((-1,2)) 1288 cbox.Add(but,0,wx.ALIGN_LEFT,0) 1289 but.phasedict = self.Phases[phasenam] # set a pointer to current phase info 1290 but.Bind(wx.EVT_BUTTON,EditRanges) # phase bond/angle ranges 1291 for i in sorted(self.powderDict.keys()): 1292 G2gd.HorizontalLine(cbox,cpnl) 1293 hist = self.powderDict[i] 1294 histblk = self.Histograms[hist] 1295 title = 'Powder dataset '+hist[5:] 1296 cbox.Add( 1297 CIFtemplateSelect(self.cifdefs, 1298 cpnl,'powder',histblk["Sample Parameters"], 1299 EditCIFDefaults, 1300 title, 1301 histblk["Sample Parameters"]['InstrName']), 1302 0,wx.EXPAND|wx.ALIGN_LEFT|wx.ALL) 1303 cpnl.SetSizer(cbox) 1304 for i in sorted(self.xtalDict.keys()): 1305 G2gd.HorizontalLine(cbox,cpnl) 1306 hist = self.xtalDict[i] 1307 histblk = self.Histograms[hist] 1308 title = 'Single Xtal dataset '+hist[5:] 1309 cbox.Add( 1310 CIFtemplateSelect(self.cifdefs, 1311 cpnl,'single',histblk["Instrument Parameters"][0], 1312 EditCIFDefaults, 1313 title, 1314 histblk["Instrument Parameters"][0]['InstrName']), 1315 0,wx.EXPAND|wx.ALIGN_LEFT|wx.ALL) 1316 cpnl.SetSizer(cbox) 1317 1318 cpnl.SetAutoLayout(1) 1319 cpnl.SetupScrolling() 1320 #cpnl.Bind(rw.EVT_RW_LAYOUT_NEEDED, self.OnLayoutNeeded) # needed if sizes change 1321 cpnl.Layout() 1322 1323 vbox.Add(cpnl, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 0) 1324 btnsizer = wx.StdDialogButtonSizer() 1325 btn = wx.Button(self.cifdefs, wx.ID_OK, "Create CIF") 1326 btn.SetDefault() 1327 btnsizer.AddButton(btn) 1328 btn = wx.Button(self.cifdefs, wx.ID_CANCEL) 1329 btnsizer.AddButton(btn) 1330 btnsizer.Realize() 1331 vbox.Add(btnsizer, 0, wx.ALIGN_CENTER|wx.ALL, 5) 1332 self.cifdefs.SetSizer(vbox) 1333 vbox.Fit(self.cifdefs) 1334 self.cifdefs.Layout() 1335 1336 # ===== end of functions for export method ======================================= 1337 #================================================================================= 1338 1339 # the export process starts here 1340 # load all of the tree into a set of dicts 1341 self.loadTree() 1342 # create a dict with refined values and their uncertainties 1343 self.loadParmDict() 1344 1345 # Someday: get restraint & constraint info 1346 #restraintDict = self.OverallParms.get('Restraints',{}) 1347 #for i in self.OverallParms['Constraints']: 1348 # print i 1349 # for j in self.OverallParms['Constraints'][i]: 1350 # print j 1351 1352 self.CIFdate = dt.datetime.strftime(dt.datetime.now(),"%Y-%m-%dT%H:%M") 1353 # index powder and single crystal histograms 1354 self.powderDict = {} 1355 self.xtalDict = {} 1356 for hist in self.Histograms: 1357 i = self.Histograms[hist]['hId'] 1358 if hist.startswith("PWDR"): 1359 self.powderDict[i] = hist 1360 elif hist.startswith("HKLF"): 1361 self.xtalDict[i] = hist 1362 # is there anything to export? 1363 if len(self.Phases) == len(self.powderDict) == len(self.xtalDict) == 0: 1364 self.G2frame.ErrorDialog( 1365 'Empty project', 1366 'Project does not contain interconnected data & phase(s)') 1367 return 1368 # get the project file name 1369 self.CIFname = os.path.splitext( 1370 os.path.split(self.G2frame.GSASprojectfile)[1] 1371 )[0] 1372 self.CIFname = self.CIFname.replace(' ','') 1373 if not self.CIFname: # none defined & needed, save as GPX to get one 1374 self.G2frame.OnFileSaveas(None) 1375 if not self.G2frame.GSASprojectfile: return 1376 self.CIFname = os.path.splitext( 1377 os.path.split(self.G2frame.GSASprojectfile)[1] 1378 )[0] 1379 self.CIFname = self.CIFname.replace(' ','') 1380 # test for quick CIF mode or no data 1381 self.quickmode = False 1382 phasenam = phasenum = None # include all phases 1383 if mode != "full" or len(self.powderDict) + len(self.xtalDict) == 0: 1384 self.quickmode = True 1385 oneblock = True 1386 if len(self.Phases) == 0: 1387 self.G2frame.ErrorDialog( 1388 'No phase present', 1389 'Cannot create a coordinates CIF with no phases') 1390 return 1391 elif len(self.Phases) > 1: # quick mode: choose one phase 1392 choices = sorted(self.Phases.keys()) 1393 phasenum = G2gd.ItemSelector(choices,self.G2frame) 1394 if phasenum is None: return 1395 phasenam = choices[phasenum] 1396 # will this require a multiblock CIF? 1397 elif len(self.Phases) > 1: 1398 oneblock = False 1399 elif len(self.powderDict) + len(self.xtalDict) > 1: 1400 oneblock = False 1401 else: # one phase, one dataset, Full CIF 1402 oneblock = True 1403 1404 # make sure needed infomation is present 1405 # get CIF author name -- required for full CIFs 1406 try: 1407 self.author = self.OverallParms['Controls'].get("Author",'').strip() 1408 except KeyError: 1409 pass 1410 while not (self.author or self.quickmode): 1411 if not EditAuthor(): return 1412 self.shortauthorname = self.author.replace(',','').replace(' ','')[:20] 1413 1414 # check there is an instrument name for every histogram 1415 if not self.quickmode: 1416 invalid = 0 1417 key3 = 'InstrName' 1418 for hist in self.Histograms: 1419 if hist.startswith("PWDR"): 1420 key2 = "Sample Parameters" 1421 d = self.Histograms[hist][key2] 1422 elif hist.startswith("HKLF"): 1423 key2 = "Instrument Parameters" 1424 d = self.Histograms[hist][key2][0] 1425 instrname = d.get(key3) 1426 if instrname is None: 1427 d[key3] = '' 1428 invalid += 1 1429 elif instrname.strip() == '': 1430 invalid += 1 1431 if invalid: 1432 msg = "" 1433 if invalid > 3: msg = ( 1434 "\n\nNote: it may be faster to set the name for\n" 1435 "one histogram for each instrument and use the\n" 1436 "File/Copy option to duplicate the name" 1437 ) 1438 if not EditInstNames(): return 1439 # check for a distance-angle range search range for each phase 1440 if not self.quickmode: 1441 for phasenam in sorted(self.Phases.keys()): 1442 #i = self.Phases[phasenam]['pId'] 1443 phasedict = self.Phases[phasenam] # pointer to current phase info 1444 if 'DisAglCtls' not in phasedict['General']: 1445 dlg = G2gd.DisAglDialog(self.G2frame,{},phasedict['General']) 1446 if dlg.ShowModal() == wx.ID_OK: 1447 phasedict['General']['DisAglCtls'] = dlg.GetData() 1448 else: 1449 dlg.Destroy() 1450 return 1451 dlg.Destroy() 1452 1453 if oneblock and not self.quickmode: 1454 # select a dataset to use (there should only be one set in one block, 1455 # but take whatever comes 1st) 1456 for hist in self.Histograms: 1457 histblk = self.Histograms[hist] 1458 if hist.startswith("PWDR"): 1459 instnam = histblk["Sample Parameters"]['InstrName'] 1460 break # ignore all but 1st data histogram 1461 elif hist.startswith("HKLF"): 1462 instnam = histblk["Instrument Parameters"][0]['InstrName'] 1463 break # ignore all but 1st data histogram 1464 if self.quickmode: 1465 fil = self.askSaveFile() 1466 else: 1467 fil = self.defSaveFile() 1468 if not fil: return 1469 if not self.quickmode: # give the user a chance to edit all defaults 1470 self.cifdefs = wx.Dialog( 1471 self.G2frame,style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER) 1472 EditCIFDefaults() 1473 val = self.cifdefs.ShowModal() 1474 self.cifdefs.Destroy() 1475 if val != wx.ID_OK: 1476 return 1477 #====================================================================== 1478 # Start writing the CIF - single block 1479 #====================================================================== 1480 print('Writing CIF output to file '+fil+"...") 1481 openCIF(fil) 1482 if oneblock: 1483 WriteCIFitem('data_'+self.CIFname) 1484 if phasenam is None: # if not already selected, select the first phase (should be one) 1485 phasenam = self.Phases.keys()[0] 1486 #print 'phasenam',phasenam 1487 phaseblk = self.Phases[phasenam] # pointer to current phase info 1488 if not self.quickmode: 1489 instnam = instnam.replace(' ','') 1490 WriteCIFitem('_pd_block_id', 1491 str(self.CIFdate) + "|" + str(self.CIFname) + "|" + 1492 str(self.shortauthorname) + "|" + instnam) 1493 WriteAudit() 1494 writeCIFtemplate(self.OverallParms['Controls'],'publ') # overall (publication) template 1495 WriteOverall() 1496 writeCIFtemplate(self.Phases[phasenam]['General'],'phase',phasenam) # write phase template 1497 # report the phase info 1498 WritePhaseInfo(phasenam) 1499 if hist.startswith("PWDR") and not self.quickmode: 1500 # preferred orientation 1501 SH = FormatSH(phasenam) 1502 MD = FormatHAPpo(phasenam) 1503 if SH and MD: 1504 WriteCIFitem('_pd_proc_ls_pref_orient_corr', SH + '\n' + MD) 1505 elif SH or MD: 1506 WriteCIFitem('_pd_proc_ls_pref_orient_corr', SH + MD) 1507 else: 1508 WriteCIFitem('_pd_proc_ls_pref_orient_corr', 'none') 1509 # report profile, since one-block: include both histogram and phase info 1510 WriteCIFitem('_pd_proc_ls_profile_function', 1511 FormatInstProfile(histblk["Instrument Parameters"],histblk['hId']) 1512 +'\n'+FormatPhaseProfile(phasenam)) 1513 histblk = self.Histograms[hist]["Sample Parameters"] 1514 writeCIFtemplate(histblk,'powder',histblk['InstrName']) # write powder template 1515 WritePowderData(hist) 1516 elif hist.startswith("HKLF") and not self.quickmode: 1517 histprm = self.Histograms[hist]["Instrument Parameters"][0] 1518 writeCIFtemplate(histprm,'single',histprm['InstrName']) # single crystal template 1519 WriteSingleXtalData(hist) 1520 else: 1521 #====================================================================== 1522 # Start writing the CIF - multiblock 1523 #====================================================================== 1524 # publication info 1525 WriteCIFitem('\ndata_'+self.CIFname+'_publ') 1526 WriteAudit() 1527 WriteCIFitem('_pd_block_id', 1528 str(self.CIFdate) + "|" + str(self.CIFname) + "|" + 1529 str(self.shortauthorname) + "|Overall") 1530 writeCIFtemplate(self.OverallParms['Controls'],'publ') #insert the publication template 1531 # ``template_publ.cif`` or a modified version 1532 # overall info 1533 WriteCIFitem('data_'+str(self.CIFname)+'_overall') 1534 WriteOverall() 1535 #============================================================ 1536 WriteCIFitem('# POINTERS TO PHASE AND HISTOGRAM BLOCKS') 1537 datablockidDict = {} # save block names here -- N.B. check for conflicts between phase & hist names (unlikely!) 1538 # loop over phase blocks 1539 if len(self.Phases) > 1: 1540 loopprefix = '' 1541 WriteCIFitem('loop_ _pd_phase_block_id') 1542 else: 1543 loopprefix = '_pd_phase_block_id' 1544 1545 for phasenam in sorted(self.Phases.keys()): 1546 i = self.Phases[phasenam]['pId'] 1547 datablockidDict[phasenam] = (str(self.CIFdate) + "|" + str(self.CIFname) + "|" + 1548 'phase_'+ str(i) + '|' + str(self.shortauthorname)) 1549 WriteCIFitem(loopprefix,datablockidDict[phasenam]) 1550 # loop over data blocks 1551 if len(self.powderDict) + len(self.xtalDict) > 1: 1552 loopprefix = '' 1553 WriteCIFitem('loop_ _pd_block_diffractogram_id') 1554 else: 1555 loopprefix = '_pd_block_diffractogram_id' 1556 for i in sorted(self.powderDict.keys()): 1557 hist = self.powderDict[i] 1558 histblk = self.Histograms[hist] 1559 instnam = histblk["Sample Parameters"]['InstrName'] 1560 instnam = instnam.replace(' ','') 1561 i = histblk['hId'] 1562 datablockidDict[hist] = (str(self.CIFdate) + "|" + str(self.CIFname) + "|" + 1563 str(self.shortauthorname) + "|" + 1564 instnam + "_hist_"+str(i)) 1565 WriteCIFitem(loopprefix,datablockidDict[hist]) 1566 for i in sorted(self.xtalDict.keys()): 1567 hist = self.xtalDict[i] 1568 histblk = self.Histograms[hist] 1569 instnam = histblk["Instrument Parameters"][0]['InstrName'] 1570 instnam = instnam.replace(' ','') 1571 i = histblk['hId'] 1572 datablockidDict[hist] = (str(self.CIFdate) + "|" + str(self.CIFname) + "|" + 1573 str(self.shortauthorname) + "|" + 1574 instnam + "_hist_"+str(i)) 1575 WriteCIFitem(loopprefix,datablockidDict[hist]) 1576 #============================================================ 1577 # loop over phases, exporting them 1578 phasebyhistDict = {} # create a cross-reference to phases by histogram 1579 for j,phasenam in enumerate(sorted(self.Phases.keys())): 1580 i = self.Phases[phasenam]['pId'] 1581 WriteCIFitem('\ndata_'+self.CIFname+"_phase_"+str(i)) 1582 WriteCIFitem('# Information for phase '+str(i)) 1583 WriteCIFitem('_pd_block_id',datablockidDict[phasenam]) 1584 # report the phase 1585 writeCIFtemplate(self.Phases[phasenam]['General'],'phase',phasenam) # write phase template 1586 WritePhaseInfo(phasenam) 1587 # preferred orientation 1588 SH = FormatSH(phasenam) 1589 MD = FormatHAPpo(phasenam) 1590 if SH and MD: 1591 WriteCIFitem('_pd_proc_ls_pref_orient_corr', SH + '\n' + MD) 1592 elif SH or MD: 1593 WriteCIFitem('_pd_proc_ls_pref_orient_corr', SH + MD) 1594 else: 1595 WriteCIFitem('_pd_proc_ls_pref_orient_corr', 'none') 1596 # report sample profile terms 1597 PP = FormatPhaseProfile(phasenam) 1598 if PP: 1599 WriteCIFitem('_pd_proc_ls_profile_function',PP) 1600 1601 #============================================================ 1602 # loop over histograms, exporting them 1603 for i in sorted(self.powderDict.keys()): 1604 hist = self.powderDict[i] 1605 histblk = self.Histograms[hist] 1606 if hist.startswith("PWDR"): 1607 WriteCIFitem('\ndata_'+self.CIFname+"_pwd_"+str(i)) 1608 #instnam = histblk["Sample Parameters"]['InstrName'] 1609 # report instrumental profile terms 1610 WriteCIFitem('_pd_proc_ls_profile_function', 1611 FormatInstProfile(histblk["Instrument Parameters"],histblk['hId'])) 1612 WriteCIFitem('# Information for histogram '+str(i)+': '+hist) 1613 WriteCIFitem('_pd_block_id',datablockidDict[hist]) 1614 histprm = self.Histograms[hist]["Sample Parameters"] 1615 writeCIFtemplate(histprm,'powder',histprm['InstrName']) # powder template 1616 WritePowderData(hist) 1617 for i in sorted(self.xtalDict.keys()): 1618 hist = self.xtalDict[i] 1619 histblk = self.Histograms[hist] 1620 if hist.startswith("HKLF"): 1621 WriteCIFitem('\ndata_'+self.CIFname+"_sx_"+str(i)) 1622 #instnam = histblk["Instrument Parameters"][0]['InstrName'] 1623 WriteCIFitem('# Information for histogram '+str(i)+': '+hist) 1624 WriteCIFitem('_pd_block_id',datablockidDict[hist]) 1625 histprm = self.Histograms[hist]["Instrument Parameters"][0] 1626 writeCIFtemplate(histprm,'single',histprm['InstrName']) # single crystal template 1627 WriteSingleXtalData(hist) 1628 1629 WriteCIFitem('#--' + 15*'eof--' + '#') 1630 closeCIF() 1631 print("...export complete") 1632 # end of CIF export 58 1633 59 1634 #=============================================================================== … … 73 1648 import CifFile as cif # PyCifRW from James Hester 74 1649 cifdic = {} 75 #dictobj = cif.CifDic(fil) 76 fp = open(fil,'r') # patch: open file to avoid windows bug 77 dictobj = cif.CifDic(fp) 78 fp.close() 1650 try: 1651 fp = open(fil,'r') # patch: open file to avoid windows bug 1652 dictobj = cif.CifDic(fp) 1653 fp.close() 1654 except IOError: 1655 dictobj = cif.CifDic(fil) 79 1656 if DEBUG: print('loaded '+str(fil)) 80 1657 for item in dictobj.keys(): … … 606 2183 self.Add(hbox) 607 2184 def _onGetTemplateFile(self,event): 2185 'select a template file' 608 2186 dlg = wx.FileDialog( 609 2187 self.cifdefs, message="Read CIF template file", … … 617 2195 dlg.Destroy() 618 2196 if ret == wx.ID_OK: 619 import CifFile as cif # PyCifRW from James Hester620 2197 try: 621 #cf = cif.ReadCif(fil) 622 fp = open(fil,'r') # patch: open file to avoid windows bug 623 cf = cif.ReadCif(fp) 624 fp.close() 2198 cf = G2IO.ReadCIF(fil) 625 2199 if len(cf.keys()) == 0: raise Exception,"No CIF data_ blocks found" 626 2200 if len(cf.keys()) != 1: 627 print('\nWarning: CIF has more than one block, '+fil)2201 raise Exception, 'Error, CIF Template has more than one block: '+fil 628 2202 self.dict["CIF_template"] = fil 629 2203 except Exception as err: … … 640 2214 641 2215 def _onEditTemplateContents(self,event): 642 import CifFile as cif # PyCifRW from James Hester2216 'Called to edit the contents of a CIF template' 643 2217 if type(self.CIF) is list or type(self.CIF) is tuple: 644 2218 dblk,loopstructure = copy.deepcopy(self.CIF) # don't modify original 645 2219 else: 646 #dblk,loopstructure = CIF2dict(cif.ReadCif(self.CIF)) 647 fp = open(self.CIF,'r') # patch: open file to avoid windows bug 648 dblk,loopstructure = CIF2dict(cif.ReadCif(fp)) 649 fp.close() 2220 cf = G2IO.ReadCIF(self.CIF) 2221 dblk,loopstructure = CIF2dict(cf) 650 2222 dlg = EditCIFtemplate(self.cifdefs,dblk,loopstructure,self.defaultname) 651 2223 val = dlg.Post() … … 662 2234 # end of misc CIF utilities 663 2235 #=============================================================================== 664 665 class ExportCIF(G2IO.ExportBaseclass):666 '''Used to create a CIF of an entire project667 '''668 def __init__(self,G2frame):669 super(self.__class__,self).__init__( # fancy way to say <parentclass>.__init__670 G2frame=G2frame,671 formatName = 'full CIF',672 extension='.cif',673 longFormatName = 'Export project as CIF'674 )675 self.author = ''676 677 def export(self,mode='full'):678 '''Export a CIF679 680 :param str mode: "full" (default) to create a complete CIF of project,681 "simple" for a simple CIF with only coordinates682 '''683 684 # ===== define functions for export method =======================================685 def openCIF(filnam):686 if DEBUG:687 self.fp = sys.stdout688 else:689 self.fp = open(filnam,'w')690 691 def closeCIF():692 if not DEBUG:693 self.fp.close()694 695 def WriteCIFitem(name,value=''):696 if value:697 if "\n" in value or len(value)> 70:698 if name.strip(): self.fp.write(name+'\n')699 self.fp.write('; '+value+'\n')700 self.fp.write('; '+'\n')701 elif " " in value:702 if len(name)+len(value) > 65:703 self.fp.write(name + '\n ' + '"' + str(value) + '"'+'\n')704 else:705 self.fp.write(name + ' ' + '"' + str(value) + '"'+'\n')706 else:707 if len(name)+len(value) > 65:708 self.fp.write(name+'\n ' + value+'\n')709 else:710 self.fp.write(name+' ' + value+'\n')711 else:712 self.fp.write(name+'\n')713 714 def WriteAudit():715 WriteCIFitem('_audit_creation_method',716 'created in GSAS-II')717 WriteCIFitem('_audit_creation_date',self.CIFdate)718 if self.author:719 WriteCIFitem('_audit_author_name',self.author)720 WriteCIFitem('_audit_update_record',721 self.CIFdate+' Initial software-generated CIF')722 723 def WriteOverall():724 '''Write out overall refinement information.725 726 More could be done here, but this is a good start.727 '''728 WriteCIFitem('_pd_proc_info_datetime', self.CIFdate)729 WriteCIFitem('_pd_calc_method', 'Rietveld Refinement')730 #WriteCIFitem('_refine_ls_shift/su_max',DAT1)731 #WriteCIFitem('_refine_ls_shift/su_mean',DAT2)732 #WriteCIFitem('_refine_diff_density_max',rhomax) #these need to be defined for each phase!733 #WriteCIFitem('_refine_diff_density_min',rhomin)734 WriteCIFitem('_computing_structure_refinement','GSAS-II (Toby & Von Dreele, J. Appl. Cryst. 46, 544-549, 2013)')735 try:736 vars = str(len(self.OverallParms['Covariance']['varyList']))737 except:738 vars = '?'739 WriteCIFitem('_refine_ls_number_parameters',vars)740 try:741 GOF = G2mth.ValEsd(self.OverallParms['Covariance']['Rvals']['GOF'],-0.009)742 except:743 GOF = '?'744 WriteCIFitem('_refine_ls_goodness_of_fit_all',GOF)745 746 # get restraint info747 # restraintDict = self.OverallParms.get('Restraints',{})748 # for i in self.OverallParms['Constraints']:749 # print i750 # for j in self.OverallParms['Constraints'][i]:751 # print j752 #WriteCIFitem('_refine_ls_number_restraints',TEXT)753 # other things to consider reporting754 # _refine_ls_number_reflns755 # _refine_ls_goodness_of_fit_obs756 # _refine_ls_wR_factor_obs757 # _refine_ls_restrained_S_all758 # _refine_ls_restrained_S_obs759 760 # include an overall profile r-factor, if there is more than one powder histogram761 R = '%.5f'%(self.OverallParms['Covariance']['Rvals']['Rwp']/100.)762 WriteCIFitem('\n# OVERALL WEIGHTED R-FACTOR')763 WriteCIFitem('_refine_ls_wR_factor_obs',R)764 # _refine_ls_R_factor_all765 # _refine_ls_R_factor_obs766 WriteCIFitem('_refine_ls_matrix_type','full')767 #WriteCIFitem('_refine_ls_matrix_type','userblocks')768 769 def GetCIF(G2dict,tmplate,defaultname=''):770 CIFobj = G2dict.get("CIF_template")771 if defaultname:772 defaultname = defaultname.encode('ascii','replace').strip().replace(' ','_')773 defaultname = re.sub(r'[^a-zA-Z0-9_-]','',defaultname)774 defaultname = tmplate + "_" + defaultname + ".cif"775 else:776 defaultname = ''777 templateDefName = 'template_'+tmplate+'.cif'778 if not CIFobj: # copying a template779 for pth in [os.getcwd()]+sys.path:780 fil = os.path.join(pth,defaultname)781 if os.path.exists(fil) and defaultname: break782 else:783 for pth in sys.path:784 fil = os.path.join(pth,templateDefName)785 if os.path.exists(fil): break786 else:787 print(CIFobj+' not found in path!')788 return789 fp = open(fil,'r')790 txt = fp.read()791 fp.close()792 elif type(CIFobj) is not list and type(CIFobj) is not tuple:793 if not os.path.exists(CIFobj):794 print("Error: requested template file has disappeared: "+CIFobj)795 return796 fp = open(CIFobj,'r')797 txt = fp.read()798 fp.close()799 else:800 txt = dict2CIF(CIFobj[0],CIFobj[1]).WriteOut()801 # remove the PyCifRW header, if present802 #if txt.find('PyCifRW') > -1 and txt.find('data_') > -1:803 txt = "# GSAS-II edited template follows "+txt[txt.index("data_")+5:]804 #txt = txt.replace('data_','#')805 WriteCIFitem(txt)806 807 def WritePubTemplate():808 '''insert the publication template ``template_publ.cif`` or a modified809 version810 '''811 GetCIF(self.OverallParms['Controls'],'publ')812 813 def WritePhaseTemplate(phasenam):814 '''insert the phase template ``template_phase.cif`` or a modified815 version for this project816 '''817 GetCIF(self.Phases[phasenam]['General'],'phase',phasenam)818 819 def WritePowderTemplate(hist):820 '''insert the powder histogram phase template821 for this project822 '''823 histblk = self.Histograms[hist]["Sample Parameters"]824 GetCIF(histblk,'powder',histblk['InstrName'])825 826 def WriteSnglXtalTemplate(hist):827 '''insert the single-crystal histogram template828 for this project829 '''830 histblk = self.Histograms[hist]["Instrument Parameters"][0]831 GetCIF(histblk,'single',histblk['InstrName'])832 833 def FormatSH(phasenam):834 'Format a full spherical harmonics texture description as a string'835 phasedict = self.Phases[phasenam] # pointer to current phase info836 pfx = str(phasedict['pId'])+'::'837 s = ""838 textureData = phasedict['General']['SH Texture']839 if textureData.get('Order'):840 s += "Spherical Harmonics correction. Order = "+str(textureData['Order'])841 s += " Model: " + str(textureData['Model']) + "\n Orientation angles: "842 for name in ['omega','chi','phi']:843 aname = pfx+'SH '+name844 s += name + " = "845 sig = self.sigDict.get(aname,-0.09)846 s += G2mth.ValEsd(self.parmDict[aname],sig)847 s += "; "848 s += "\n"849 s1 = " Coefficients: "850 for name in textureData['SH Coeff'][1]:851 aname = pfx+name852 if len(s1) > 60:853 s += s1 + "\n"854 s1 = " "855 s1 += aname + ' = '856 sig = self.sigDict.get(aname,-0.0009)857 s1 += G2mth.ValEsd(self.parmDict[aname],sig)858 s1 += "; "859 s += s1860 return s861 862 def FormatHAPpo(phasenam):863 '''return the March-Dollase/SH correction for every864 histogram in the current phase formatted into a865 character string866 '''867 phasedict = self.Phases[phasenam] # pointer to current phase info868 s = ''869 for histogram in sorted(phasedict['Histograms']):870 if histogram.startswith("HKLF"): continue # powder only871 Histogram = self.Histograms.get(histogram)872 if not Histogram: continue873 hapData = phasedict['Histograms'][histogram]874 if hapData['Pref.Ori.'][0] == 'MD':875 aname = str(phasedict['pId'])+':'+str(Histogram['hId'])+':MD'876 if self.parmDict.get(aname,1.0) != 1.0: continue877 sig = self.sigDict.get(aname,-0.009)878 if s != "": s += '\n'879 s += 'March-Dollase correction'880 if len(self.powderDict) > 1:881 s += ', histogram '+str(Histogram['hId']+1)882 s += ' coef. = ' + G2mth.ValEsd(self.parmDict[aname],sig)883 s += ' axis = ' + str(hapData['Pref.Ori.'][3])884 else: # must be SH885 if s != "": s += '\n'886 s += 'Simple spherical harmonic correction'887 if len(self.powderDict) > 1:888 s += ', histogram '+str(Histogram['hId']+1)889 s += ' Order = '+str(hapData['Pref.Ori.'][4])+'\n'890 s1 = " Coefficients: "891 for item in hapData['Pref.Ori.'][5]:892 aname = str(phasedict['pId'])+':'+str(Histogram['hId'])+':'+item893 if len(s1) > 60:894 s += s1 + "\n"895 s1 = " "896 s1 += aname + ' = '897 sig = self.sigDict.get(aname,-0.0009)898 s1 += G2mth.ValEsd(self.parmDict[aname],sig)899 s1 += "; "900 s += s1901 return s902 def FormatBackground(bkg,hId):903 '''Display the Background information as a descriptive text string.904 905 TODO: this needs to be expanded to show the diffuse peak and906 Debye term information as well. (Bob)907 908 :returns: the text description (str)909 '''910 hfx = ':'+str(hId)+':'911 fxn, bkgdict = bkg912 terms = fxn[2]913 txt = 'Background function: "'+fxn[0]+'" function with '+str(terms)+' terms:\n'914 l = " "915 for i,v in enumerate(fxn[3:]):916 name = '%sBack:%d'%(hfx,i)917 sig = self.sigDict.get(name,-0.009)918 if len(l) > 60:919 txt += l + '\n'920 l = ' '921 l += G2mth.ValEsd(v,sig)+', '922 txt += l923 if bkgdict['nDebye']:924 txt += '\n Background Debye function parameters: A, R, U:'925 names = ['A:','R:','U:']926 for i in range(bkgdict['nDebye']):927 txt += '\n '928 for j in range(3):929 name = hfx+'Debye'+names[j]+str(i)930 sig = self.sigDict.get(name,-0.009)931 txt += G2mth.ValEsd(bkgdict['debyeTerms'][i][2*j],sig)+', '932 if bkgdict['nPeaks']:933 txt += '\n Background peak parameters: pos, int, sig, gam:'934 names = ['pos:','int:','sig:','gam:']935 for i in range(bkgdict['nPeaks']):936 txt += '\n '937 for j in range(4):938 name = hfx+'BkPk'+names[j]+str(i)939 sig = self.sigDict.get(name,-0.009)940 txt += G2mth.ValEsd(bkgdict['peaksList'][i][2*j],sig)+', '941 return txt942 943 def FormatInstProfile(instparmdict,hId):944 '''Format the instrumental profile parameters with a945 string description. Will only be called on PWDR histograms946 '''947 s = ''948 inst = instparmdict[0]949 hfx = ':'+str(hId)+':'950 if 'C' in inst['Type'][0]:951 s = 'Finger-Cox-Jephcoat function parameters U, V, W, X, Y, SH/L:\n'952 s += ' peak variance(Gauss) = Utan(Th)^2^+Vtan(Th)+W:\n'953 s += ' peak HW(Lorentz) = X/cos(Th)+Ytan(Th); SH/L = S/L+H/L\n'954 s += ' U, V, W in (centideg)^2^, X & Y in centideg\n '955 for item in ['U','V','W','X','Y','SH/L']:956 name = hfx+item957 sig = self.sigDict.get(name,-0.009)958 s += G2mth.ValEsd(inst[item][1],sig)+', '959 elif 'T' in inst['Type'][0]: #to be tested after TOF Rietveld done960 s = 'Von Dreele-Jorgenson-Windsor function parameters\n'+ \961 ' alpha, beta-0, beta-1, beta-q, sig-0, sig-1, sig-q, X, Y:\n '962 for item in ['alpha','bet-0','bet-1','bet-q','sig-0','sig-1','sig-q','X','Y']:963 name = hfx+item964 sig = self.sigDict.get(name,-0.009)965 s += G2mth.ValEsd(inst[item][1],sig)+', '966 return s967 968 def FormatPhaseProfile(phasenam):969 '''Format the phase-related profile parameters (size/strain)970 with a string description.971 return an empty string or None if there are no972 powder histograms for this phase.973 '''974 s = ''975 phasedict = self.Phases[phasenam] # pointer to current phase info976 SGData = phasedict['General'] ['SGData']977 for histogram in sorted(phasedict['Histograms']):978 if histogram.startswith("HKLF"): continue # powder only979 Histogram = self.Histograms.get(histogram)980 if not Histogram: continue981 hapData = phasedict['Histograms'][histogram]982 pId = phasedict['pId']983 hId = Histogram['hId']984 phfx = '%d:%d:'%(pId,hId)985 size = hapData['Size']986 mustrain = hapData['Mustrain']987 hstrain = hapData['HStrain']988 s = ' Crystallite size model "%s" for %s (microns)\n '%(size[0],phasenam)989 names = ['Size;i','Size;mx']990 if 'uniax' in size[0]:991 names = ['Size;i','Size;a','Size;mx']992 s += 'anisotropic axis is %s\n '%(str(size[3]))993 s += 'parameters: equatorial size, axial size, G/L mix\n '994 for i,item in enumerate(names):995 name = phfx+item996 sig = self.sigDict.get(name,-0.009)997 s += G2mth.ValEsd(size[1][i],sig)+', '998 elif 'ellip' in size[0]:999 s += 'parameters: S11, S22, S33, S12, S13, S23, G/L mix\n '1000 for i in range(6):1001 name = phfx+'Size:'+str(i)1002 sig = self.sigDict.get(name,-0.009)1003 s += G2mth.ValEsd(size[4][i],sig)+', '1004 sig = self.sigDict.get(phfx+'Size;mx',-0.009)1005 s += G2mth.ValEsd(size[1][2],sig)+', '1006 else: #isotropic1007 s += 'parameters: Size, G/L mix\n '1008 i = 01009 for item in names:1010 name = phfx+item1011 sig = self.sigDict.get(name,-0.009)1012 s += G2mth.ValEsd(size[1][i],sig)+', '1013 i = 2 #skip the aniso value1014 s += '\n Mustrain model "%s" for %s (10^6^)\n '%(mustrain[0],phasenam)1015 names = ['Mustrain;i','Mustrain;mx']1016 if 'uniax' in mustrain[0]:1017 names = ['Mustrain;i','Mustrain;a','Mustrain;mx']1018 s += 'anisotropic axis is %s\n '%(str(size[3]))1019 s += 'parameters: equatorial mustrain, axial mustrain, G/L mix\n '1020 for i,item in enumerate(names):1021 name = phfx+item1022 sig = self.sigDict.get(name,-0.009)1023 s += G2mth.ValEsd(mustrain[1][i],sig)+', '1024 elif 'general' in mustrain[0]:1025 names = 'parameters: '1026 for i,name in enumerate(G2spc.MustrainNames(SGData)):1027 names += name+', '1028 if i == 9:1029 names += '\n '1030 names += 'G/L mix\n '1031 s += names1032 txt = ''1033 for i in range(len(mustrain[4])):1034 name = phfx+'Mustrain:'+str(i)1035 sig = self.sigDict.get(name,-0.009)1036 if len(txt) > 60:1037 s += txt+'\n '1038 txt = ''1039 txt += G2mth.ValEsd(mustrain[4][i],sig)+', '1040 s += txt1041 sig = self.sigDict.get(phfx+'Mustrain;mx',-0.009)1042 s += G2mth.ValEsd(mustrain[1][2],sig)+', '1043 1044 else: #isotropic1045 s += ' parameters: Mustrain, G/L mix\n '1046 i = 01047 for item in names:1048 name = phfx+item1049 sig = self.sigDict.get(name,-0.009)1050 s += G2mth.ValEsd(mustrain[1][i],sig)+', '1051 i = 2 #skip the aniso value1052 s += '\n Macrostrain for %s\n'%(phasenam)1053 txt = ' parameters: '1054 names = G2spc.HStrainNames(SGData)1055 for name in names:1056 txt += name+', '1057 s += txt+'\n '1058 for i in range(len(names)):1059 name = phfx+name[i]1060 sig = self.sigDict.get(name,-0.009)1061 s += G2mth.ValEsd(hstrain[0][i],sig)+', '1062 return s1063 1064 def FmtAtomType(sym):1065 'Reformat a GSAS-II atom type symbol to match CIF rules'1066 sym = sym.replace('_','') # underscores are not allowed: no isotope designation?1067 # in CIF, oxidation state sign symbols come after, not before1068 if '+' in sym:1069 sym = sym.replace('+','') + '+'1070 elif '-' in sym:1071 sym = sym.replace('-','') + '-'1072 return sym1073 1074 def PutInCol(val,wid):1075 '''Pad a value to >=wid+1 columns by adding spaces at the end. Always1076 adds at least one space1077 '''1078 val = str(val).replace(' ','')1079 if not val: val = '?'1080 fmt = '{:' + str(wid) + '} '1081 return fmt.format(val)1082 1083 def MakeUniqueLabel(lbl,labellist):1084 'Make sure that every atom label is unique'1085 lbl = lbl.strip()1086 if not lbl: # deal with a blank label1087 lbl = 'A_1'1088 if lbl not in labellist:1089 labellist.append(lbl)1090 return lbl1091 i = 11092 prefix = lbl1093 if '_' in lbl:1094 prefix = lbl[:lbl.rfind('_')]1095 suffix = lbl[lbl.rfind('_')+1:]1096 try:1097 i = int(suffix)+11098 except:1099 pass1100 while prefix+'_'+str(i) in labellist:1101 i += 11102 else:1103 lbl = prefix+'_'+str(i)1104 labellist.append(lbl)1105 1106 def WriteAtomsNuclear(phasenam):1107 'Write atom positions to CIF'1108 phasedict = self.Phases[phasenam] # pointer to current phase info1109 General = phasedict['General']1110 cx,ct,cs,cia = General['AtomPtrs']1111 Atoms = phasedict['Atoms']1112 cfrac = cx+31113 fpfx = str(phasedict['pId'])+'::Afrac:'1114 for i,at in enumerate(Atoms):1115 fval = self.parmDict.get(fpfx+str(i),at[cfrac])1116 if fval != 0.0:1117 break1118 else:1119 WriteCIFitem('\n# PHASE HAS NO ATOMS!')1120 return1121 1122 WriteCIFitem('\n# ATOMIC COORDINATES AND DISPLACEMENT PARAMETERS')1123 WriteCIFitem('loop_ '+1124 '\n\t_atom_site_label'+1125 '\n\t_atom_site_type_symbol'+1126 '\n\t_atom_site_fract_x'+1127 '\n\t_atom_site_fract_y'+1128 '\n\t_atom_site_fract_z'+1129 '\n\t_atom_site_occupancy'+1130 '\n\t_atom_site_adp_type'+1131 '\n\t_atom_site_U_iso_or_equiv'+1132 '\n\t_atom_site_symmetry_multiplicity')1133 1134 varnames = {cx:'Ax',cx+1:'Ay',cx+2:'Az',cx+3:'Afrac',1135 cia+1:'AUiso',cia+2:'AU11',cia+3:'AU22',cia+4:'AU33',1136 cia+5:'AU12',cia+6:'AU13',cia+7:'AU23'}1137 self.labellist = []1138 1139 pfx = str(phasedict['pId'])+'::'1140 # loop over all atoms1141 naniso = 01142 for i,at in enumerate(Atoms):1143 s = PutInCol(MakeUniqueLabel(at[ct-1],self.labellist),6) # label1144 fval = self.parmDict.get(fpfx+str(i),at[cfrac])1145 if fval == 0.0: continue # ignore any atoms that have a occupancy set to 0 (exact)1146 s += PutInCol(FmtAtomType(at[ct]),4) # type1147 if at[cia] == 'I':1148 adp = 'Uiso '1149 else:1150 adp = 'Uani '1151 naniso += 11152 # compute Uequiv crudely1153 # correct: Defined as "1/3 trace of diagonalized U matrix".1154 # SEE cell2GS & Uij2Ueqv to GSASIIlattice. Former is needed to make the GS matrix used by the latter.1155 t = 0.01156 for j in (2,3,4):1157 var = pfx+varnames[cia+j]+":"+str(i)1158 t += self.parmDict.get(var,at[cia+j])1159 for j in (cx,cx+1,cx+2,cx+3,cia,cia+1):1160 if j in (cx,cx+1,cx+2):1161 dig = 111162 sigdig = -0.000091163 else:1164 dig = 101165 sigdig = -0.0091166 if j == cia:1167 s += adp1168 else:1169 var = pfx+varnames[j]+":"+str(i)1170 dvar = pfx+"d"+varnames[j]+":"+str(i)1171 if dvar not in self.sigDict:1172 dvar = var1173 if j == cia+1 and adp == 'Uani ':1174 val = t/3.1175 sig = sigdig1176 else:1177 #print var,(var in self.parmDict),(var in self.sigDict)1178 val = self.parmDict.get(var,at[j])1179 sig = self.sigDict.get(dvar,sigdig)1180 s += PutInCol(G2mth.ValEsd(val,sig),dig)1181 s += PutInCol(at[cs+1],3)1182 WriteCIFitem(s)1183 if naniso == 0: return1184 # now loop over aniso atoms1185 WriteCIFitem('\nloop_' + '\n\t_atom_site_aniso_label' +1186 '\n\t_atom_site_aniso_U_11' + '\n\t_atom_site_aniso_U_12' +1187 '\n\t_atom_site_aniso_U_13' + '\n\t_atom_site_aniso_U_22' +1188 '\n\t_atom_site_aniso_U_23' + '\n\t_atom_site_aniso_U_33')1189 for i,at in enumerate(Atoms):1190 fval = self.parmDict.get(fpfx+str(i),at[cfrac])1191 if fval == 0.0: continue # ignore any atoms that have a occupancy set to 0 (exact)1192 if at[cia] == 'I': continue1193 s = PutInCol(self.labellist[i],6) # label1194 for j in (2,3,4,5,6,7):1195 sigdig = -0.00091196 var = pfx+varnames[cia+j]+":"+str(i)1197 val = self.parmDict.get(var,at[cia+j])1198 sig = self.sigDict.get(var,sigdig)1199 s += PutInCol(G2mth.ValEsd(val,sig),11)1200 WriteCIFitem(s)1201 1202 def HillSortElements(elmlist):1203 '''Sort elements in "Hill" order: C, H, others, (where others1204 are alphabetical).1205 1206 :params list elmlist: a list of element strings1207 1208 :returns: a sorted list of element strings1209 '''1210 newlist = []1211 oldlist = elmlist[:]1212 for elm in ('C','H'):1213 if elm in elmlist:1214 newlist.append(elm)1215 oldlist.pop(oldlist.index(elm))1216 return newlist+sorted(oldlist)1217 1218 def WriteComposition(phasenam):1219 '''determine the composition for the unit cell, crudely determine Z and1220 then compute the composition in formula units1221 '''1222 phasedict = self.Phases[phasenam] # pointer to current phase info1223 General = phasedict['General']1224 Z = General.get('cellZ',0.0)1225 cx,ct,cs,cia = General['AtomPtrs']1226 Atoms = phasedict['Atoms']1227 fpfx = str(phasedict['pId'])+'::Afrac:'1228 cfrac = cx+31229 cmult = cs+11230 compDict = {} # combines H,D & T1231 sitemultlist = []1232 massDict = dict(zip(General['AtomTypes'],General['AtomMass']))1233 cellmass = 01234 for i,at in enumerate(Atoms):1235 atype = at[ct].strip()1236 if atype.find('-') != -1: atype = atype.split('-')[0]1237 if atype.find('+') != -1: atype = atype.split('+')[0]1238 atype = atype[0].upper()+atype[1:2].lower() # force case conversion1239 if atype == "D" or atype == "D": atype = "H"1240 fvar = fpfx+str(i)1241 fval = self.parmDict.get(fvar,at[cfrac])1242 mult = at[cmult]1243 if not massDict.get(at[ct]):1244 print('Error: No mass found for atom type '+at[ct])1245 print('Will not compute cell contents for phase '+phasenam)1246 return1247 cellmass += massDict[at[ct]]*mult*fval1248 compDict[atype] = compDict.get(atype,0.0) + mult*fval1249 if fval == 1: sitemultlist.append(mult)1250 if len(compDict.keys()) == 0: return # no elements!1251 if Z < 1: # Z has not been computed or set by user1252 Z = 11253 for i in range(2,min(sitemultlist)+1):1254 for m in sitemultlist:1255 if m % i != 0:1256 break1257 else:1258 Z = i1259 General['cellZ'] = Z # save it1260 1261 # when scattering factors are included in the CIF, this needs to be1262 # added to the loop here but only in the one-block case.1263 # For multiblock CIFs, scattering factors go in the histogram1264 # blocks (for all atoms in all appropriate phases) - an example?:1265 #loop_1266 # _atom_type_symbol1267 # _atom_type_description1268 # _atom_type_scat_dispersion_real1269 # _atom_type_scat_dispersion_imag1270 # _atom_type_scat_source1271 # 'C' 'C' 0.0033 0.00161272 # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'1273 # 'H' 'H' 0.0000 0.00001274 # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'1275 # 'P' 'P' 0.1023 0.09421276 # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'1277 # 'Cl' 'Cl' 0.1484 0.15851278 # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'1279 # 'Cu' 'Cu' 0.3201 1.26511280 # 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'1281 1282 #if oneblock: # add scattering factors for current phase here1283 WriteCIFitem('\nloop_ _atom_type_symbol _atom_type_number_in_cell')1284 formula = ''1285 reload(G2mth)1286 for elem in HillSortElements(compDict.keys()):1287 WriteCIFitem(' ' + PutInCol(elem,4) +1288 G2mth.ValEsd(compDict[elem],-0.009,True))1289 if formula: formula += " "1290 formula += elem1291 if compDict[elem] == Z: continue1292 formula += G2mth.ValEsd(compDict[elem]/Z,-0.009,True)1293 WriteCIFitem( '\n# Note that Z affects _cell_formula_sum and _weight')1294 WriteCIFitem( '_cell_formula_units_Z',str(Z))1295 WriteCIFitem( '_chemical_formula_sum',formula)1296 WriteCIFitem( '_chemical_formula_weight',1297 G2mth.ValEsd(cellmass/Z,-0.09,True))1298 1299 def WriteDistances(phasenam,SymOpList,offsetList,symOpList,G2oprList):1300 '''Report bond distances and angles for the CIF1301 1302 Note that _geom_*_symmetry_* fields are values of form1303 n_klm where n is the symmetry operation in SymOpList (counted1304 starting with 1) and (k-5, l-5, m-5) are translations to add1305 to (x,y,z). See1306 http://www.iucr.org/__data/iucr/cifdic_html/1/cif_core.dic/Igeom_angle_site_symmetry_.html1307 1308 TODO: need a method to select publication flags for distances/angles1309 '''1310 phasedict = self.Phases[phasenam] # pointer to current phase info1311 Atoms = phasedict['Atoms']1312 generalData = phasedict['General']1313 cx,ct,cs,cia = phasedict['General']['AtomPtrs']1314 cn = ct-11315 fpfx = str(phasedict['pId'])+'::Afrac:'1316 cfrac = cx+31317 DisAglData = {}1318 DisAglCtls = {}1319 # create a list of atoms, but skip atoms with zero occupancy1320 xyz = []1321 fpfx = str(phasedict['pId'])+'::Afrac:'1322 for i,atom in enumerate(Atoms):1323 if self.parmDict.get(fpfx+str(i),atom[cfrac]) == 0.0: continue1324 xyz.append([i,]+atom[cn:cn+2]+atom[cx:cx+3])1325 if 'DisAglCtls' in generalData:1326 DisAglCtls = generalData['DisAglCtls']1327 else:1328 dlg = G2gd.DisAglDialog(self.G2frame,DisAglCtls,generalData)1329 if dlg.ShowModal() == wx.ID_OK:1330 DisAglCtls = dlg.GetData()1331 generalData['DisAglCtls'] = DisAglCtls1332 else:1333 dlg.Destroy()1334 return1335 dlg.Destroy()1336 DisAglData['OrigAtoms'] = xyz1337 DisAglData['TargAtoms'] = xyz1338 SymOpList,offsetList,symOpList,G2oprList = G2spc.AllOps(1339 generalData['SGData'])1340 1341 xpandSGdata = generalData['SGData'].copy()1342 xpandSGdata.update({'SGOps':symOpList,1343 'SGInv':False,1344 'SGLatt':'P',1345 'SGCen':np.array([[0, 0, 0]]),})1346 DisAglData['SGData'] = xpandSGdata1347 1348 DisAglData['Cell'] = generalData['Cell'][1:] #+ volume1349 if 'pId' in phasedict:1350 DisAglData['pId'] = phasedict['pId']1351 DisAglData['covData'] = self.OverallParms['Covariance']1352 try:1353 AtomLabels,DistArray,AngArray = G2stMn.RetDistAngle(DisAglCtls,DisAglData)1354 except KeyError: # inside DistAngle for missing atom types in DisAglCtls1355 print('**** ERROR - try again but do "Reset" to fill in missing atom types ****')1356 1357 # loop over interatomic distances for this phase1358 WriteCIFitem('\n# MOLECULAR GEOMETRY')1359 WriteCIFitem('loop_' +1360 '\n\t_geom_bond_atom_site_label_1' +1361 '\n\t_geom_bond_atom_site_label_2' +1362 '\n\t_geom_bond_distance' +1363 '\n\t_geom_bond_site_symmetry_1' +1364 '\n\t_geom_bond_site_symmetry_2' +1365 '\n\t_geom_bond_publ_flag')1366 1367 for i in sorted(AtomLabels.keys()):1368 Dist = DistArray[i]1369 for D in Dist:1370 line = ' '+PutInCol(AtomLabels[i],6)+PutInCol(AtomLabels[D[0]],6)1371 sig = D[4]1372 if sig == 0: sig = -0.000091373 line += PutInCol(G2mth.ValEsd(D[3],sig,True),10)1374 line += " 1_555 "1375 line += " {:3d}_".format(D[2])1376 for d in D[1]:1377 line += "{:1d}".format(d+5)1378 line += " yes"1379 WriteCIFitem(line)1380 1381 # loop over interatomic angles for this phase1382 WriteCIFitem('\nloop_' +1383 '\n\t_geom_angle_atom_site_label_1' +1384 '\n\t_geom_angle_atom_site_label_2' +1385 '\n\t_geom_angle_atom_site_label_3' +1386 '\n\t_geom_angle' +1387 '\n\t_geom_angle_site_symmetry_1' +1388 '\n\t_geom_angle_site_symmetry_2' +1389 '\n\t_geom_angle_site_symmetry_3' +1390 '\n\t_geom_angle_publ_flag')1391 1392 for i in sorted(AtomLabels.keys()):1393 Dist = DistArray[i]1394 for k,j,tup in AngArray[i]:1395 Dj = Dist[j]1396 Dk = Dist[k]1397 line = ' '+PutInCol(AtomLabels[Dj[0]],6)+PutInCol(AtomLabels[i],6)+PutInCol(AtomLabels[Dk[0]],6)1398 sig = tup[1]1399 if sig == 0: sig = -0.0091400 line += PutInCol(G2mth.ValEsd(tup[0],sig,True),10)1401 line += " {:3d}_".format(Dj[2])1402 for d in Dj[1]:1403 line += "{:1d}".format(d+5)1404 line += " 1_555 "1405 line += " {:3d}_".format(Dk[2])1406 for d in Dk[1]:1407 line += "{:1d}".format(d+5)1408 line += " yes"1409 WriteCIFitem(line)1410 1411 def WritePhaseInfo(phasenam):1412 WriteCIFitem('\n# phase info for '+str(phasenam) + ' follows')1413 phasedict = self.Phases[phasenam] # pointer to current phase info1414 WriteCIFitem('_pd_phase_name', phasenam)1415 pfx = str(phasedict['pId'])+'::'1416 A,sigA = G2stIO.cellFill(pfx,phasedict['General']['SGData'],self.parmDict,self.sigDict)1417 cellSig = G2stIO.getCellEsd(pfx,1418 phasedict['General']['SGData'],A,1419 self.OverallParms['Covariance']) # returns 7 vals, includes sigVol1420 cellList = G2lat.A2cell(A) + (G2lat.calc_V(A),)1421 defsigL = 3*[-0.00001] + 3*[-0.001] + [-0.01] # significance to use when no sigma1422 names = ['length_a','length_b','length_c',1423 'angle_alpha','angle_beta ','angle_gamma',1424 'volume']1425 prevsig = 01426 for lbl,defsig,val,sig in zip(names,defsigL,cellList,cellSig):1427 if sig:1428 txt = G2mth.ValEsd(val,sig)1429 prevsig = -sig # use this as the significance for next value1430 else:1431 txt = G2mth.ValEsd(val,min(defsig,prevsig),True)1432 WriteCIFitem('_cell_'+lbl,txt)1433 1434 WriteCIFitem('_symmetry_cell_setting',1435 phasedict['General']['SGData']['SGSys'])1436 1437 spacegroup = phasedict['General']['SGData']['SpGrp'].strip()1438 # regularize capitalization and remove trailing H/R1439 spacegroup = spacegroup[0].upper() + spacegroup[1:].lower().rstrip('rh ')1440 WriteCIFitem('_symmetry_space_group_name_H-M',spacegroup)1441 1442 # generate symmetry operations including centering and center of symmetry1443 SymOpList,offsetList,symOpList,G2oprList = G2spc.AllOps(1444 phasedict['General']['SGData'])1445 WriteCIFitem('loop_\n _space_group_symop_id\n _space_group_symop_operation_xyz')1446 for i,op in enumerate(SymOpList,start=1):1447 WriteCIFitem(' {:3d} {:}'.format(i,op.lower()))1448 1449 # loop over histogram(s) used in this phase1450 if not oneblock and not self.quickmode:1451 # report pointers to the histograms used in this phase1452 histlist = []1453 for hist in self.Phases[phasenam]['Histograms']:1454 if self.Phases[phasenam]['Histograms'][hist]['Use']:1455 if phasebyhistDict.get(hist):1456 phasebyhistDict[hist].append(phasenam)1457 else:1458 phasebyhistDict[hist] = [phasenam,]1459 blockid = datablockidDict.get(hist)1460 if not blockid:1461 print("Internal error: no block for data. Phase "+str(1462 phasenam)+" histogram "+str(hist))1463 histlist = []1464 break1465 histlist.append(blockid)1466 1467 if len(histlist) == 0:1468 WriteCIFitem('# Note: phase has no associated data')1469 1470 # report atom params1471 if phasedict['General']['Type'] == 'nuclear': #this needs macromolecular variant, etc!1472 WriteAtomsNuclear(phasenam)1473 else:1474 raise Exception,"no export for mm coordinates implemented"1475 # report cell contents1476 WriteComposition(phasenam)1477 if not self.quickmode: # report distances and angles1478 WriteDistances(phasenam,SymOpList,offsetList,symOpList,G2oprList)1479 1480 def Yfmt(ndec,val):1481 'Format intensity values'1482 out = ("{:."+str(ndec)+"f}").format(val)1483 out = out.rstrip('0') # strip zeros to right of decimal1484 return out.rstrip('.') # and decimal place when not needed1485 1486 def WriteReflStat(refcount,hklmin,hklmax,dmin,dmax,nRefSets=1):1487 WriteCIFitem('_reflns_number_total', str(refcount))1488 if hklmin is not None and nRefSets == 1: # hkl range has no meaning with multiple phases1489 WriteCIFitem('_reflns_limit_h_min', str(int(hklmin[0])))1490 WriteCIFitem('_reflns_limit_h_max', str(int(hklmax[0])))1491 WriteCIFitem('_reflns_limit_k_min', str(int(hklmin[1])))1492 WriteCIFitem('_reflns_limit_k_max', str(int(hklmax[1])))1493 WriteCIFitem('_reflns_limit_l_min', str(int(hklmin[2])))1494 WriteCIFitem('_reflns_limit_l_max', str(int(hklmax[2])))1495 if hklmin is not None:1496 WriteCIFitem('_reflns_d_resolution_low ', G2mth.ValEsd(dmax,-0.009))1497 WriteCIFitem('_reflns_d_resolution_high ', G2mth.ValEsd(dmin,-0.009))1498 1499 def WritePowderData(histlbl):1500 histblk = self.Histograms[histlbl]1501 inst = histblk['Instrument Parameters'][0]1502 hId = histblk['hId']1503 pfx = ':' + str(hId) + ':'1504 1505 if 'Lam1' in inst:1506 ratio = self.parmDict.get('I(L2)/I(L1)',inst['I(L2)/I(L1)'][1])1507 sratio = self.sigDict.get('I(L2)/I(L1)',-0.0009)1508 lam1 = self.parmDict.get('Lam1',inst['Lam1'][1])1509 slam1 = self.sigDict.get('Lam1',-0.00009)1510 lam2 = self.parmDict.get('Lam2',inst['Lam2'][1])1511 slam2 = self.sigDict.get('Lam2',-0.00009)1512 # always assume Ka1 & Ka2 if two wavelengths are present1513 WriteCIFitem('_diffrn_radiation_type','K\\a~1,2~')1514 WriteCIFitem('loop_' +1515 '\n\t_diffrn_radiation_wavelength' +1516 '\n\t_diffrn_radiation_wavelength_wt' +1517 '\n\t_diffrn_radiation_wavelength_id')1518 WriteCIFitem(' ' + PutInCol(G2mth.ValEsd(lam1,slam1),15)+1519 PutInCol('1.0',15) +1520 PutInCol('1',5))1521 WriteCIFitem(' ' + PutInCol(G2mth.ValEsd(lam2,slam2),15)+1522 PutInCol(G2mth.ValEsd(ratio,sratio),15)+1523 PutInCol('2',5))1524 else:1525 lam1 = self.parmDict.get('Lam',inst['Lam'][1])1526 slam1 = self.sigDict.get('Lam',-0.00009)1527 WriteCIFitem('_diffrn_radiation_wavelength',G2mth.ValEsd(lam1,slam1))1528 1529 if not oneblock:1530 if not phasebyhistDict.get(histlbl):1531 WriteCIFitem('\n# No phases associated with this data set')1532 else:1533 WriteCIFitem('\n# PHASE TABLE')1534 WriteCIFitem('loop_' +1535 '\n\t_pd_phase_id' +1536 '\n\t_pd_phase_block_id' +1537 '\n\t_pd_phase_mass_%')1538 wtFrSum = 0.1539 for phasenam in phasebyhistDict.get(histlbl):1540 hapData = self.Phases[phasenam]['Histograms'][histlbl]1541 General = self.Phases[phasenam]['General']1542 wtFrSum += hapData['Scale'][0]*General['Mass']1543 1544 for phasenam in phasebyhistDict.get(histlbl):1545 hapData = self.Phases[phasenam]['Histograms'][histlbl]1546 General = self.Phases[phasenam]['General']1547 wtFr = hapData['Scale'][0]*General['Mass']/wtFrSum1548 pfx = str(self.Phases[phasenam]['pId'])+':'+str(hId)+':'1549 if pfx+'Scale' in self.sigDict:1550 sig = self.sigDict[pfx+'Scale']*wtFr/hapData['Scale'][0]1551 else:1552 sig = -0.00011553 WriteCIFitem(1554 ' '+1555 str(self.Phases[phasenam]['pId']) +1556 ' '+datablockidDict[phasenam]+1557 ' '+G2mth.ValEsd(wtFr,sig)1558 )1559 WriteCIFitem('loop_' +1560 '\n\t_gsas_proc_phase_R_F_factor' +1561 '\n\t_gsas_proc_phase_R_Fsqd_factor' +1562 '\n\t_gsas_proc_phase_id' +1563 '\n\t_gsas_proc_phase_block_id')1564 for phasenam in phasebyhistDict.get(histlbl):1565 pfx = str(self.Phases[phasenam]['pId'])+':'+str(hId)+':'1566 WriteCIFitem(1567 ' '+1568 ' '+G2mth.ValEsd(histblk[pfx+'Rf']/100.,-.00009) +1569 ' '+G2mth.ValEsd(histblk[pfx+'Rf^2']/100.,-.00009)+1570 ' '+str(self.Phases[phasenam]['pId'])+1571 ' '+datablockidDict[phasenam]1572 )1573 else:1574 # single phase in this histogram1575 pfx = '0:'+str(hId)+':'1576 WriteCIFitem('_refine_ls_R_F_factor ','%.5f'%(histblk[pfx+'Rf']/100.))1577 WriteCIFitem('_refine_ls_R_Fsqd_factor ','%.5f'%(histblk[pfx+'Rf^2']/100.))1578 1579 WriteCIFitem('_pd_proc_ls_prof_R_factor ','%.5f'%(histblk['R']/100.))1580 WriteCIFitem('_pd_proc_ls_prof_wR_factor ','%.5f'%(histblk['wR']/100.))1581 WriteCIFitem('_gsas_proc_ls_prof_R_B_factor ','%.5f'%(histblk['Rb']/100.))1582 WriteCIFitem('_gsas_proc_ls_prof_wR_B_factor','%.5f'%(histblk['wRb']/100.))1583 WriteCIFitem('_pd_proc_ls_prof_wR_expected','%.5f'%(histblk['wRmin']/100.))1584 1585 if histblk['Instrument Parameters'][0]['Type'][1][1] == 'X':1586 WriteCIFitem('_diffrn_radiation_probe','x-ray')1587 pola = histblk['Instrument Parameters'][0].get('Polariz.')1588 if pola:1589 pfx = ':' + str(hId) + ':'1590 sig = self.sigDict.get(pfx+'Polariz.',-0.0009)1591 txt = G2mth.ValEsd(pola[1],sig)1592 WriteCIFitem('_diffrn_radiation_polarisn_ratio',txt)1593 elif histblk['Instrument Parameters'][0]['Type'][1][1] == 'N':1594 WriteCIFitem('_diffrn_radiation_probe','neutron')1595 # TOF (note that this may not be defined)1596 #if histblk['Instrument Parameters'][0]['Type'][1][2] == 'T':1597 # WriteCIFitem('_pd_meas_2theta_fixed',text)1598 1599 1600 # TODO: this will need help from Bob1601 #if not oneblock:1602 #WriteCIFitem('\n# SCATTERING FACTOR INFO')1603 #WriteCIFitem('loop_ _atom_type_symbol')1604 #if histblk['Instrument Parameters'][0]['Type'][1][1] == 'X':1605 # WriteCIFitem(' _atom_type_scat_dispersion_real')1606 # WriteCIFitem(' _atom_type_scat_dispersion_imag')1607 # for lbl in ('a1','a2','a3', 'a4', 'b1', 'b2', 'b3', 'b4', 'c'):1608 # WriteCIFitem(' _atom_type_scat_Cromer_Mann_'+lbl)1609 #elif histblk['Instrument Parameters'][0]['Type'][1][1] == 'N':1610 # WriteCIFitem(' _atom_type_scat_length_neutron')1611 #WriteCIFitem(' _atom_type_scat_source')1612 1613 WriteCIFitem('_pd_proc_ls_background_function',FormatBackground(histblk['Background'],histblk['hId']))1614 1615 # TODO: this will need help from Bob1616 #WriteCIFitem('_exptl_absorpt_process_details','?')1617 #WriteCIFitem('_exptl_absorpt_correction_T_min','?')1618 #WriteCIFitem('_exptl_absorpt_correction_T_max','?')1619 #C extinction1620 #WRITE(IUCIF,'(A)') '# Extinction correction'1621 #CALL WRVAL(IUCIF,'_gsas_exptl_extinct_corr_T_min',TEXT(1:10))1622 #CALL WRVAL(IUCIF,'_gsas_exptl_extinct_corr_T_max',TEXT(11:20))1623 1624 if not oneblock: # instrumental profile terms go here1625 WriteCIFitem('_pd_proc_ls_profile_function',1626 FormatInstProfile(histblk["Instrument Parameters"],histblk['hId']))1627 1628 #refprx = '_refln.' # mm1629 refprx = '_refln_' # normal1630 WriteCIFitem('\n# STRUCTURE FACTOR TABLE')1631 # compute maximum intensity reflection1632 Imax = 01633 for phasenam in histblk['Reflection Lists']:1634 scale = self.Phases[phasenam]['Histograms'][histlbl]['Scale'][0]1635 Icorr = np.array([refl[13] for refl in histblk['Reflection Lists'][phasenam]])[0]1636 FO2 = np.array([refl[8] for refl in histblk['Reflection Lists'][phasenam]])1637 I100 = scale*FO2*Icorr1638 Imax = max(Imax,max(I100))1639 1640 WriteCIFitem('loop_')1641 if len(histblk['Reflection Lists'].keys()) > 1:1642 WriteCIFitem('\t_pd_refln_phase_id')1643 WriteCIFitem('\t' + refprx + 'index_h' +1644 '\n\t' + refprx + 'index_k' +1645 '\n\t' + refprx + 'index_l' +1646 '\n\t' + refprx + 'F_squared_meas' +1647 '\n\t' + refprx + 'F_squared_calc' +1648 '\n\t' + refprx + 'phase_calc' +1649 '\n\t_pd_refln_d_spacing')1650 if Imax > 0:1651 WriteCIFitem('\t_gsas_i100_meas')1652 1653 refcount = 01654 hklmin = None1655 hklmax = None1656 dmax = None1657 dmin = None1658 for phasenam in histblk['Reflection Lists']:1659 scale = self.Phases[phasenam]['Histograms'][histlbl]['Scale'][0]1660 phaseid = self.Phases[phasenam]['pId']1661 refcount += len(histblk['Reflection Lists'][phasenam])1662 for ref in histblk['Reflection Lists'][phasenam]:1663 if DEBUG:1664 print('DEBUG: skipping reflection list')1665 break1666 if hklmin is None:1667 hklmin = ref[0:3]1668 hklmax = ref[0:3]1669 dmax = dmin = ref[4]1670 if len(histblk['Reflection Lists'].keys()) > 1:1671 s = PutInCol(phaseid,2)1672 else:1673 s = ""1674 for i,hkl in enumerate(ref[0:3]):1675 hklmax[i] = max(hkl,hklmax[i])1676 hklmin[i] = min(hkl,hklmin[i])1677 s += PutInCol(int(hkl),4)1678 for I in ref[8:10]:1679 s += PutInCol(G2mth.ValEsd(I,-0.0009),10)1680 s += PutInCol(G2mth.ValEsd(ref[10],-0.9),7)1681 dmax = max(dmax,ref[4])1682 dmin = min(dmin,ref[4])1683 s += PutInCol(G2mth.ValEsd(ref[4],-0.009),8)1684 if Imax > 0:1685 I100 = 100.*scale*ref[8]*ref[13]/Imax1686 s += PutInCol(G2mth.ValEsd(I100,-0.09),6)1687 WriteCIFitem(" "+s)1688 1689 WriteReflStat(refcount,hklmin,hklmax,dmin,dmax,len(histblk['Reflection Lists']))1690 WriteCIFitem('\n# POWDER DATA TABLE')1691 # is data fixed step? If the step varies by <0.01% treat as fixed step1692 steps = histblk['Data'][0][1:] - histblk['Data'][0][:-1]1693 if abs(max(steps)-min(steps)) > abs(max(steps))/10000.:1694 fixedstep = False1695 else:1696 fixedstep = True1697 1698 if fixedstep: # and not TOF1699 WriteCIFitem('_pd_meas_2theta_range_min', G2mth.ValEsd(histblk['Data'][0][0],-0.00009))1700 WriteCIFitem('_pd_meas_2theta_range_max', G2mth.ValEsd(histblk['Data'][0][-1],-0.00009))1701 WriteCIFitem('_pd_meas_2theta_range_inc', G2mth.ValEsd(steps.sum()/len(steps),-0.00009))1702 # zero correct, if defined1703 zero = None1704 zerolst = histblk['Instrument Parameters'][0].get('Zero')1705 if zerolst: zero = zerolst[1]1706 zero = self.parmDict.get('Zero',zero)1707 if zero:1708 WriteCIFitem('_pd_proc_2theta_range_min', G2mth.ValEsd(histblk['Data'][0][0]-zero,-0.00009))1709 WriteCIFitem('_pd_proc_2theta_range_max', G2mth.ValEsd(histblk['Data'][0][-1]-zero,-0.00009))1710 WriteCIFitem('_pd_proc_2theta_range_inc', G2mth.ValEsd(steps.sum()/len(steps),-0.00009))1711 1712 if zero:1713 WriteCIFitem('_pd_proc_number_of_points', str(len(histblk['Data'][0])))1714 else:1715 WriteCIFitem('_pd_meas_number_of_points', str(len(histblk['Data'][0])))1716 WriteCIFitem('\nloop_')1717 # WriteCIFitem('\t_pd_proc_d_spacing') # need easy way to get this1718 if not fixedstep:1719 if zero:1720 WriteCIFitem('\t_pd_proc_2theta_corrected')1721 else:1722 WriteCIFitem('\t_pd_meas_2theta_scan')1723 # at least for now, always report weights.1724 #if countsdata:1725 # WriteCIFitem('\t_pd_meas_counts_total')1726 #else:1727 WriteCIFitem('\t_pd_meas_intensity_total')1728 WriteCIFitem('\t_pd_calc_intensity_total')1729 WriteCIFitem('\t_pd_proc_intensity_bkg_calc')1730 WriteCIFitem('\t_pd_proc_ls_weight')1731 maxY = max(histblk['Data'][1].max(),histblk['Data'][3].max())1732 if maxY < 0: maxY *= -10 # this should never happen, but...1733 ndec = max(0,10-int(np.log10(maxY))-1) # 10 sig figs should be enough1734 maxSU = histblk['Data'][2].max()1735 if maxSU < 0: maxSU *= -1 # this should never happen, but...1736 ndecSU = max(0,8-int(np.log10(maxSU))-1) # 8 sig figs should be enough1737 lowlim,highlim = histblk['Limits'][1]1738 1739 if DEBUG:1740 print('DEBUG: skipping profile list')1741 else:1742 for x,yobs,yw,ycalc,ybkg in zip(histblk['Data'][0],1743 histblk['Data'][1],1744 histblk['Data'][2],1745 histblk['Data'][3],1746 histblk['Data'][4]):1747 if lowlim <= x <= highlim:1748 pass1749 else:1750 yw = 0.0 # show the point is not in use1751 1752 if fixedstep:1753 s = ""1754 else:1755 s = PutInCol(G2mth.ValEsd(x-zero,-0.00009),10)1756 s += PutInCol(Yfmt(ndec,yobs),12)1757 s += PutInCol(Yfmt(ndec,ycalc),12)1758 s += PutInCol(Yfmt(ndec,ybkg),11)1759 s += PutInCol(Yfmt(ndecSU,yw),9)1760 WriteCIFitem(" "+s)1761 1762 def WriteSingleXtalData(histlbl):1763 histblk = self.Histograms[histlbl]1764 #refprx = '_refln.' # mm1765 refprx = '_refln_' # normal1766 1767 WriteCIFitem('\n# STRUCTURE FACTOR TABLE')1768 WriteCIFitem('loop_' +1769 '\n\t' + refprx + 'index_h' +1770 '\n\t' + refprx + 'index_k' +1771 '\n\t' + refprx + 'index_l' +1772 '\n\t' + refprx + 'F_squared_meas' +1773 '\n\t' + refprx + 'F_squared_sigma' +1774 '\n\t' + refprx + 'F_squared_calc' +1775 '\n\t' + refprx + 'phase_calc'1776 )1777 1778 hklmin = None1779 hklmax = None1780 dmax = None1781 dmin = None1782 refcount = len(histblk['Data'])1783 for ref in histblk['Data']:1784 s = " "1785 if hklmin is None:1786 hklmin = ref[0:3]1787 hklmax = ref[0:3]1788 dmax = dmin = ref[4]1789 for i,hkl in enumerate(ref[0:3]):1790 hklmax[i] = max(hkl,hklmax[i])1791 hklmin[i] = min(hkl,hklmin[i])1792 s += PutInCol(int(hkl),4)1793 sig = ref[6] * ref[8] / ref[5]1794 s += PutInCol(G2mth.ValEsd(ref[8],-abs(sig/10)),12)1795 s += PutInCol(G2mth.ValEsd(sig,-abs(sig)/10.),10)1796 s += PutInCol(G2mth.ValEsd(ref[9],-abs(sig/10)),12)1797 s += PutInCol(G2mth.ValEsd(ref[10],-0.9),7)1798 dmax = max(dmax,ref[4])1799 dmin = min(dmin,ref[4])1800 WriteCIFitem(s)1801 WriteReflStat(refcount,hklmin,hklmax,dmin,dmax)1802 hId = histblk['hId']1803 pfx = '0:'+str(hId)+':'1804 WriteCIFitem('_reflns_wR_factor_obs ','%.4f'%(histblk['wR']/100.))1805 WriteCIFitem('_reflns_R_F_factor_obs ','%.4f'%(histblk[pfx+'Rf']/100.))1806 WriteCIFitem('_reflns_R_Fsqd_factor_obs','%.4f'%(histblk[pfx+'Rf^2']/100.))1807 def EditAuthor(event=None):1808 'Edit the CIF author name'1809 dlg = G2gd.SingleStringDialog(self.G2frame,1810 'Get CIF Author',1811 'Provide CIF Author name (Last, First)',1812 value=self.author)1813 if not dlg.Show():1814 dlg.Destroy()1815 return False # cancel was pressed1816 self.author = dlg.GetValue()1817 dlg.Destroy()1818 try:1819 self.OverallParms['Controls']["Author"] = self.author # save for future1820 except KeyError:1821 pass1822 return True1823 def EditInstNames(event=None):1824 'Provide a dialog for editing instrument names'1825 dictlist = []1826 keylist = []1827 lbllist = []1828 for hist in self.Histograms:1829 if hist.startswith("PWDR"):1830 key2 = "Sample Parameters"1831 d = self.Histograms[hist][key2]1832 elif hist.startswith("HKLF"):1833 key2 = "Instrument Parameters"1834 d = self.Histograms[hist][key2][0]1835 1836 lbllist.append(hist)1837 dictlist.append(d)1838 keylist.append('InstrName')1839 instrname = d.get('InstrName')1840 if instrname is None:1841 d['InstrName'] = ''1842 return G2gd.CallScrolledMultiEditor(1843 self.G2frame,dictlist,keylist,1844 prelbl=range(1,len(dictlist)+1),1845 postlbl=lbllist,1846 title='Instrument names',1847 header="Edit instrument names. Note that a non-blank\nname is required for all histograms",1848 CopyButton=True)1849 1850 def EditRanges(event):1851 but = event.GetEventObject()1852 phasedict = but.phasedict1853 dlg = G2gd.DisAglDialog(self.G2frame,{},phasedict['General'])1854 if dlg.ShowModal() == wx.ID_OK:1855 phasedict['General']['DisAglCtls'] = dlg.GetData()1856 dlg.Destroy()1857 1858 def EditCIFDefaults():1859 'Fills the CIF Defaults window'1860 import wx.lib.scrolledpanel as wxscroll1861 self.cifdefs.DestroyChildren()1862 self.cifdefs.SetTitle('Edit CIF settings')1863 vbox = wx.BoxSizer(wx.VERTICAL)1864 but = wx.Button(self.cifdefs, wx.ID_ANY,'Edit CIF Author')1865 but.Bind(wx.EVT_BUTTON,EditAuthor)1866 vbox.Add(but,0,wx.ALIGN_CENTER,3)1867 but = wx.Button(self.cifdefs, wx.ID_ANY,'Edit Instrument Name(s)')1868 but.Bind(wx.EVT_BUTTON,EditInstNames)1869 vbox.Add(but,0,wx.ALIGN_CENTER,3)1870 cpnl = wxscroll.ScrolledPanel(self.cifdefs,size=(300,300))1871 cbox = wx.BoxSizer(wx.VERTICAL)1872 G2gd.HorizontalLine(cbox,cpnl)1873 cbox.Add(1874 CIFtemplateSelect(self.cifdefs,1875 cpnl,'publ',self.OverallParms['Controls'],1876 EditCIFDefaults,1877 "Publication (overall) template",1878 ),1879 0,wx.EXPAND|wx.ALIGN_LEFT|wx.ALL)1880 for phasenam in sorted(self.Phases.keys()):1881 G2gd.HorizontalLine(cbox,cpnl)1882 title = 'Phase '+phasenam1883 phasedict = self.Phases[phasenam] # pointer to current phase info1884 cbox.Add(1885 CIFtemplateSelect(self.cifdefs,1886 cpnl,'phase',phasedict['General'],1887 EditCIFDefaults,1888 title,1889 phasenam),1890 0,wx.EXPAND|wx.ALIGN_LEFT|wx.ALL)1891 cpnl.SetSizer(cbox)1892 but = wx.Button(cpnl, wx.ID_ANY,'Edit distance/angle ranges')1893 #cbox.Add(but,0,wx.ALIGN_CENTER,3)1894 cbox.Add((-1,2))1895 cbox.Add(but,0,wx.ALIGN_LEFT,0)1896 but.phasedict = self.Phases[phasenam] # set a pointer to current phase info1897 but.Bind(wx.EVT_BUTTON,EditRanges) # phase bond/angle ranges1898 for i in sorted(self.powderDict.keys()):1899 G2gd.HorizontalLine(cbox,cpnl)1900 hist = self.powderDict[i]1901 histblk = self.Histograms[hist]1902 title = 'Powder dataset '+hist[5:]1903 cbox.Add(1904 CIFtemplateSelect(self.cifdefs,1905 cpnl,'powder',histblk["Sample Parameters"],1906 EditCIFDefaults,1907 title,1908 histblk["Sample Parameters"]['InstrName']),1909 0,wx.EXPAND|wx.ALIGN_LEFT|wx.ALL)1910 cpnl.SetSizer(cbox)1911 for i in sorted(self.xtalDict.keys()):1912 G2gd.HorizontalLine(cbox,cpnl)1913 hist = self.xtalDict[i]1914 histblk = self.Histograms[hist]1915 title = 'Single Xtal dataset '+hist[5:]1916 cbox.Add(1917 CIFtemplateSelect(self.cifdefs,1918 cpnl,'single',histblk["Instrument Parameters"][0],1919 EditCIFDefaults,1920 title,1921 histblk["Instrument Parameters"][0]['InstrName']),1922 0,wx.EXPAND|wx.ALIGN_LEFT|wx.ALL)1923 cpnl.SetSizer(cbox)1924 1925 cpnl.SetAutoLayout(1)1926 cpnl.SetupScrolling()1927 #cpnl.Bind(rw.EVT_RW_LAYOUT_NEEDED, self.OnLayoutNeeded) # needed if sizes change1928 cpnl.Layout()1929 1930 vbox.Add(cpnl, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 0)1931 btnsizer = wx.StdDialogButtonSizer()1932 btn = wx.Button(self.cifdefs, wx.ID_OK, "Create CIF")1933 btn.SetDefault()1934 btnsizer.AddButton(btn)1935 btn = wx.Button(self.cifdefs, wx.ID_CANCEL)1936 btnsizer.AddButton(btn)1937 btnsizer.Realize()1938 vbox.Add(btnsizer, 0, wx.ALIGN_CENTER|wx.ALL, 5)1939 self.cifdefs.SetSizer(vbox)1940 vbox.Fit(self.cifdefs)1941 self.cifdefs.Layout()1942 1943 # ===== end of functions for export method =======================================1944 #=================================================================================1945 1946 # the export process starts here1947 # load all of the tree into a set of dicts1948 self.loadTree()1949 # create a dict with refined values and their uncertainties1950 self.loadParmDict()1951 1952 # Someday: get restraint & constraint info1953 #restraintDict = self.OverallParms.get('Restraints',{})1954 #for i in self.OverallParms['Constraints']:1955 # print i1956 # for j in self.OverallParms['Constraints'][i]:1957 # print j1958 1959 self.CIFdate = dt.datetime.strftime(dt.datetime.now(),"%Y-%m-%dT%H:%M")1960 # index powder and single crystal histograms1961 self.powderDict = {}1962 self.xtalDict = {}1963 for hist in self.Histograms:1964 i = self.Histograms[hist]['hId']1965 if hist.startswith("PWDR"):1966 self.powderDict[i] = hist1967 elif hist.startswith("HKLF"):1968 self.xtalDict[i] = hist1969 # is there anything to export?1970 if len(self.Phases) == len(self.powderDict) == len(self.xtalDict) == 0:1971 self.G2frame.ErrorDialog(1972 'Empty project',1973 'Project does not contain interconnected data & phase(s)')1974 return1975 # get the project file name1976 self.CIFname = os.path.splitext(1977 os.path.split(self.G2frame.GSASprojectfile)[1]1978 )[0]1979 self.CIFname = self.CIFname.replace(' ','')1980 if not self.CIFname: # none defined & needed, save as GPX to get one1981 self.G2frame.OnFileSaveas(None)1982 if not self.G2frame.GSASprojectfile: return1983 self.CIFname = os.path.splitext(1984 os.path.split(self.G2frame.GSASprojectfile)[1]1985 )[0]1986 self.CIFname = self.CIFname.replace(' ','')1987 # test for quick CIF mode or no data1988 self.quickmode = False1989 phasenam = phasenum = None # include all phases1990 if mode != "full" or len(self.powderDict) + len(self.xtalDict) == 0:1991 self.quickmode = True1992 oneblock = True1993 if len(self.Phases) == 0:1994 self.G2frame.ErrorDialog(1995 'No phase present',1996 'Cannot create a coordinates CIF with no phases')1997 return1998 elif len(self.Phases) > 1: # quick mode: choose one phase1999 choices = sorted(self.Phases.keys())2000 phasenum = G2gd.ItemSelector(choices,self.G2frame)2001 if phasenum is None: return2002 phasenam = choices[phasenum]2003 # will this require a multiblock CIF?2004 elif len(self.Phases) > 1:2005 oneblock = False2006 elif len(self.powderDict) + len(self.xtalDict) > 1:2007 oneblock = False2008 else: # one phase, one dataset, Full CIF2009 oneblock = True2010 2011 # make sure needed infomation is present2012 # get CIF author name -- required for full CIFs2013 try:2014 self.author = self.OverallParms['Controls'].get("Author",'').strip()2015 except KeyError:2016 pass2017 while not (self.author or self.quickmode):2018 if not EditAuthor(): return2019 self.shortauthorname = self.author.replace(',','').replace(' ','')[:20]2020 2021 # check there is an instrument name for every histogram2022 if not self.quickmode:2023 invalid = 02024 key3 = 'InstrName'2025 for hist in self.Histograms:2026 if hist.startswith("PWDR"):2027 key2 = "Sample Parameters"2028 d = self.Histograms[hist][key2]2029 elif hist.startswith("HKLF"):2030 key2 = "Instrument Parameters"2031 d = self.Histograms[hist][key2][0]2032 instrname = d.get(key3)2033 if instrname is None:2034 d[key3] = ''2035 invalid += 12036 elif instrname.strip() == '':2037 invalid += 12038 if invalid:2039 msg = ""2040 if invalid > 3: msg = (2041 "\n\nNote: it may be faster to set the name for\n"2042 "one histogram for each instrument and use the\n"2043 "File/Copy option to duplicate the name"2044 )2045 if not EditInstNames(): return2046 # check for a distance-angle range search range for each phase2047 if not self.quickmode:2048 for phasenam in sorted(self.Phases.keys()):2049 #i = self.Phases[phasenam]['pId']2050 phasedict = self.Phases[phasenam] # pointer to current phase info2051 if 'DisAglCtls' not in phasedict['General']:2052 dlg = G2gd.DisAglDialog(self.G2frame,{},phasedict['General'])2053 if dlg.ShowModal() == wx.ID_OK:2054 phasedict['General']['DisAglCtls'] = dlg.GetData()2055 else:2056 dlg.Destroy()2057 return2058 dlg.Destroy()2059 2060 if oneblock and not self.quickmode:2061 # select a dataset to use (there should only be one set in one block,2062 # but take whatever comes 1st)2063 for hist in self.Histograms:2064 histblk = self.Histograms[hist]2065 if hist.startswith("PWDR"):2066 instnam = histblk["Sample Parameters"]['InstrName']2067 break # ignore all but 1st data histogram2068 elif hist.startswith("HKLF"):2069 instnam = histblk["Instrument Parameters"][0]['InstrName']2070 break # ignore all but 1st data histogram2071 if self.quickmode:2072 fil = self.askSaveFile()2073 else:2074 fil = self.defSaveFile()2075 if not fil: return2076 if not self.quickmode: # give the user a chance to edit all defaults2077 self.cifdefs = wx.Dialog(2078 self.G2frame,style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)2079 EditCIFDefaults()2080 val = self.cifdefs.ShowModal()2081 self.cifdefs.Destroy()2082 if val != wx.ID_OK:2083 return2084 #======================================================================2085 # Start writing the CIF - single block2086 #======================================================================2087 print('Writing CIF output to file '+fil+"...")2088 openCIF(fil)2089 if oneblock:2090 WriteCIFitem('data_'+self.CIFname)2091 if phasenam is None: # if not already selected, select the first phase (should be one)2092 phasenam = self.Phases.keys()[0]2093 #print 'phasenam',phasenam2094 phaseblk = self.Phases[phasenam] # pointer to current phase info2095 if not self.quickmode:2096 instnam = instnam.replace(' ','')2097 WriteCIFitem('_pd_block_id',2098 str(self.CIFdate) + "|" + str(self.CIFname) + "|" +2099 str(self.shortauthorname) + "|" + instnam)2100 WriteAudit()2101 WritePubTemplate()2102 WriteOverall()2103 WritePhaseTemplate(phasenam)2104 # report the phase info2105 WritePhaseInfo(phasenam)2106 if hist.startswith("PWDR") and not self.quickmode:2107 # preferred orientation2108 SH = FormatSH(phasenam)2109 MD = FormatHAPpo(phasenam)2110 if SH and MD:2111 WriteCIFitem('_pd_proc_ls_pref_orient_corr', SH + '\n' + MD)2112 elif SH or MD:2113 WriteCIFitem('_pd_proc_ls_pref_orient_corr', SH + MD)2114 else:2115 WriteCIFitem('_pd_proc_ls_pref_orient_corr', 'none')2116 # report profile, since one-block: include both histogram and phase info2117 WriteCIFitem('_pd_proc_ls_profile_function',2118 FormatInstProfile(histblk["Instrument Parameters"],histblk['hId'])2119 +'\n'+FormatPhaseProfile(phasenam))2120 WritePowderTemplate(hist)2121 WritePowderData(hist)2122 elif hist.startswith("HKLF") and not self.quickmode:2123 WriteSnglXtalTemplate(hist)2124 WriteSingleXtalData(hist)2125 else:2126 #======================================================================2127 # Start writing the CIF - multiblock2128 #======================================================================2129 # publication info2130 WriteCIFitem('\ndata_'+self.CIFname+'_publ')2131 WriteAudit()2132 WriteCIFitem('_pd_block_id',2133 str(self.CIFdate) + "|" + str(self.CIFname) + "|" +2134 str(self.shortauthorname) + "|Overall")2135 WritePubTemplate()2136 # overall info2137 WriteCIFitem('data_'+str(self.CIFname)+'_overall')2138 WriteOverall()2139 #============================================================2140 WriteCIFitem('# POINTERS TO PHASE AND HISTOGRAM BLOCKS')2141 datablockidDict = {} # save block names here -- N.B. check for conflicts between phase & hist names (unlikely!)2142 # loop over phase blocks2143 if len(self.Phases) > 1:2144 loopprefix = ''2145 WriteCIFitem('loop_ _pd_phase_block_id')2146 else:2147 loopprefix = '_pd_phase_block_id'2148 2149 for phasenam in sorted(self.Phases.keys()):2150 i = self.Phases[phasenam]['pId']2151 datablockidDict[phasenam] = (str(self.CIFdate) + "|" + str(self.CIFname) + "|" +2152 'phase_'+ str(i) + '|' + str(self.shortauthorname))2153 WriteCIFitem(loopprefix,datablockidDict[phasenam])2154 # loop over data blocks2155 if len(self.powderDict) + len(self.xtalDict) > 1:2156 loopprefix = ''2157 WriteCIFitem('loop_ _pd_block_diffractogram_id')2158 else:2159 loopprefix = '_pd_block_diffractogram_id'2160 for i in sorted(self.powderDict.keys()):2161 hist = self.powderDict[i]2162 histblk = self.Histograms[hist]2163 instnam = histblk["Sample Parameters"]['InstrName']2164 instnam = instnam.replace(' ','')2165 i = histblk['hId']2166 datablockidDict[hist] = (str(self.CIFdate) + "|" + str(self.CIFname) + "|" +2167 str(self.shortauthorname) + "|" +2168 instnam + "_hist_"+str(i))2169 WriteCIFitem(loopprefix,datablockidDict[hist])2170 for i in sorted(self.xtalDict.keys()):2171 hist = self.xtalDict[i]2172 histblk = self.Histograms[hist]2173 instnam = histblk["Instrument Parameters"][0]['InstrName']2174 instnam = instnam.replace(' ','')2175 i = histblk['hId']2176 datablockidDict[hist] = (str(self.CIFdate) + "|" + str(self.CIFname) + "|" +2177 str(self.shortauthorname) + "|" +2178 instnam + "_hist_"+str(i))2179 WriteCIFitem(loopprefix,datablockidDict[hist])2180 #============================================================2181 # loop over phases, exporting them2182 phasebyhistDict = {} # create a cross-reference to phases by histogram2183 for j,phasenam in enumerate(sorted(self.Phases.keys())):2184 i = self.Phases[phasenam]['pId']2185 WriteCIFitem('\ndata_'+self.CIFname+"_phase_"+str(i))2186 WriteCIFitem('# Information for phase '+str(i))2187 WriteCIFitem('_pd_block_id',datablockidDict[phasenam])2188 # report the phase2189 WritePhaseTemplate(phasenam)2190 WritePhaseInfo(phasenam)2191 # preferred orientation2192 SH = FormatSH(phasenam)2193 MD = FormatHAPpo(phasenam)2194 if SH and MD:2195 WriteCIFitem('_pd_proc_ls_pref_orient_corr', SH + '\n' + MD)2196 elif SH or MD:2197 WriteCIFitem('_pd_proc_ls_pref_orient_corr', SH + MD)2198 else:2199 WriteCIFitem('_pd_proc_ls_pref_orient_corr', 'none')2200 # report sample profile terms2201 PP = FormatPhaseProfile(phasenam)2202 if PP:2203 WriteCIFitem('_pd_proc_ls_profile_function',PP)2204 2205 #============================================================2206 # loop over histograms, exporting them2207 for i in sorted(self.powderDict.keys()):2208 hist = self.powderDict[i]2209 histblk = self.Histograms[hist]2210 if hist.startswith("PWDR"):2211 WriteCIFitem('\ndata_'+self.CIFname+"_pwd_"+str(i))2212 #instnam = histblk["Sample Parameters"]['InstrName']2213 # report instrumental profile terms2214 WriteCIFitem('_pd_proc_ls_profile_function',2215 FormatInstProfile(histblk["Instrument Parameters"],histblk['hId']))2216 WriteCIFitem('# Information for histogram '+str(i)+': '+hist)2217 WriteCIFitem('_pd_block_id',datablockidDict[hist])2218 WritePowderTemplate(hist)2219 WritePowderData(hist)2220 for i in sorted(self.xtalDict.keys()):2221 hist = self.xtalDict[i]2222 histblk = self.Histograms[hist]2223 if hist.startswith("HKLF"):2224 WriteCIFitem('\ndata_'+self.CIFname+"_sx_"+str(i))2225 #instnam = histblk["Instrument Parameters"][0]['InstrName']2226 WriteCIFitem('# Information for histogram '+str(i)+': '+hist)2227 WriteCIFitem('_pd_block_id',datablockidDict[hist])2228 WriteSnglXtalTemplate(hist)2229 WriteSingleXtalData(hist)2230 2231 WriteCIFitem('#--' + 15*'eof--' + '#')2232 closeCIF()2233 print("...export complete") -
TabularUnified trunk/imports/G2phase_CIF.py ¶
r1069 r1074 17 17 GSASIIpath.SetVersionNumber("$Revision: 810 $") 18 18 import CifFile as cif # PyCifRW from James Hester 19 import urllib20 19 21 20 class CIFPhaseReader(G2IO.ImportPhase): … … 74 73 #### end development code 75 74 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() 75 cf = G2IO.ReadCIF(filename) 81 76 self.DoneBusy() 82 77 #print cf -
TabularUnified trunk/imports/G2pwd_CIF.py ¶
r1069 r1074 14 14 import GSASIIIO as G2IO 15 15 import CifFile as cif # PyCifRW from James Hester 16 import urllib17 16 import GSASIIpath 18 17 GSASIIpath.SetVersionNumber("$Revision: 810 $") … … 100 99 if cf is None: 101 100 self.ShowBusy() # this can take a while 102 ciffile = 'file:'+urllib.pathname2url(filename) 103 #cf = cif.ReadCif(ciffile) 104 fp = open(ciffile,'r') # patch: open file to avoid windows bug 105 cf = cif.ReadCif(fp) 106 fp.close() 101 cf = G2IO.ReadCIF(filename) 107 102 self.DoneBusy() 108 103 except Exception as detail: -
TabularUnified trunk/imports/G2sfact_CIF.py ¶
r1069 r1074 13 13 import os.path 14 14 import GSASIIIO as G2IO 15 import CifFile as cif # PyCifRW from James Hester16 import urllib17 15 import GSASIIpath 18 16 GSASIIpath.SetVersionNumber("$Revision: 810 $") 17 import CifFile as cif # PyCifRW from James Hester 19 18 20 19 class CIFhklReader(G2IO.ImportStructFactor): … … 63 62 if cf is None: 64 63 self.ShowBusy() # this can take a while 65 ciffile = 'file:'+urllib.pathname2url(filename) 66 #cf = cif.ReadCif(ciffile) 67 fp = open(ciffile,'r') # patch: open file to avoid windows bug 68 cf = cif.ReadCif(fp) 69 fp.close() 64 cf = G2IO.ReadCIF(filename) 70 65 self.DoneBusy() 71 66 # scan blocks for reflections
Note: See TracChangeset
for help on using the changeset viewer.